- Published on
리눅스 디스크 100%? lsof로 삭제파일 점유 해결
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버에서 갑자기 디스크가 100%가 되면 보통 du로 큰 디렉터리를 찾아 지우는 방식으로 접근합니다. 그런데 df는 꽉 찼다고 하는데 du로는 큰 파일이 보이지 않거나, 지웠다고 생각했는데도 용량이 줄지 않는 경우가 있습니다. 이때 가장 흔한 원인 중 하나가 삭제된 파일을 어떤 프로세스가 계속 열고 있는 상태입니다.
리눅스에서는 파일을 삭제(rm)해도, 그 파일을 열고 있는 파일 디스크립터가 남아 있으면 실제 데이터 블록은 즉시 회수되지 않습니다. 즉, 파일은 디렉터리 엔트리에서는 사라졌지만(그래서 du에 안 잡힘), 커널은 프로세스가 닫을 때까지 데이터를 유지합니다. 이 글에서는 lsof로 그 상황을 진단하고, 안전하게 공간을 회수하는 방법을 단계별로 정리합니다.
운영 환경에서 디스크 100%는 장애로 직결됩니다. 특히 DB, 로그, 컨테이너 런타임, 에이전트(모니터링/보안)가 원인이 되는 경우가 많습니다. 쿠버네티스/EKS 환경이라면 노드 디스크 압박이
Pod Pending으로 이어질 수 있으니, 연관 이슈는 K8s Pod가 Pending? 스케줄링 실패 12가지도 함께 참고하면 좋습니다.
1) 증상 패턴: df는 100%인데 du로는 안 보인다
대표적인 증상은 다음과 같습니다.
df -h에서 특정 마운트(/,/var,/data등)가 100%du -sh /var/*같은 탐색으로는 큰 파일이 안 보이거나, 지운 후에도df가 줄지 않음- 서비스 재시작/로그 로테이션 이후에도 회복이 안 됨
먼저 기본 확인부터 합니다.
# 파일시스템 사용량(커널 관점)
df -h
# inode 고갈인지도 같이 확인 (inode 100%면 파일 생성 자체가 막힙니다)
df -ih
# 디렉터리 기준 사용량(디렉터리 엔트리 기반)
du -xh /var | sort -h | tail -n 20
df와 du가 크게 어긋난다면, 삭제된 파일 점유(혹은 마운트/바인드, 스냅샷, overlay 계층 등)를 의심할 타이밍입니다.
2) 원리: 삭제했는데 왜 용량이 안 돌아오나
유닉스 계열 파일시스템에서 파일은 크게 두 요소로 관리됩니다.
- 디렉터리 엔트리(파일명과 inode를 연결)
- inode와 데이터 블록(실제 내용)
rm은 디렉터리 엔트리 링크를 제거합니다. 하지만 어떤 프로세스가 이미 그 파일을 열어서 파일 디스크립터를 가지고 있다면, 커널은 참조 카운트가 0이 될 때까지(모든 FD가 닫힐 때까지) 데이터 블록을 유지합니다.
그래서
du는 디렉터리 트리를 따라가며 계산하므로 삭제된 파일은 잡히지 않고df는 파일시스템의 실제 블록 사용량을 보여주므로 여전히 꽉 찬 것으로 보입니다.
이 간극을 메우는 도구가 lsof입니다.
3) lsof로 삭제된 파일을 잡아내기
3-1) 가장 많이 쓰는 한 줄
# 삭제(deleted)된 파일을 열고 있는 프로세스 찾기
sudo lsof +L1
+L1은 링크 수가 1보다 작은(즉, 디렉터리 엔트리가 없는) 열린 파일을 의미합니다.- 출력에
(deleted)가 붙는 항목이 핵심입니다.
3-2) 특정 마운트/경로에서만 찾기
디스크가 꽉 찬 마운트가 /var라면 범위를 좁히는 게 좋습니다.
sudo lsof +L1 /var
또는 파일시스템 단위로 잡고 싶다면 df에서 문제 파티션의 마운트 포인트를 확인한 뒤 그 경로를 넣습니다.
3-3) 출력에서 봐야 할 컬럼
lsof 출력에서 주로 확인하는 값은 다음입니다.
COMMAND: 어떤 프로세스인지PID: 프로세스 IDUSER: 실행 사용자FD: 파일 디스크립터 번호 (예:1w,2w,3u)TYPE:REG(일반 파일) 등SIZE/OFF: 파일 크기NAME: 경로 및(deleted)표시
예시 상황(개념 예시):
java프로세스가/var/log/app.log (deleted)를 수십 GB로 잡고 있음nginx가 오래된 access log를 계속 쓰고 있음dockerd또는containerd가 컨테이너 로그를 잡고 있음
4) 해결 전략: “프로세스가 잡고 있는 FD”를 안전하게 놓게 하기
삭제된 파일 점유를 해제하는 방법은 크게 3가지입니다.
- 프로세스를 재시작해서 FD를 닫게 한다 (가장 흔하고 안전)
- 해당 FD를 직접 truncate해서 공간만 회수한다 (응급 처치)
- 로그 로테이션/설정을 수정해 재발을 막는다 (근본 해결)
4-1) 가장 권장: 서비스 재시작
점유 주체가 명확하고 재시작이 가능한 서비스라면 재시작이 가장 깔끔합니다.
# systemd 서비스 예시
sudo systemctl restart nginx
sudo systemctl restart myapp
# 프로세스 직접 종료(권장도는 낮음)
sudo kill -TERM 12345
재시작 후 다시 확인합니다.
sudo lsof +L1
df -h
디스크가 즉시 회수되는 것이 정상입니다.
4-2) 재시작이 어렵다면: FD에 대해 truncate(공간만 회수)
장애 상황에서 “지금 당장 공간만 확보”해야 하는 경우가 있습니다. 이때 프로세스를 죽이지 않고도 열린 FD가 가리키는 파일 내용을 0바이트로 줄여 공간을 회수할 수 있습니다.
핵심은 /proc/[pid]/fd/[fd]를 이용하는 것입니다.
lsof에서 PID와 FD를 확인합니다. 예를 들어 PID가12345, FD가4w라면 숫자4가 FD 번호입니다.- 아래 중 하나를 실행합니다.
# 방법 A: shell 리다이렉션으로 0바이트로 만들기
sudo sh -c 'true > /proc/12345/fd/4'
# 방법 B: truncate 사용
sudo truncate -s 0 /proc/12345/fd/4
주의점:
- 이 방식은 파일 내용을 날리는 것이므로, 로그 파일이라면 괜찮지만 데이터 파일(DB 파일 등)에 하면 치명적일 수 있습니다.
- 반드시
lsof에서NAME이 로그/캐시/임시 파일인지 확인하고 진행하세요.
4-3) 로그 로테이션 문제라면: 설정 점검
삭제된 로그를 계속 점유하는 케이스는 보통 로테이션 정책과 프로세스의 로그 reopen 동작이 어긋날 때 발생합니다.
logrotate를 쓰는 경우,copytruncate를 쓸지postrotate에서 서비스에 reopen 신호를 보낼지 선택이 필요합니다.- nginx는 보통
USR1신호로 로그 파일을 다시 엽니다.
예시(nginx):
# nginx가 로그를 다시 열도록 유도
sudo kill -USR1 $(cat /run/nginx.pid)
앱이 자체적으로 로그 파일을 열어두는 방식이라면, 로거 설정(예: logback, log4j2)에서 rolling 정책을 점검해야 합니다.
5) 실전 점검 플로우(복붙용)
장애 대응 시 순서대로 실행하기 좋은 플로우입니다.
# 1) 어디가 찼는지 확인
df -h
# 2) inode 문제인지 확인
df -ih
# 3) du로 큰 디렉터리 확인(일반적인 대용량 원인)
du -xh /var | sort -h | tail -n 30
# 4) df는 큰데 du가 애매하면, 삭제 파일 점유 확인
sudo lsof +L1 | sort -k7 -h | tail -n 30
# 5) 특정 마운트만 보고 싶으면 경로 제한
sudo lsof +L1 /var | sort -k7 -h | tail -n 30
sort -k7 -h는 환경에 따라 컬럼 위치가 달라질 수 있습니다. 정렬이 기대대로 안 되면 정렬은 빼고 SIZE/OFF 큰 항목을 눈으로 확인하는 게 더 안전합니다.
6) 컨테이너/쿠버네티스 환경에서의 추가 포인트
쿠버네티스 노드에서 디스크가 100%가 되는 흔한 원인 중 하나는 컨테이너 로그/이미지/레이어입니다. 다만 이 글의 주제처럼 “삭제된 파일 점유”도 컨테이너 런타임이나 로깅 에이전트가 관련될 수 있습니다.
- 노드에서
lsof +L1결과에containerd,dockerd,fluent-bit,filebeat등이 보이면 로그 파이프라인을 의심합니다. - 노드 디스크 압박은 스케줄링 실패로 이어질 수 있으니, 장애가
Pending으로 확산되는 상황이라면 K8s Pod가 Pending? 스케줄링 실패 12가지에서DiskPressure관련 항목도 같이 확인하세요.
7) 자주 하는 실수와 안전 가이드
7-1) “파일을 지웠는데 왜 안 줄지?”만 반복
rm은 디렉터리 엔트리만 제거합니다. 열린 FD가 남아 있으면 공간은 그대로입니다. 이때 du만 계속 보는 건 시간 낭비가 되기 쉽습니다.
7-2) 무작정 kill -9
SIGKILL은 즉시 종료라서 FD는 닫히며 공간은 회수되겠지만, 데이터 정합성/정리 작업을 건너뛸 수 있습니다. 가능한 systemctl restart 또는 kill -TERM 같은 정상 종료 경로를 우선하세요.
7-3) /proc/[pid]/fd/[fd] truncate를 아무 파일에나 적용
로그 파일이면 대체로 안전하지만, DB나 큐, 스토리지 파일에 적용하면 장애가 더 커질 수 있습니다. lsof 출력의 NAME과 프로세스 역할을 확인하고, 확신이 없으면 재시작/롤백 가능한 방향을 선택하세요.
8) 마무리: df와 du가 다르면 lsof +L1부터
정리하면,
df는 파일시스템 실제 사용량du는 디렉터리 트리 기준 사용량- 둘이 어긋나고 삭제했는데도 용량이 안 줄면, 프로세스가 삭제 파일을 점유 중일 가능성이 큼
가장 빠른 진단은 sudo lsof +L1이고, 해결은 보통 “해당 프로세스 재시작”입니다. 재시작이 어려운 상황에서는 /proc 경로의 FD를 truncate하는 응급 처치가 가능하지만, 적용 대상이 로그/임시 파일인지 반드시 확인한 뒤 진행하세요.