"No space left on device" 디스크 풀 에러 5분 만에 진단·해결하기
새벽에 알림이 울립니다. DB가 멈췄고, 애플리케이션 로그엔 익숙한 그 문장이 떠 있습니다.
write error: No space left on device급한 마음에 df -h를 쳤더니 루트 파티션은 고작 50%. "디스크 여유 있는데 왜 쓰기가 안 되지?" — 운영 중 가장 당황스러운 순간입니다. 결론부터 말하면, 디스크 풀 에러는 용량(블록) 문제일 수도 있고 inode 고갈 문제일 수도 있습니다. 둘은 처방이 완전히 다릅니다. 이 글은 패닉 상황에서 진단 → 처방 → 재발 방지를 명령어 우선으로 따라갈 수 있도록 구성했습니다.
5분 진단 플로우 요약
df -h로 용량 풀 마운트 확인 (Use% 100%?)df -i로 inode 풀 확인 (IUse% 100%?)- 범인 디렉터리 추적 (
du) - "지웠는데 안 비는" 함정 점검 (
lsof +L1) - 상황별 즉시 처방 → 서비스 복구
1단계: 용량 vs inode 구분하기
가장 먼저 할 일은 어느 쪽이 100%인지 가려내는 것입니다. 두 명령을 나란히 실행하세요.
용량(블록) 확인:
df -hFilesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p1 50G 50G 0 100% /
/dev/nvme1n1 20G 3.2G 16G 17% /datainode 확인:
df -iFilesystem Inodes IUsed IFree IUse% Mounted on
/dev/nvme0n1p1 3.2M 3.2M 0 100% /
/dev/nvme1n1 1.3M 8.4K 1.3M 1% /data판독법은 단순합니다.
- Use%가 100% → 용량(큰 파일)이 꽉 찼습니다. → 2~3단계 용량 추적으로
- IUse%가 100% → 파일 개수가 한계입니다(작은 파일 수백만 개). 용량은 멀쩡해도 새 파일을 못 만듭니다. → inode 처방으로
둘 다 멀쩡한데 에러가 난다면? 삭제된 파일을 프로세스가 붙들고 있는 함정(2단계 후반)을 의심하세요.
2단계: 용량을 잡아먹는 범인 추적
용량 풀이라면, 루트부터 단계적으로 좁혀 들어갑니다.
du -sh /* 2>/dev/null | sort -rh | head32G /var
9.1G /usr
4.2G /home
.../var가 범인이군요. 한 단계 더 들어갑니다.
du -sh /var/* 2>/dev/null | sort -rh | head
du -sh /var/log/* 2>/dev/null | sort -rh | head
du -sh /var/lib/docker/* 2>/dev/null | sort -rh | head대부분의 장애는 3대 용의자로 수렴합니다.
| 경로 | 원인 |
|---|---|
/var/log, journald | 로그·저널 폭증 |
/var/lib/docker | 이미지·볼륨·빌드 캐시 누적 |
| 앱 데이터/업로드 | 대용량 파일 적재 |
"지웠는데 공간이 안 비는" 함정
큰 로그를 rm으로 지웠는데 df -h가 그대로라면, 프로세스가 삭제된 파일의 핸들(fd)을 붙잡고 있는 것입니다. Linux는 열린 파일이 모두 닫힐 때까지 블록을 회수하지 않습니다.
lsof +L1COMMAND PID USER FD TYPE ... NLINK NAME
nginx 812 root 4w REG ... 0 /var/log/nginx/access.log (deleted)NLINK 0 + (deleted)가 범인입니다. 두 가지 처방:
# 방법 1: 해당 프로세스 재시작(가장 안전)
systemctl restart nginx
# 방법 2: 재시작이 곤란하면 fd를 비워 즉시 회수 (PID=812, FD=4)
: > /proc/812/fd/43단계: 상황별 즉시 처방
로그 폭증
# journald 저널을 200MB로 축소
journalctl --vacuum-size=200M
# 특정 대용량 로그를 0으로 비우기 (rm 대신 truncate 권장)
truncate -s 0 /var/log/nginx/access.log⚠️
truncate는 파일 내용을 즉시 0으로 만듭니다. 보존이 필요한 로그는 먼저 백업/압축(gzip)하고 비우세요.
Docker 누적
컨테이너 배포가 늘면서 로컬 디스크의 이미지·볼륨·빌드 캐시 누적이 신규 장애 1순위로 떠올랐습니다. 단계적으로 정리하세요.
# 1) 사용 안 하는(dangling) 이미지만
docker image prune
# 2) 중지된 컨테이너·네트워크·캐시 정리(이미지는 dangling만)
docker system prune
# 3) 빌드 캐시 정리
docker builder prune# 최후의 수단: 미사용 이미지 전부 + 볼륨까지 삭제
docker system prune -a --volumes⚠️
prune -a --volumes는 **실행 중이지 않은 모든 이미지와 볼륨(=DB 데이터까지!)**을 지웁니다. 운영 볼륨이 실수로 날아갈 수 있으니docker volume ls로 보존 대상부터 확인하세요.
inode 고갈
용량은 남는데 IUse%가 100%면, 보통 작은 파일 수백만 개입니다. 어디 있는지 찾습니다.
# 디렉터리별 파일 개수 상위 추적
for d in /var/* /tmp /home/*; do echo "$(find "$d" -xdev | wc -l) $d"; done | sort -rn | head흔한 원인은 세션 파일, 메일 큐, __pycache__, 만료 안 된 캐시 조각입니다. 대량 삭제는 rm -rf *가 인자 한계에 걸리므로:
find /var/cache/myapp -type f -name '*.tmp' -delete풀마운트 식별 표
| 증상 | 진단 명령 | 흔한 원인 | 즉시 조치 |
|---|---|---|---|
| 용량 풀 (Use% 100%) | df -h, du -sh /* | 대용량 로그·DB·업로드 | truncate, 로그 압축/이동 |
| inode 풀 (IUse% 100%) | df -i, find | wc -l | 소형 파일 수백만 개 | find ... -delete |
| 삭제 후 미반영 | lsof +L1 | 프로세스가 fd 점유 | 프로세스 재시작 / : > /proc/PID/fd/N |
| Docker 누적 | du -sh /var/lib/docker/* | 이미지·볼륨·캐시 | docker system prune |
실무 한마디
경험상 디스크 풀 장애의 8할은 "예전엔 잘 돌던 서버"에서 터집니다. 트래픽이 늘면서 access 로그가 하루 수 GB씩 쌓이는데 logrotate가 빠져 있거나, CI/CD 러너가 빌드 캐시를 무한정 쌓는 경우죠. 한 번은 df -h가 70%인데 쓰기가 막혀 30분을 헤맸는데, 범인은 배포 스크립트가 옛 로그를 rm만 하고 앱을 재시작 안 해 fd가 붙들려 있던 것이었습니다. 그 뒤로 디스크 장애가 나면 무조건 df -i와 lsof +L1을 먼저 칩니다. 이 두 줄이 평균 복구 시간을 절반으로 줄였습니다.
재발 방지
급한 불을 껐다면 다음 세 가지로 재발을 막으세요.
1) logrotate로 로그 자동 순환
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 7
compress
missingok
notifempty
copytruncate
}2) journald 영구 용량 제한
# /etc/systemd/journald.conf
[Journal]
SystemMaxUse=500M
SystemMaxFileSize=50Msystemctl restart systemd-journald3) 80% 임계치 모니터링 알림
클라우드에서는 EBS 자동 확장도 있지만, 비용·한계가 있어 사용률 80% 알림 → 사람이 판단하는 운영이 안전합니다. CloudWatch, Prometheus node_filesystem_avail_bytes, 또는 간단히 cron + Slack 웹훅으로도 충분합니다.
자주 묻는 질문 (FAQ)
Q. df -h는 여유가 있는데 왜 "No space left on device"가 뜨나요?
A. 두 가지 가능성입니다. 첫째, inode 고갈(df -i의 IUse% 100%) — 용량은 남아도 파일을 더 못 만듭니다. 둘째, 삭제된 파일을 프로세스가 붙들고 있는 경우(lsof +L1) — 블록이 회수되지 않습니다.
Q. 로그 파일을 rm으로 지웠는데 공간이 안 늘어요.
A. 프로세스가 해당 fd를 열고 있어서입니다. lsof +L1로 PID를 찾아 프로세스를 재시작하거나, 긴급 시 : > /proc/PID/fd/N으로 fd를 비우면 즉시 회수됩니다. rm 대신 truncate -s 0로 비우는 습관도 도움이 됩니다.
Q. docker system prune -a는 안전한가요?
A. -a --volumes는 미사용 이미지 전부와 볼륨까지 삭제하므로 운영 DB 데이터가 날아갈 수 있습니다. 먼저 docker image prune, docker builder prune처럼 범위가 좁은 명령부터 쓰고, 볼륨 삭제 전에는 반드시 docker volume ls로 보존 대상을 확인하세요.
인접 트러블슈팅도 함께 보면 좋습니다 — 포트 충돌(EADDRINUSE), PostgreSQL too many clients, MySQL 1045 인증 오류, systemd 서비스 장애 진단.
이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.
댓글
불러오는 중...