리눅스에서 No space left on device 오류가 발생하면 대부분 디스크가 가득 찼다고 생각합니다. 하지만 실제 원인은 디스크 블록 부족뿐 아니라 inode 고갈, 삭제됐지만 프로세스가 계속 점유하는 파일, 마운트 실패, 급격히 증가한 로그일 수 있습니다.

원인을 확인하지 않고 rm -rf로 파일부터 지우면 장애 분석에 필요한 로그를 잃거나 서비스가 더 크게 중단될 수 있습니다. 이 글에서는 Rocky Linux, RHEL, CentOS, Ubuntu 등 일반적인 리눅스 서버에서 사용할 수 있는 진단 순서와 안전한 해결 방법을 정리합니다.

먼저 실행할 5가지 명령어

시간이 없다면 아래 순서대로 확인합니다. /path에는 오류가 발생한 파일이나 디렉터리 경로를 입력합니다.

# 1. 오류가 발생한 경로가 어느 파일시스템에 속하는지 확인
findmnt -T /path

# 2. 파일시스템의 디스크 블록 사용률 확인
df -hT /path

# 3. inode 사용률 확인
df -i /path

# 4. 같은 파일시스템 안에서 용량이 큰 디렉터리 확인
sudo du -xhd1 /path 2>/dev/null | sort -h

# 5. 삭제됐지만 프로세스가 열고 있는 파일 확인
sudo lsof +L1 2>/dev/null

주의: dufind는 파일이 많은 서버에서 디스크 I/O를 증가시킬 수 있습니다. 운영 서비스의 부하를 확인하면서 범위를 좁혀 실행해야 합니다.

No space left on device의 주요 원인

원인 대표 증상 우선 확인 명령어
디스크 블록 부족 Use%가 100% 또는 임계치에 근접 df -hT
inode 고갈 용량은 남았지만 파일을 새로 만들 수 없음 df -i
삭제된 열린 파일 파일을 삭제했는데 df 사용량이 줄지 않음 lsof +L1
로그·캐시 급증 /var 또는 루트 파일시스템이 빠르게 증가 du, journalctl --disk-usage
마운트 실패 별도 디스크 경로의 데이터가 루트 파일시스템에 쌓임 findmnt -T, lsblk -f

1. 디스크 블록 사용률 확인

df -hT
df -hT /var/log

df는 파일시스템 단위로 전체 크기, 사용량, 여유 공간, 사용률과 마운트 위치를 보여줍니다. -h는 사람이 읽기 쉬운 단위로 출력하고, -T는 XFS·ext4 같은 파일시스템 유형을 함께 표시합니다.

전체 결과만 보고 판단하지 말고 실제로 쓰기에 실패한 경로를 인수로 지정해야 합니다. 예를 들어 애플리케이션이 /data/app.log에 기록하지 못한다면 다음과 같이 확인합니다.

findmnt -T /data/app.log
df -hT /data/app.log

루트 파일시스템에는 여유 공간이 있어도 /data가 별도 파일시스템이고 가득 찼다면 해당 경로에서는 파일을 만들 수 없습니다.

2. inode 사용률 확인

df -i
df -i /var

inode는 파일의 권한, 소유자, 크기, 시간 정보와 데이터 위치 등의 메타데이터를 관리하는 자료구조입니다. 작은 파일이 매우 많이 생성되면 디스크 용량이 남아 있어도 사용 가능한 inode가 먼저 소진될 수 있습니다.

IUse%가 100%라면 큰 파일 몇 개를 지우는 것보다 불필요한 작은 파일을 많이 정리해야 효과가 있습니다. 파일 수가 많은 경로는 다음 명령으로 찾을 수 있습니다.

# /var와 같은 파일시스템 안에서 파일이 많은 디렉터리 확인
sudo find /var -xdev -type f -printf '%h\n' 2>/dev/null \
  | sort | uniq -c | sort -nr | head -n 30

세션 파일, 애플리케이션 캐시, 메일 큐, 임시 파일처럼 대량 생성되는 파일이 흔한 원인입니다. 삭제 전에는 보존 기간과 서비스 영향을 반드시 확인합니다.

3. 용량이 큰 디렉터리와 파일 찾기

루트 파일시스템이 가득 찼다면 우선 최상위 디렉터리별 사용량을 확인하고, 큰 경로로 한 단계씩 내려갑니다.

sudo du -xhd1 / 2>/dev/null | sort -h
sudo du -xhd1 /var 2>/dev/null | sort -h
sudo du -xhd1 /var/log 2>/dev/null | sort -h

-x는 다른 파일시스템으로 넘어가지 않게 하며, -d1은 바로 아래 한 단계만 집계합니다. du의 옵션과 계산 방식은 기존 글인 du 명령어 사용방법에서 더 자세히 확인할 수 있습니다.

특정 파일시스템에서 1GB보다 큰 파일을 찾는 예시는 다음과 같습니다.

sudo find /var -xdev -type f -size +1G \
  -printf '%s %p\n' 2>/dev/null \
  | sort -nr | head -n 30

주로 확인할 경로는 /var/log, /var/cache, /tmp, /home, /opt, /var/lib/docker입니다. 다만 /var/lib 아래의 파일을 수동으로 삭제하면 데이터베이스나 컨테이너 런타임이 손상될 수 있으므로 각 서비스의 정식 정리 절차를 사용해야 합니다.

4. 파일을 삭제했는데 용량이 줄지 않는 경우

리눅스에서는 실행 중인 프로세스가 파일을 열고 있으면 파일명을 삭제해도 데이터 블록이 즉시 반환되지 않습니다. 디렉터리에서는 보이지 않아 du가 계산하지 못하지만, 파일 디스크립터가 닫힐 때까지 df에는 사용 중인 공간으로 남습니다.

sudo lsof +L1 2>/dev/null

# 용량이 큰 항목부터 확인
sudo lsof +L1 2>/dev/null \
  | awk 'NR>1 {print $7, $1, $2, $4, $9}' \
  | sort -nr | head -n 30

출력에서 프로세스명, PID, 파일 디스크립터와 크기를 확인합니다. 해결 방법은 해당 파일을 점유한 서비스를 정상 절차로 재시작하거나 애플리케이션이 파일을 다시 열도록 하는 것입니다.

sudo systemctl restart 서비스명
sudo lsof +L1 2>/dev/null
df -hT

운영 서버에서는 서비스 이중화와 영향도를 먼저 확인해야 합니다. 원인 확인 없이 프로세스를 kill -9로 종료하거나 /proc/PID/fd를 강제로 비우는 방법은 데이터 유실과 장애를 일으킬 수 있어 우선 조치로 권장하지 않습니다.

5. systemd journal 로그가 큰 경우

journalctl --disk-usage

systemd journal이 많은 공간을 차지한다면 오래된 보관 로그를 크기 또는 기간 기준으로 정리할 수 있습니다.

# 활성 로그를 먼저 보관 상태로 전환한 뒤, 보관 로그를 500MB 이하로 정리
sudo journalctl --rotate --vacuum-size=500M

# 14일보다 오래된 보관 로그 정리
sudo journalctl --vacuum-time=14d

--vacuum-* 옵션은 보관된 journal 파일을 대상으로 합니다. 활성 로그까지 고려해 즉시 정리하려면 --rotate와 함께 사용하는 것이 명확합니다.

재발 방지를 위해 배포판과 운영 정책에 맞게 journal의 최대 사용량을 제한할 수 있습니다.

# /etc/systemd/journald.conf.d/10-size-limit.conf
[Journal]
SystemMaxUse=1G
RuntimeMaxUse=256M
sudo systemctl restart systemd-journald
journalctl --disk-usage

systemd 서비스 구조가 익숙하지 않다면 Systemd service 생성과 구성 요소 글도 함께 참고할 수 있습니다.

6. 마운트가 풀려 루트 디스크에 데이터가 쌓인 경우

/data가 별도 스토리지여야 하는데 부팅 실패나 네트워크 장애로 마운트되지 않으면, 애플리케이션이 같은 경로의 루트 파일시스템에 데이터를 계속 기록할 수 있습니다.

findmnt -T /data
lsblk -f
systemctl --failed
journalctl -b -u '*.mount'

이 경우 파일을 먼저 삭제하는 것이 아니라 애플리케이션 쓰기를 중지하고 원래 파일시스템의 마운트 상태를 복구해야 합니다. 마운트 아래에 가려진 파일을 확인하려면 서비스 영향과 데이터 정합성을 검토한 유지보수 절차가 필요합니다.

df와 du의 용량이 다른 이유

df는 파일시스템이 할당한 블록을 기준으로 사용량을 보고하고, du는 현재 디렉터리 트리에서 접근할 수 있는 파일을 순회해 사용량을 계산합니다. 따라서 다음 상황에서는 값이 달라질 수 있습니다.

  • 삭제됐지만 프로세스가 계속 열고 있는 파일
  • 파일시스템 메타데이터와 예약 영역
  • 권한이 없어 du가 읽지 못한 디렉터리
  • 하위 경로에 마운트된 다른 파일시스템
  • 스냅샷과 Copy-on-Write 파일시스템의 공유 블록

dfdu 차이가 크다면 가장 먼저 lsof +L1과 마운트 구조를 확인하는 것이 좋습니다.

운영 서버의 안전한 복구 순서

  1. 오류 경로 확인: 애플리케이션이 실제로 쓰는 경로와 파일시스템을 확인합니다.
  2. 증가 원인 억제: 로그 폭주나 반복 작업처럼 용량을 계속 늘리는 원인을 먼저 멈춥니다.
  3. 장애 증거 보존: 필요한 로그와 상태 정보를 별도 위치에 보관한 뒤 정리합니다.
  4. 정식 절차로 정리: logrotate, journal vacuum, 애플리케이션의 캐시 정리 기능을 우선 사용합니다.
  5. 복구 검증: 디스크·inode 사용률, 파일 생성, 서비스 상태와 애플리케이션 로그를 다시 확인합니다.
df -hT /path
df -i /path
touch /path/.write-test && rm -f /path/.write-test
systemctl --failed

재발 방지 체크리스트

  • 디스크 사용률뿐 아니라 inode 사용률도 모니터링합니다.
  • 경고와 위험 임계치를 나누고 용량 증가 속도를 함께 관찰합니다.
  • 애플리케이션 로그에 logrotate 또는 자체 보존 정책을 설정합니다.
  • systemd journal의 최대 크기와 보존 기간을 운영 정책에 맞게 제한합니다.
  • Docker·데이터베이스·백업 솔루션은 제품이 제공하는 정리 기능을 사용합니다.
  • /var/log, 데이터, 백업 영역을 분리해 한 영역의 증가가 전체 OS 장애로 번지는 것을 줄입니다.
  • 마운트 실패 상태에서 애플리케이션이 로컬 디스크에 계속 쓰지 않도록 의존성과 사전 점검을 구성합니다.

자주 묻는 질문

디스크 용량이 남아 있는데도 No space left on device가 발생하는 이유는?

가장 먼저 inode 사용률과 실제 오류 경로가 속한 파일시스템을 확인해야 합니다. df -h에 여유 공간이 있어도 df -i가 100%이거나, 다른 마운트 포인트가 가득 찼다면 파일 생성에 실패합니다.

로그 파일을 삭제했는데 df 사용량이 줄지 않는 이유는?

프로세스가 삭제된 파일을 계속 열고 있을 가능성이 큽니다. lsof +L1으로 점유 프로세스를 확인하고 해당 서비스를 정상적으로 재시작하거나 파일을 다시 열도록 해야 공간이 반환됩니다.

/var/log 아래 파일을 모두 삭제해도 되나요?

권장하지 않습니다. 장애 원인과 감사 기록을 잃을 수 있고, 애플리케이션에 따라 로그 파일 재생성 권한 문제도 발생할 수 있습니다. logrotate, journalctl vacuum 또는 제품별 로그 정리 기능을 사용해야 합니다.

du 명령어가 너무 느린 경우에는 어떻게 하나요?

-x로 다른 파일시스템 탐색을 막고 -d1로 깊이를 제한한 뒤, 큰 디렉터리로 단계적으로 내려갑니다. 파일 수가 매우 많은 운영 서버에서는 I/O 부하가 낮은 시간에 실행하는 것이 안전합니다.

정리

리눅스의 No space left on device 해결은 파일 삭제부터 시작하는 작업이 아닙니다. findmnt로 대상 파일시스템을 확인하고, df -hT로 블록 사용률, df -i로 inode, du로 디렉터리 사용량, lsof +L1로 삭제된 열린 파일을 순서대로 확인해야 합니다.

원인을 구분한 다음 로그 보존 정책, 서비스 재시작, 마운트 복구 등 원인에 맞는 조치를 적용해야 데이터 유실과 재발을 막을 수 있습니다.

참고 문서