- Published on
No space left on device인데 df는 여유인 이유
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버에서 로그를 쓰거나 패키지를 설치하거나 컨테이너가 파일을 만들다가 갑자기 No space left on device가 터졌는데, 정작 df -h를 보면 디스크 사용률이 넉넉한 상황이 종종 있습니다. 이 메시지는 “디스크 블록이 100% 찼다”만 의미하지 않습니다. 리눅스 파일시스템 관점에서 “더 이상 할당할 수 있는 자원(블록, 아이노드, 메타데이터, 프로젝트 쿼터 등)이 없다”는 뜻이라서, df가 보여주는 수치와 어긋날 수 있습니다.
이 글은 df가 여유로 보이는데도 ENOSPC가 발생하는 대표 원인과, 현장에서 바로 써먹는 진단 명령/해결책을 원인별로 정리한 실전 가이드입니다.
1) 먼저 증상부터 확인: 블록 부족인가, 아이노드 부족인가
가장 먼저 확인할 것은 “용량(블록)”이 아니라 “아이노드(inode)”가 고갈된 케이스입니다. 작은 파일을 엄청 많이 만들면 용량은 남아도 아이노드가 먼저 바닥납니다.
# 블록(용량) 관점
df -h
# 아이노드 관점
df -ih
df -h는 여유인데df -ih에서IUse%가100%면 아이노드 고갈입니다.- 특히
/var/log,/tmp, 빌드 디렉터리, 패키지 캐시, 컨테이너 레이어 저장소에서 자주 발생합니다.
아이노드 고갈 해결
- 작은 파일이 많은 디렉터리 찾기
# 파일 개수 상위 디렉터리 찾기(깊게는 느릴 수 있음)
sudo find /var -xdev -type f | wc -l
# 디렉터리별 파일 개수(간단 버전)
sudo bash -c 'for d in /var/*; do echo -n "$d "; find "$d" -xdev -type f 2>/dev/null | wc -l; done | sort -nr -k2 | head'
- 로그 로테이션/캐시 정리
# systemd-journald 로그 사용량 확인
journalctl --disk-usage
# 1GB만 남기고 정리
sudo journalctl --vacuum-size=1G
- 근본 대책
- 로그 로테이션(
logrotate) 정책 강화 - 애플리케이션이 너무 잘게 파일을 쪼개는 구조(예: 요청당 파일 생성) 개선
- 파일시스템 생성 시 아이노드 수 조정이 필요할 수도 있습니다(특히 ext4를 작은 파일 위주로 쓸 때)
2) ext4 예약 블록(Reserved blocks) 때문에 발생
ext 계열 파일시스템(ext4 등)은 기본적으로 일부 공간을 root 전용으로 예약합니다(보통 5%). 일반 사용자나 데몬이 쓰는 디스크가 꽉 찼을 때 시스템이 완전히 멈추지 않게 하기 위한 장치입니다.
이 경우 df -h에서 여유처럼 보이거나, 혹은 Use%가 100%가 아니어도 특정 사용자/프로세스가 쓰지 못하는 상황이 생길 수 있습니다.
진단
# ext4 예약 블록 비율 확인
sudo tune2fs -l /dev/sda1 | grep -E 'Reserved block count|Block count|Reserved block percentage'
해결
- 예약 비율을 낮춥니다(데이터 파티션이라면 1% 정도로 줄이는 경우가 많음)
# 예약 블록 1%로 변경
sudo tune2fs -m 1 /dev/sda1
주의: 루트(/) 파티션에서 무작정 0%로 만들면 장애 시 복구 여지가 줄어들 수 있습니다.
3) “삭제했는데도 용량이 안 줄어드는” 삭제된 열린 파일 문제
리눅스는 파일을 삭제(rm)해도, 그 파일을 어떤 프로세스가 열고 있는 동안에는 실제 디스크 블록이 해제되지 않습니다. 대표적으로 로그 파일을 지운 뒤에도, 로그를 쓰는 프로세스가 계속 같은 파일 디스크립터에 쓰고 있으면 공간이 그대로 잡혀 있습니다.
이때 du로 보면 별로 없는데 df는 꽉 차 보이거나, 반대로 운영자가 파일을 지웠다고 생각했는데 여전히 ENOSPC가 지속되는 식으로 혼란이 생깁니다.
진단
# (deleted)로 표시된 열린 파일 찾기
sudo lsof +L1
# 특정 마운트에서만 보고 싶다면
sudo lsof +L1 /var
해결
- 해당 프로세스를 재시작(가장 확실)
sudo systemctl restart nginx
- 재시작이 부담되면, 열린 파일 디스크립터를 통해 truncate하는 방식도 있지만 운영 리스크가 있어 권장 순위는 낮습니다.
4) 파일시스템/프로젝트 쿼터(quota)로 막힌 경우
디스크 전체는 남아 있어도 사용자 쿼터, 그룹 쿼터, XFS 프로젝트 쿼터에 걸리면 ENOSPC가 납니다. 특히 멀티테넌트 서버, CI 머신, 또는 컨테이너 런타임이 특정 디렉터리에 프로젝트 쿼터를 걸어둔 환경에서 흔합니다.
진단
- 일반 쿼터
# 사용자 쿼터 확인
quota -u $USER
# 쿼터 활성화 여부(마운트 옵션)
mount | grep quota
- XFS 프로젝트 쿼터
# XFS 쿼터 리포트
sudo xfs_quota -x -c 'report -h' /mount/point
해결
- 쿼터 상향 또는 제한 해제
- 문제를 유발한 디렉터리(예: 빌드 아티팩트, 캐시) 정리
5) 컨테이너/쿠버네티스에서 df는 노드 여유인데 파드는 ENOSPC
컨테이너 환경에서는 “노드 디스크”와 “파드가 쓰는 볼륨/레이어”가 다를 수 있습니다.
대표 케이스:
- 파드의
emptyDir가sizeLimit에 걸림 - PVC 용량이 작아 꽉 찼는데, 노드
df는 여유 - 오버레이 스토리지(
/var/lib/docker또는 containerd 경로)가 별도 파티션인데 그쪽만 가득 참
진단
# 파드 내부에서 실제 마운트 확인
kubectl exec -it pod-name -- sh -c 'df -h; df -ih; mount'
# 노드에서 컨테이너 런타임 저장소 확인(예: docker)
sudo du -hs /var/lib/docker
sudo df -h /var/lib/docker
컨테이너 이미지/레이어 저장소가 병목인 경우, 빌드 캐시가 쌓여 폭발하는 패턴이 많습니다. 이 주제는 Docker BuildKit 캐시 안먹힘 원인·해결 7가지에서도 함께 참고하면 원인 분리(캐시 누적 vs 캐시 미적용)를 빠르게 할 수 있습니다.
해결
emptyDir또는 PVC 용량 확장- 불필요한 이미지/레이어/캐시 정리
# Docker 예시: 사용하지 않는 리소스 정리
docker system prune -af
# BuildKit 캐시까지 정리(상황에 따라)
docker builder prune -af
주의: 운영 환경에서 prune는 영향 범위가 크므로, 먼저 docker system df로 무엇이 큰지 확인한 뒤 진행하세요.
6) 디스크는 남았는데 “디렉터리 엔트리/메타데이터”가 병목인 경우
드물지만 다음과 같은 상황에서도 ENOSPC가 날 수 있습니다.
- 특정 디렉터리에 파일이 과도하게 많아 메타데이터 작업이 실패하거나 극단적으로 느려짐
- 파일시스템 손상 또는 저널 이슈로 인해 쓰기 실패
- btrfs에서 메타데이터 chunk 부족
공통 진단
# 커널 로그에서 파일시스템 관련 에러 확인
dmesg -T | tail -n 200
# ext4 파일시스템 점검(언마운트 필요할 수 있음)
sudo fsck -f /dev/sda1
btrfs 메타데이터 이슈는 별도 절차가 필요하므로, 운영 환경이라면 먼저 스냅샷/백업과 장애 허용 시간을 확보한 뒤 접근하는 것을 권장합니다.
7) 빠른 트러블슈팅 체크리스트(현장용)
아래 순서대로 보면 대부분의 케이스를 짧은 시간 안에 좁힐 수 있습니다.
- 아이노드 확인
df -ih
- 문제가 난 경로가 어느 마운트인지 확인
df -h /문제/경로
du로 큰 디렉터리 찾기(동일 파일시스템 한정)
sudo du -xhd1 /문제/마운트 | sort -h | tail -n 20
- 삭제된 열린 파일 확인
sudo lsof +L1 | head
- ext4 예약 블록 확인(해당 시)
sudo tune2fs -l /dev/sda1 | grep -i reserved
- 쿼터 확인
quota -u $USER
- 컨테이너라면 파드 내부
df도 확인
kubectl exec -it pod-name -- sh -c 'df -h; df -ih'
쿠버네티스에서 스토리지(PVC) 문제로 파드가 비정상 상태에 빠지는 경우도 많습니다. 디스크/볼륨 관점에서 원인 분리할 때는 K8s Pod Pending? PVC 바인딩 실패 7가지도 함께 보면 “노드 디스크 여유 vs PVC 제약”을 더 빨리 구분할 수 있습니다.
8) 예방: ENOSPC를 장애로 키우지 않는 운영 팁
node_exporter또는cadvisor로 블록 사용률뿐 아니라 아이노드 사용률도 알람에 포함/var/log,/tmp, 컨테이너 저장소 경로를 별도 파티션으로 분리(장애 격리)- 로그는 무조건 로테이션 + 압축 + 보관기간 제한
- CI/빌드 머신은 캐시/아티팩트 정리 잡을 주기적으로 실행
- ext4 데이터 파티션은 예약 블록 비율을 환경에 맞게 조정
마무리
No space left on device는 “디스크 용량이 부족하다”보다 훨씬 넓은 의미입니다. df -h가 여유로 보여도, 아이노드 고갈, ext4 예약 블록, 삭제된 열린 파일, 쿼터, 컨테이너 볼륨 제약 같은 이유로 동일한 에러가 발생할 수 있습니다.
가장 효율적인 접근은 df -ih로 아이노드를 먼저 배제하고, lsof +L1로 삭제된 열린 파일을 확인한 다음, 파일시스템 특성(ext4 예약, XFS 쿼터, 컨테이너 볼륨)을 순서대로 좁혀가는 것입니다. 이 루틴만 정착해도 “df는 여유인데 왜 안 돼?” 같은 상황에서 복구 시간이 크게 줄어듭니다.