Published on

리눅스 디스크 100%인데 삭제해도 용량이 안 늘 때

Authors

운영 중인 리눅스 서버에서 디스크가 100%에 가까워져 로그나 임시 파일을 삭제했는데도 df 상의 사용량이 그대로라면, 단순히 “삭제가 안 됐다”라기보다 파일시스템/프로세스 관점에서 공간이 아직 반환되지 않은 상태일 가능성이 큽니다. 이 글에서는 실무에서 가장 자주 만나는 케이스를 우선순위대로 진단하고, 서비스 영향도를 최소화하면서 공간을 회수하는 방법을 단계별로 정리합니다.

문제 패턴은 보통 다음 중 하나로 귀결됩니다.

  • 프로세스가 삭제된 파일을 계속 열고 있음(가장 흔함)
  • 공간이 아니라 inode가 고갈
  • ext 계열의 예약 블록(reserved blocks) 때문에 100%처럼 보임
  • 컨테이너/오버레이 파일시스템 특성으로 호스트와 컨테이너의 관측이 다름
  • 로그/저널/스냅샷/LVM, 또는 애플리케이션의 쓰기 패턴 때문에 회수가 지연됨

아래 절차대로 보면 대부분 10~20분 내에 원인을 좁힐 수 있습니다.

1) 먼저 dfdu 불일치부터 확인

파일을 지웠는데 df -h는 그대로인데 du로 보면 줄어든 것처럼 보이는 상황이 자주 발생합니다.

# 파일시스템 관점(블록 사용량)
df -hT

# 디렉터리 합계 관점(현재 경로에서 보이는 파일들의 합)
du -xh --max-depth=1 / | sort -h
  • df는 “파일시스템이 실제로 점유/예약한 블록”을 봅니다.
  • du는 “현재 디렉터리 트리에서 보이는 파일”만 셉니다.

즉, 삭제되어 디렉터리에서는 안 보이지만 프로세스가 열고 있는 파일du에 잡히지 않고 df에만 남습니다.

이 불일치가 보이면 다음 단계(삭제된 열린 파일)로 바로 가는 게 정석입니다.

2) 삭제했는데 용량이 안 느는 1순위: 삭제된 열린 파일((deleted))

리눅스에서는 파일을 rm로 삭제해도, 어떤 프로세스가 해당 파일 디스크립터를 잡고 있으면 inode가 참조되는 동안 데이터 블록이 해제되지 않습니다. 이때 디스크 공간은 계속 점유되며, lsof에서 (deleted)로 보입니다.

2-1) lsof로 원인 프로세스 찾기

# 삭제된 파일을 열고 있는 프로세스 목록
sudo lsof +L1

# 특정 마운트(예: /var)에서만 보고 싶을 때
sudo lsof +L1 /var

출력에서 다음을 확인합니다.

  • COMMAND / PID: 어떤 프로세스가 잡고 있는지
  • SIZE/OFF: 얼마나 큰 파일인지
  • NAME: (deleted) 여부

대용량 로그 파일을 rm 했는데도 공간이 안 느는 경우, 대개 java, node, python, nginx, rsyslogd, dockerd 같은 프로세스가 파일을 계속 쓰고 있습니다.

2-2) 안전한 회수 방법: 프로세스 재시작 또는 로그 로테이션

가장 확실한 방법은 해당 프로세스를 재시작해서 파일 디스크립터를 닫게 하는 것입니다.

# systemd 서비스라면
sudo systemctl restart nginx

# PID를 직접 종료해야 한다면(주의)
sudo kill -TERM 12345

로그 파일이 원인이라면, logrotate를 “삭제(truncate)” 방식으로 구성하는 것도 방법입니다. 다만 애플리케이션과 로그 수집 방식에 따라 권장 설정이 다릅니다.

예시: copytruncate는 재시작 없이도 공간을 회수할 수 있지만, 회전 순간 일부 로그 유실 가능성이 있습니다.

# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
  daily
  rotate 7
  compress
  missingok
  notifempty
  copytruncate
}

운영에서 파일 디스크립터/열린 파일 이슈는 디스크 문제뿐 아니라 다양한 장애의 출발점이 됩니다. 관련해서는 Linux EMFILE(Too many open files) 원인과 해결도 함께 참고하면, “열린 파일”을 시스템적으로 관리하는 감이 잡힙니다.

3) 디스크가 아니라 inode가 100%일 수도 있음

파일이 아주 많아지면(작은 파일 수백만 개) 블록 공간은 남아도 inode가 먼저 바닥납니다. 이 경우 “삭제했는데도 여전히 꽉 참”처럼 보이기도 합니다.

df -ih
  • IUse%가 100%면 inode 고갈입니다.

3-1) inode를 많이 먹는 디렉터리 찾기

# 디렉터리별 파일 개수(대략적인 탐색)
sudo find /var -xdev -type f | wc -l

# 상위 디렉터리별로 더 빠르게 보고 싶으면
sudo find /var -xdev -type d -maxdepth 2 -print0 | \
  xargs -0 -I{} sh -c 'echo -n "{} "; find "{}" -xdev -type f | wc -l' | \
  sort -k2 -n

캐시 디렉터리(예: /var/cache, /tmp, 패키지 캐시, 애플리케이션 세션/스풀)가 범인인 경우가 많습니다. 해결은 “큰 파일 삭제”가 아니라 파일 개수 자체를 줄이는 방향(TTL, 주기적 정리, 캐시 정책 변경)으로 가야 합니다.

4) ext4 예약 블록 때문에 100%처럼 보이는 경우

ext 계열 파일시스템은 기본적으로 일부 블록을 root 전용으로 예약합니다(보통 5%). 그래서 일반 사용자/일반 프로세스 기준으로는 “꽉 찼다”처럼 보일 수 있습니다.

4-1) 예약 블록 확인

sudo tune2fs -l /dev/sda1 | grep -E "Reserved block count|Block count|Reserved block percentage"

4-2) (필요 시) 예약 비율 조정

데이터 파티션(예: 대용량 로그 볼륨)에서는 예약 비율을 1% 정도로 낮추는 선택을 하기도 합니다. 단, 루트 파티션(/)에서 무작정 줄이면 장애 시 복구 여지가 줄어듭니다.

# 예: 예약 블록 비율을 1%로
sudo tune2fs -m 1 /dev/sda1

5) 컨테이너 환경: 오버레이(overlay2) 때문에 관측이 엇갈림

Docker/컨테이너를 쓰면 다음 혼동이 흔합니다.

  • 컨테이너 안에서 df를 보면 남아 보이는데 호스트는 꽉 참
  • 컨테이너에서 파일을 지웠는데 호스트의 df가 줄지 않음

이는 보통 overlay 레이어, 로그 드라이버, 이미지/빌드 캐시, 또는 컨테이너가 만든 파일이 호스트 특정 경로(예: /var/lib/docker)를 잠식해서 생깁니다.

5-1) Docker 디스크 사용량 점검

docker system df
sudo du -xh --max-depth=1 /var/lib/docker | sort -h

5-2) 안전한 정리 순서

# 1) 사용하지 않는 컨테이너/이미지/네트워크 정리(주의: 사용 중인 리소스 확인)
docker system prune

# 2) 빌드 캐시가 크면
docker builder prune

빌드 캐시가 예상보다 빨리 커지거나 무효화되어 디스크를 잡아먹는 문제는 Docker BuildKit 캐시 무효화 원인·해결 8가지에서 원인별로 더 깊게 다룹니다.

6) 로그가 원인일 때: “지우기”보다 “쓰는 주체”를 멈춰야 한다

디스크 100% 사건의 절반 이상은 로그입니다. 여기서 중요한 포인트는 “로그 파일 삭제” 자체가 아니라,

  • 누가(어떤 프로세스가) 계속 쓰고 있는지
  • 로그 로테이션 정책이 맞는지
  • stdout/stderr가 어디로 쌓이는지

를 확인하는 것입니다.

6-1) 큰 파일 상위 랭킹

# 루트부터 큰 파일 20개(권한 필요)
sudo find / -xdev -type f -size +100M -printf '%s %p\n' 2>/dev/null | \
  sort -nr | head -n 20

6-2) systemd journal이 커졌다면

# 현재 journal 디스크 사용량
journalctl --disk-usage

# 7일치만 유지
sudo journalctl --vacuum-time=7d

# 1GB만 유지
sudo journalctl --vacuum-size=1G

7) 파일시스템/스토리지 레이어 이슈: 스냅샷, LVM, 삭제 지연

클라우드/가상화 환경에서는 “삭제했는데도 안 줄어듦”이 파일시스템 밖에서 발생하기도 합니다.

  • LVM 스냅샷이 존재하면 CoW로 인해 공간이 빨리 증가
  • 스토리지 스냅샷 정책 때문에 실제 물리 공간 회수가 지연
  • thin provisioning에서 논리/물리 사용량 관측이 다름

이 경우 OS 레벨 df는 줄었는데도 스토리지 콘솔에서 안 줄거나, 반대로 OS에서 안 줄어 보이는 등 다양한 변형이 있습니다.

LVM을 쓴다면 아래를 확인합니다.

sudo lvs
sudo vgs
sudo pvs

스냅샷이 크면 삭제/병합 정책을 점검해야 합니다.

8) 즉시 대응 체크리스트(운영용)

디스크 100%는 서비스 장애로 곧장 이어질 수 있으니, 아래 순서로 “가장 효과 큰 조치”부터 합니다.

  1. df -hT로 꽉 찬 마운트 지점 확인
  2. du -xh --max-depth=1로 큰 디렉터리 대략 파악
  3. dfdu 불일치면 sudo lsof +L1(deleted) 열린 파일 확인
  4. 원인 프로세스 재시작(또는 로그 로테이션)으로 공간 회수
  5. df -ih로 inode 고갈 여부 확인
  6. Docker 사용 시 docker system df/var/lib/docker 점검
  7. journal/logrotate 정책 정비

9) 재발 방지: “용량 확보”가 아니라 “성장률 관리”

일회성으로 파일을 지워서 급한 불을 끄면, 대부분 같은 문제가 다시 옵니다. 재발 방지는 결국 “디스크 성장률을 예측 가능하게” 만드는 작업입니다.

  • 로그: 로테이션/보관기간/압축 정책 수립, stdout 로그 수집 경로 통일
  • 캐시: TTL, 최대 크기 제한, 주기적 정리 크론
  • 컨테이너: 이미지 태깅/정리 규칙, BuildKit 캐시 정책
  • 모니터링: 디스크 사용률뿐 아니라 “일별 증가량” 알람(예: 24시간 증가량)

운영 자동화 관점에서 “적용했는데 바뀌지 않는 것처럼 보이는” 문제는 디스크에서도 자주 발생합니다(실제 삭제는 됐는데 핸들이 남아 있거나, 관측 지표가 다른 레이어를 보고 있거나). 이런 류의 ‘관측과 실제의 불일치’를 다루는 사고방식은 Terraform apply 후 Azure NSG 규칙이 안 바뀌는 이유 같은 글에서도 도움이 됩니다.

마무리

리눅스에서 “삭제했는데도 용량이 안 늘어나는” 현상은 대부분 정상 동작의 결과입니다. 핵심은 dfdu의 관점 차이를 이해하고, (deleted) 열린 파일을 빠르게 찾아 파일을 지우는 행위가 아니라 파일을 쥔 프로세스를 닫게 만드는 것입니다.

위 절차대로 확인해도 원인이 애매하다면, 다음 정보를 모아두면 원인 규명이 훨씬 빨라집니다.

  • df -hT, df -ih 결과
  • sudo lsof +L1 결과(상위 몇 줄)
  • 가장 큰 디렉터리 du 결과
  • Docker 사용 여부와 docker system df 결과

이 정도면 “왜 안 줄지”가 아니라 “어디에서 누가 잡고 있는지”까지 대부분 특정할 수 있습니다.