Home Linux AWS Cloud Docker Python AI
클릭하여 터미널 활성화

No space left on device 4가지 원인과 해결법

// Linux · 디스크 · inode · 트러블슈팅 · Rocky Linux · 서버 관리
서버 운영 중 가장 당황스러운 에러 중 하나가 No space left on device다. 단순히 디스크가 꽉 찬 경우도 있지만, df -h로 확인하면 용량이 남아있는데도 이 에러가 뜨는 경우가 있다. Rocky Linux 9 환경에서 4가지 원인을 직접 재현하고 해결한다.
📋 이 글에서 다루는 것
No space left on device가 발생하는 4가지 원인과 진단 방법
진짜 디스크 부족, inode 고갈, 삭제한 파일이 용량을 잡고 있는 경우, 로그 폭증
df -h에서 용량이 남아있는데 에러가 뜨는 이유 (df -i로 inode 확인)
rm vs truncate — 왜 로그 파일은 rm으로 지우면 안 되는지
재발 방지를 위한 logrotate 설정과 트러블슈팅 플로우차트
에러 메시지
terminal
$ touch /tmp/newfile
touch: cannot touch '/tmp/newfile': No space left on device

$ echo "data" > /var/log/app.log
bash: /var/log/app.log: No space left on device

파일을 생성하거나 쓸 수 없는 상태다. 원인은 크게 4가지로 나뉜다.

#원인핵심 진단 명령어특징
1진짜 디스크 용량 부족df -hUse% 100%
2inode 고갈df -i용량은 남아있는데 에러
3삭제한 파일이 용량을 잡고 있음lsof +L1rm 후에도 용량 안 늘어남
4/var/log 로그 폭증du -sh /var/log/*로그가 GB 단위로 쌓임

원인 1. 진짜 디스크 용량 부족

가장 단순한 경우다. 디스크 파티션이 100% 찬 상태다. 로그 파일이 무한정 쌓이거나, 대용량 파일이 생성됐거나, 백업 파일을 정리하지 않았을 때 발생한다.

진단
디스크 용량 확인
$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        20G   20G     0 100% /
tmpfs           3.9G     0  3.9G   0% /dev/shm

Use% 100% — 디스크가 꽉 찼다. 이제 어디서 용량을 먹고 있는지 찾아야 한다.

해결 — 큰 파일 찾아서 정리
디렉토리별 용량 확인
$ du -sh /* 2>/dev/null | sort -rh | head -10
8.5G    /var
4.2G    /usr
3.1G    /home
2.8G    /opt

$ du -sh /var/* | sort -rh | head -5
7.9G    /var/log
312M    /var/cache
180M    /var/lib

/var/log가 7.9G나 차지하고 있다. 더 파고들어보자.

50MB 이상 파일 찾기
$ find / -xdev -type f -size +50M -exec ls -lh {} \; 2>/dev/null
-rw-r--r-- 1 root root 3.2G /var/log/messages
-rw-r--r-- 1 root root 2.1G /var/log/secure
-rw-r--r-- 1 root root 1.8G /var/log/app/error.log
⚠️ 중요 — 로그 파일은 rm이 아니라 truncate로 비워야 한다. 프로세스가 파일을 열고 있으면 삭제해도 용량이 회수되지 않는다 (원인 3에서 자세히 설명).
로그 파일 비우기 (truncate)
$ truncate -s 0 /var/log/messages
$ truncate -s 0 /var/log/secure

$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        20G   12G   6.7G  64% /
✓ 해결 — 100% → 64%로 용량 확보.
💡 팁ncdu를 설치하면 인터랙티브하게 용량을 분석할 수 있다. dnf install -y ncdu && ncdu / — 방향키로 디렉토리를 탐색하면서 어디가 큰지 직관적으로 파악 가능하다.

원인 2. inode 고갈 — 용량은 남아있는데 에러

이것이 가장 헷갈리는 케이스다. df -h로 확인하면 용량은 충분한데 파일을 만들 수 없다. 많은 사람들이 이 상황에서 "디스크 남아있는데 왜?"하고 멘붕에 빠진다.

파일 시스템은 파일 하나당 inode 하나를 사용한다. inode는 파일의 메타데이터(권한, 소유자, 위치 등)를 저장하는 자료구조인데, 파일 시스템 생성 시 개수가 고정된다. 파일 크기가 0바이트여도 inode 하나를 소비한다. 그래서 작은 파일이 수십만 개 쌓이면 용량은 남아있어도 inode가 바닥날 수 있다.

진단 — df -h vs df -i

핵심은 df -hdf -i둘 다 확인하는 것이다.

용량 vs inode 비교
$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        20G  8.0G   11G  43% /        # ← 용량 여유 충분!

$ df -i /
Filesystem      Inodes   IUsed   IFree IUse% Mounted on
/dev/sda1       1310720 1310720       0  100% /  # ← inode 완전 소진!

df -h: Use% 43% — 용량 여유 충분. df -i: IUse% 100% — inode 완전 소진. 용량은 남았지만 inode가 0이라 새 파일을 만들 수 없는 것이다.

진단 — 어디에 파일이 많은지 찾기
디렉토리별 파일 개수
$ find / -xdev -type d -exec sh -c 'echo "$(find "$1" -maxdepth 1 -type f | wc -l) $1"' _ {} \; 2>/dev/null | sort -rn | head -10
524288 /var/spool/postfix/maildrop
412000 /tmp/sess
89320  /var/lib/php/sessions

/var/spool/postfix/maildrop52만 개의 파일이 쌓여있었다. 미발송 메일 큐가 원인이었다.

해결
대량 파일 삭제
$ find /var/spool/postfix/maildrop -type f -delete

$ df -i /
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/sda1       1310720 501320  809400   38% /
✓ 해결 — inode 100% → 38%로 복구.
💡 inode 고갈의 흔한 원인 — Postfix/cron 미발송 메일 큐(/var/spool/postfix/maildrop), PHP 세션 파일(/var/lib/php/sessions), 임시 파일(/tmp), 캐시 파일이 소규모로 대량 생성되는 경우.

원인 3. 파일 삭제했는데 용량이 안 늘어남

큰 로그 파일을 rm으로 삭제했는데, df -h로 확인하면 용량이 그대로인 경우다. 이건 많은 사람들이 겪는 함정이다.

이유는 간단하다. 파일을 삭제해도 프로세스가 해당 파일을 열고 있으면 실제로는 디스크에서 제거되지 않는다. 파일은 (deleted) 상태로 남아서 용량을 계속 차지한다. 프로세스가 파일 핸들을 놓을 때까지(= 프로세스가 종료되거나 재시작될 때까지) 디스크 공간은 회수되지 않는다.

진단
삭제됐지만 열려있는 파일 확인
$ lsof +L1 2>/dev/null | head -10
COMMAND   PID USER   FD   TYPE DEVICE   SIZE/OFF NLINK NODE NAME
tail      450 root    3r  REG  0,127   52428800     0 2890 /var/log/biglog (deleted)
java     1280 app    12w  REG  8,1   2147483648     0 3921 /var/log/app.log (deleted)

(deleted)가 보이면 파일은 삭제되었지만 프로세스가 아직 잡고 있는 상태다. SIZE/OFF 열을 보면 해당 파일이 차지하는 용량을 알 수 있다.

해결 — 방법 A: 프로세스 재시작

가장 깔끔한 방법이다. 프로세스를 재시작하면 파일 핸들이 해제되면서 용량이 즉시 회수된다.

프로세스 재시작
$ kill 450
$ systemctl restart app-service

$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        20G   12G   6.7G  64% /
해결 — 방법 B: 프로세스를 죽일 수 없는 경우

프로덕션에서 프로세스를 재시작할 수 없는 상황이라면, /proc을 통해 열린 파일 디스크립터를 직접 비울 수 있다.

/proc을 통해 열린 파일 비우기
# PID 1280이 잡고 있는 fd 12를 비우기
$ : > /proc/1280/fd/12

$ df -h /  # 용량 즉시 확보됨
❌ 이 문제를 방지하려면 — 로그 파일은 rm 대신 truncate -s 0으로 비워라. 파일을 삭제하지 않고 내용만 비우기 때문에 프로세스가 열고 있어도 안전하다. rm은 파일 자체를 삭제하므로 프로세스가 잡고 있으면 용량이 회수되지 않는다.

원인 4. /var/log 로그 폭증

애플리케이션이 에러 로그를 쏟아내거나, logrotate가 제대로 동작하지 않으면 /var/log가 기하급수적으로 커진다. 특히 애플리케이션이 무한 루프에 빠져서 에러를 반복 출력하는 경우, 몇 시간 만에 디스크가 꽉 차는 일이 실제로 발생한다.

진단
/var/log 용량 분석
$ du -sh /var/log/
7.9G    /var/log/

$ du -sh /var/log/* | sort -rh | head -5
3.2G    /var/log/messages
2.1G    /var/log/secure
1.8G    /var/log/app/error.log
512M    /var/log/journal
180M    /var/log/audit
50MB 이상 로그파일
$ find /var/log -type f -size +50M -exec ls -lh {} \;
-rw-r--r-- 1 root root 3.2G /var/log/messages
-rw-r--r-- 1 root root 2.1G /var/log/secure
-rw-r--r-- 1 root root 1.8G /var/log/app/error.log
해결 — 즉시 조치
로그 비우기
# rm이 아닌 truncate 사용!
$ truncate -s 0 /var/log/messages
$ truncate -s 0 /var/log/secure

# journal 로그 정리 (100MB만 유지)
$ journalctl --vacuum-size=100M
Vacuuming done, freed 420.0M of archived journals.

$ du -sh /var/log/
1.2G    /var/log/
해결 — 재발 방지 (logrotate)

즉시 조치만으로는 또 쌓인다. logrotate를 설정해서 로그가 일정 크기 이상 커지면 자동으로 회전(rotate)시켜야 한다. copytruncate 옵션이 핵심인데, 로그 파일을 복사한 뒤 원본을 비우는 방식이라 프로세스 재시작 없이 로테이션이 가능하다.

/etc/logrotate.d/app
/var/log/app/*.log {
    daily                # 매일 로테이션
    rotate 7             # 7일치만 보관
    compress             # gz 압축
    missingok            # 파일 없어도 에러 안 냄
    notifempty           # 빈 파일은 스킵
    maxsize 100M         # 100MB 넘으면 일자 관계없이 로테이션
    copytruncate         # 복사 후 원본 비우기 (프로세스 재시작 불필요)
}
💡 팁logrotate -d /etc/logrotate.d/app으로 dry run을 돌려서 설정이 제대로 적용되는지 미리 확인할 수 있다.

트러블슈팅 플로우차트

No space left on device를 만났을 때, 이 순서대로 확인하면 원인을 빠르게 찾을 수 있다.

No space left on device 발생 │ ├─ 1. df -h 확인 → 100%인가? │ → YES: 큰 파일 찾기 (du -sh /*, find -size +50M) │ → NO: 2번으로 │ ├─ 2. df -i 확인 → inode 100%인가? │ → YES: 파일 많은 디렉토리 찾기 (find -type f | wc -l) │ → NO: 3번으로 │ ├─ 3. 파일 삭제했는데 용량 그대로? │ → lsof +L1 | grep deleted │ → 프로세스 재시작 또는 /proc/PID/fd truncate │ └─ 4. 재발 방지 → logrotate 설정 → journalctl --vacuum-size → cron으로 /tmp 주기적 정리

자주 쓰는 명령어 정리
disk troubleshooting cheatsheet
# 디스크 용량 확인
$ df -h

# inode 확인
$ df -i

# 디렉토리별 용량 (상위 10개)
$ du -sh /* 2>/dev/null | sort -rh | head -10

# 큰 파일 찾기 (100MB 이상)
$ find / -xdev -type f -size +100M -exec ls -lh {} \;

# 삭제됐지만 열려있는 파일
$ lsof +L1

# 로그 비우기 (안전)
$ truncate -s 0 /var/log/messages

# journal 정리
$ journalctl --vacuum-size=100M

# 로그 파일 실시간 증가 감시
$ watch -n 1 'du -sh /var/log/*'

테스트 환경
항목버전
OSRocky Linux 9.3 (Blue Onyx)
FilesystemXFS / ext4

자주 묻는 질문 (FAQ)
Q. df -h에서 용량이 남아있는데 No space left on device가 뜨면?
df -i로 inode 사용률을 확인하라. IUse%가 100%면 inode가 고갈된 것이다. 파일 크기와 관계없이 파일 하나당 inode 하나를 소비하기 때문에, 작은 파일이 대량으로 쌓이면 용량은 남아있어도 새 파일을 만들 수 없다.
Q. rm과 truncate의 차이는?
rm은 파일 자체를 삭제한다. 하지만 프로세스가 파일을 열고 있으면 디스크 공간이 회수되지 않는다. truncate -s 0은 파일을 삭제하지 않고 내용만 비운다. 파일 핸들이 유지되기 때문에 프로세스가 열고 있어도 안전하고, 용량도 즉시 확보된다. 로그 파일은 항상 truncate를 쓰는 게 맞다.
Q. lsof +L1은 정확히 뭘 보여주나?
link count가 1 미만인 열린 파일, 즉 삭제됐지만(unlinked) 아직 프로세스가 잡고 있는 파일 목록을 보여준다. (deleted) 표시가 붙어 있으면 파일은 디렉토리에서 사라졌지만 디스크 공간을 계속 차지하고 있다는 뜻이다.
Q. XFS에서 inode를 늘릴 수 있나?
XFS는 inode를 동적으로 할당하기 때문에 ext4보다 inode 고갈이 발생하기 어렵다. 하지만 maxpct 설정이 낮으면(기본 25%) inode 할당 가능 공간이 제한된다. xfs_growfs -m으로 비율을 늘릴 수 있다. ext4는 파일 시스템 생성 시 inode 수가 고정되므로 포맷 전에 mkfs.ext4 -N으로 충분히 설정해야 한다.
Q. 디스크 부족을 사전에 모니터링하려면?
Prometheus의 node_filesystem_avail_bytes 메트릭으로 남은 용량을, node_filesystem_files_free로 남은 inode를 모니터링할 수 있다. Grafana에서 80% 이상일 때 알림을 설정하면 디스크가 꽉 차기 전에 대응할 수 있다.

📌 이 글 핵심 요약
No space left on device는 디스크 용량 부족, inode 고갈, 삭제된 파일의 미회수, 로그 폭증 4가지가 주요 원인이다
df -hdf -i를 둘 다 확인해야 한다 — 용량이 남아있어도 inode가 바닥나면 같은 에러가 뜬다
로그 파일은 rm이 아니라 truncate -s 0으로 비워야 한다 — 프로세스가 열고 있으면 rm으로는 용량이 회수되지 않는다
lsof +L1로 삭제됐지만 용량을 잡고 있는 파일을 찾고, 프로세스 재시작 또는 /proc truncate로 해결한다
재발 방지는 logrotate 설정이 핵심이다 — copytruncate 옵션으로 프로세스 재시작 없이 로테이션 가능