lsof 명령어로 어떤 프로세스가 파일을 점유 중인지 확인하는 법

Views: 0

lsof의 핵심 개념

lsof(list open files)는 시스템에서 현재 열려 있는 모든 파일과 이를 연 프로세스를 나열한다. 유닉스 계열에서 “파일”은 일반 파일뿐 아니라 디렉터리, 소켓, 파이프, 장치 파일까지 포괄한다. 따라서 파일 점유 문제, 포트 충돌, 언마운트 실패, 삭제된 파일로 인한 디스크 공간 회수 실패까지 한 도구로 진단할 수 있다.

설치와 기본 사용

대부분 배포판에 기본 포함되어 있지만 없으면 패키지로 설치한다.

# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y lsof

# RHEL/CentOS/AlmaLinux/Rocky
sudo yum install -y lsof

# macOS(Homebrew)
brew install lsof

기본 실행은 다음과 같다.

lsof        # 열린 모든 파일을 나열(출력 많음)
sudo lsof   # 권한 필요한 항목까지 포함해 더 완전한 결과

출력의 주요 열은 COMMAND(프로세스명), PID, USER, FD(파일디스크립터), TYPE, SIZE/OFF, NODE, NAME다. FD 열에서 cwd(현재 작업 디렉터리), txt(실행 파일/라이브러리), mem(매핑), n(네트워크) 등 역할을 구분해 볼 수 있다.

특정 파일을 누가 점유 중인지 즉시 확인

가장 흔한 요구는 “이 경로를 누가 열고 있나?”다.

lsof /path/to/file.log

여러 프로세스가 열었을 수 있고, 쓰기 핸들이 궁금하다면 FD 열에 w가 붙은 항목을 우선 확인하면 된다.

디렉터리 전체를 훑어야 하면 재귀 옵션을 쓴다.

# 디렉터리 아래를 재귀적으로 검색(심볼릭 링크 따라가지 않음)
lsof +D /var/www

대규모 트리에서는 시간이 걸릴 수 있어 상위 수준에서 필터를 결합하는 것이 좋다(아래 ‘성능 팁’ 참고).

포트 충돌 원인 찾기

웹 서버나 애플리케이션이 “Address already in use”로 뜰 때 가장 빠른 확인법은 다음과 같다.

# 80/TCP를 점유한 프로세스
sudo lsof -i :80

# 특정 프로토콜/상태까지 좁히기
sudo lsof -iTCP:5432 -sTCP:LISTEN

PID만 깔끔히 얻어서 자동화에 쓰려면 -t를 결합한다.

PID=$(sudo lsof -t -iTCP:5432 -sTCP:LISTEN)

삭제된 파일이 디스크를 잡아먹을 때

로그 로테이션 후에도 디스크가 비지 않는 경우, 삭제된 파일을 여전히 프로세스가 붙잡고 있을 가능성이 크다.

sudo lsof | grep '(deleted)'
# 또는 특정 파일시스템에서만
sudo lsof +L1

+L1은 하드링크 수가 1 미만(삭제됨)인 열린 파일을 찾는다. 해당 PID의 서비스를 재시작하거나, 가능하면 truncate -s 0 /proc/<PID>/fd/<FD>로 공간만 비울 수 있다(중요한 프로세스에선 신중히 진행).

언마운트 실패 해결

“target is busy”로 언마운트가 실패하면 어느 프로세스가 파일시스템을 붙잡고 있는지 확인한다.

sudo lsof +f -- /mnt/data

마운트 지점을 인자로 주면 하위 경로의 열린 파일을 모두 찾아준다. 셸이 그 디렉터리를 cwd로 잡고 있을 수도 있으니 현재 경로도 점검한다.

사용자·프로세스·명령어 기준 필터링

문제의 소유자나 서비스 단위로 좁히면 탐색 속도가 빨라진다.

# 특정 사용자
lsof -u www-data

# 특정 PID
lsof -p 12345

# 프로세스명 접두어(대문자/소문자 구분 없음, 최대 9글자)
lsof -c nginx
lsof -c java

여러 조건을 조합할 수 있다.

# nginx가 연 포트 리스닝 소켓
sudo lsof -a -c nginx -iTCP -sTCP:LISTEN

-a는 AND 조건으로 결합한다(기본은 OR 결합).

디바이스/특정 파일타입 점검

디스크 장치, 파이프, 소켓 등 특정 타입만 보고 싶다면 -d 또는 -a와 함께 사용한다.

# 파일디스크립터 번호 1(표준출력)만
lsof -d 1 -p 12345

# 블록 디바이스 파일을 여는 프로세스
sudo lsof /dev/sdb

성능과 정확도를 높이는 습관

대규모 서버에서 전체 스캔은 비용이 크다. 다음 옵션으로 I/O와 시간을 줄인다.

# DNS 역조회 생략(빨라짐)
sudo lsof -nP

# 관심 경로만 재귀 검색
sudo lsof -nP +D /var/log/myapp

# 다중 조건 AND 결합으로 결과 축소
sudo lsof -nP -a -u myuser +D /srv/app

-n은 호스트명을, -P는 포트명을 수치로 출력해 불필요한 네트워크/DNS 지연을 제거한다.

네트워크 진단: lsof vs ss/netstat

네트워크 포트 자체의 목록만 빠르게 보려면 ss(또는 구형 netstat)가 더 가볍다. 반대로 “그 포트를 연 프로세스의 실행파일·현재 작업 디렉터리·열린 다른 파일까지” 엮어서 보고 싶다면 lsof가 더 풍부한 문맥을 제공한다. 실무에서는 ss -ltnp로 빠르게 범위를 좁힌 뒤, 해당 PID를 lsof로 깊이 들여다보는 흐름이 효율적이다.

로그 로테이션 실전 절차

  1. 디스크 사용량 급증 확인 후 삭제했는데 공간이 안 비면 삭제된 열린 파일 여부를 본다.
sudo lsof +L1 | sort -k7 -h
  1. 문제 PID를 파악하고 서비스 영향도를 검토한다.
  2. 재시작이 가능하면 안전 시간대에 재시작한다.
  3. 불가피할 경우 파일디스크립터를 비워 공간을 확보한다.
# 예: FD 번호가 4라면
sudo truncate -s 0 /proc/<PID>/fd/4

포트 충돌 실전 절차

  1. 포트 리스너 PID를 얻는다.
sudo lsof -t -iTCP:8080 -sTCP:LISTEN
  1. 시스템 서비스 매핑을 확인한다(systemd 사용 시).
systemctl status <service>
  1. 의도치 않은 잔존 프로세스라면 종료하거나 포트를 변경하고 재기동한다.

컨테이너/네임스페이스 환경

컨테이너 내부의 열린 파일은 컨테이너 네임스페이스에서 확인한다.

# docker exec로 컨테이너 안에서
docker exec -it <container> lsof -nP

호스트에서 특정 PID의 네임스페이스로 들어가려면 nsenter를 사용할 수 있다. 컨테이너 기반 배포에선 이미지 빌드 시 디버그 도구로 lsof를 포함할지 정책적으로 결정해 두면 장애 대응 속도가 달라진다.

보안·권한 고려사항

일부 항목은 루트 권한이 없으면 보이지 않는다. 운영 서버에서는 최소 권한 원칙을 지키되, 진단 시에는 감사 로깅을 활성화하고 필요 구간에서만 sudo를 사용한다. 또한 프로덕션에서 FD 조작은 서비스 영향 범위를 숙지한 담당자가 절차에 따라 실행하는 것이 안전하다.

자주 쓰는 옵션 요약

-nP                 # 이름 해석 비활성화로 속도 향상
-t                  # PID만 출력(스크립트에 유용)
-u <user>           # 사용자 기준 필터
-p <pid>            # PID 기준 필터
-c <cmd>            # 프로세스명 접두어 필터
-i[46][proto][:p]   # 네트워크 소켓 필터(예: -iTCP:443)
-sTCP:LISTEN        # 소켓 상태 필터
+D <dir>            # 디렉터리 재귀 검색
+d <dir>            # 디렉터리 한 단계만
+L1                 # 삭제된 파일(링크 수 < 1)

자동화 스니펫 예시

포트 사용 프로세스를 종료하기 전에 안전하게 알림을 보내는 간단한 스크립트 예시다.

#!/usr/bin/env bash
set -euo pipefail

PORT="${1:-8080}"
PID="$(sudo lsof -t -iTCP:${PORT} -sTCP:LISTEN || true)"
if [[ -z "${PID}" ]]; then
  echo "포트 ${PORT}를 점유한 프로세스가 없습니다."
  exit 0
fi

echo "포트 ${PORT} 점유 PID: ${PID}"
ps -o pid,ppid,cmd -p "${PID}"

# 필요한 경우 여기서 graceful 종료 로직 추가
# kill -TERM "${PID}"

FAQ

Q. 특정 파일을 쓰기 모드로 여는 프로세스만 보고 싶다
A. FD에 w가 붙은 항목을 grep으로 걸러낸다.

lsof /var/log/app.log | awk '$4 ~ /w/'

Q. 심볼릭 링크 대상까지 추적 가능한가
A. 경로를 해석한 뒤 대상 파일을 인자로 주면 된다. 다만 애플리케이션이 실제 열어둔 경로 기준으로 일치하도록 확인한다.
Q. 결과가 비어 있는데 확실히 점유 중처럼 보인다
A. 권한 부족, 네임스페이스 차이, 이미 FD가 닫혔을 가능성을 점검한다. sudo lsof -nP와 컨테이너 내부 실행을 시도한다.

마무리 체크리스트

  1. 경로·포트·사용자·PID 중 가장 좁은 기준으로 시작한다
  2. -nP로 이름 해석을 끄고 속도를 확보한다
  3. 삭제된 파일·언마운트 문제는 +L1, +f -- <mount>로 접근한다
  4. 자동화가 필요하면 -t로 PID만 추출해 스크립트화한다
  5. 컨테이너/권한/네임스페이스 경계를 항상 의식한다

이 글의 흐름대로 점검하면, “누가 이 파일 또는 포트를 점유했는가”라는 질문에 단 몇 줄의 lsof 명령으로 일관된 답을 얻을 수 있다.