디스크 공간 부족이 초래하는 문제와 핵심 인사이트
디스크 공간 부족은 단순한 경고 메시지로 끝나지 않습니다. 장애 복구 지연, 로그 유실, 애플리케이션 쓰기 실패, 데이터베이스 성능 저하, 심하면 커널의 I/O 에러와 서비스 다운까지 이어질 수 있습니다. 특히 컨테이너/클라우드 환경에서는 디스크 부족이 노드 단위의 파드 축출(eviction)로 확산되어 전체 서비스 가용성을 떨어뜨리기도 합니다.
이 글에서는 시스템 관리자 관점에서 디스크 공간 부족을 선제적으로 방지하고, 실제로 부족 상황이 발생했을 때 신속하게 대응할 수 있는 모니터링과 스케일링 전략을 구체적인 예시와 함께 제시합니다. 목표는 간단합니다. “장애 전에 알아차리고, 장애가 와도 빠르게 복구하고, 다시 재발하지 않게 만드는 것.”
무엇을 모니터링할 것인가: 지표 설계의 정석
필수 지표
- 사용량 비율: 파일시스템 사용률 (%) — 예: /, /var, /var/lib/docker, /data 등 핵심 마운트별
- 남은 용량: 남은 GB/MB — 절대량으로 경고 기준을 보완
- inode 사용률: 많은 작은 파일이 쌓이는 워크로드에서 필수
- 삭제되었지만 열린 파일: 디스크를 먹는 “유령 파일” 감지
- 성장률: 시계열로 용량 증가 속도를 추정해 예측 경보 설정
- IOPS/대기시간: 디스크 확장 필요성과 성능 한계점 파악
- 컨테이너/파드 단위 ephemeral-storage 사용량(Kubernetes 환경)
추천 도구
- Linux 기본: df, du, lsblk, lsof, journalctl, logrotate
- 모니터링: Prometheus + node_exporter, Grafana, Telegraf/InfluxDB, Datadog, CloudWatch
- 시각화 대시보드: 파일시스템별 사용률/성장률, 상위 디렉터리, open-but-deleted 파일 카운트
경보(Alerts) 임계값 제안
- 경고(Warning): 사용률 75–80% + 24–72시간 내 90% 도달 예상
- 심각(Critical): 사용률 90% 이상 또는 12시간 내 95% 도달 예상
- inode: 80%/90% 기준으로 별도 경보
- Kubernetes: 노드/파드 ephemeral-storage 사용률 80%/90%
예: Prometheus 예측 경보
# 24시간 내 90% 이상 도달 예측
predict_linear(node_filesystem_size_bytes{mountpoint="/var"}[6h], 24*3600)
+ node_filesystem_avail_bytes{mountpoint="/var"} < 0
즉시 대응 플레이북: “지금 당장 공간이 모자랄 때”
아래 절차는 안전한 순서로 구성되어 있습니다. 삭제 전에는 항상 대상이 안전한지 확인하고, 가능하면 스냅샷/백업을 선행하세요.
1) 빠른 현황 파악
- 전체 용량과 inode 확인
df -hT
df -i
- 대용량 디렉터리 탐색
du -xhd1 / | sort -h
du -xhd1 /var | sort -h
du -sh /var/* 2>/dev/null | sort -h
- 대화형 분석 도구
ncdu /var
- 삭제됐지만 열린 파일 확인(공간 반납 안 됨)
lsof +L1
- 가장 큰 파일 상위 20개
find / -xdev -type f -size +100M -printf "%s %p\n" 2>/dev/null \
| sort -nr | head -20
2) 로그 및 캐시 정리
- systemd journal
journalctl --disk-usage
sudo journalctl --vacuum-size=500M
sudo journalctl --vacuum-time=7d
- 패키지 캐시
sudo apt-get clean
sudo dnf clean all
sudo yum clean all
- 애플리케이션 로그 압축/로테이션
sudo logrotate -f /etc/logrotate.conf
logrotate 예시 설정:
/var/log/app/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
}
- 코어덤프 제거/관리
coredumpctl list
sudo coredumpctl purge
3) Docker/Container 정리
- 디스크 사용 현황
docker system df
- 안전한 프룬(중단 영향 최소화)
docker image prune -a
docker container prune
docker volume prune
docker system prune
주의: 현재 사용 중인 이미지/볼륨은 제거되지 않지만, 미사용 리소스만 정리됩니다. 프로덕션에서는 유지해야 할 태그/이미지를 확인 후 실행하세요.
- Docker 디렉터리 자체가 문제일 경우, 별도 디스크로 분리 권장(/var/lib/docker를 전용 파티션으로 마이그레이션).
4) Kubernetes 환경에서의 응급조치
- 노드의 /var/log, /var/lib/docker(또는 containerd) 사용량 확인
- 임시 파드 로그/캐시 정리, Eviction Thresholds 점검
- ephemeral-storage requests/limits 설정 상태 점검
- 불필요한 이미지/파드 정리 및 DaemonSet/Job의 잔여 아티팩트 제거
5) “유령 파일” 해제
삭제된 파일을 잡고 있는 프로세스가 있으면 공간이 반납되지 않습니다.
- lsof +L1로 프로세스 확인
- 해당 프로세스 재시작 또는 로그 재오픈 신호 전송(예: nginx에 USR1)
- copytruncate로 무중단 로그 축소:
: > /var/log/app/app.log
또는 logrotate의 copytruncate 옵션 사용
6) inode 고갈 대응
- 파일 개수 파악
df -i
sudo find /var -xdev -type f | wc -l
- 수백만 개의 작은 파일이 쌓인 경우:
- 임시 파일 정책 강화, 세분화된 로테이션/압축(소량 파일로 합치기), tar/zip 아카이빙
- 장기적으로는 XFS/ZFS/Btrfs 등 파일시스템 특성 및 블록 크기 재검토
7) Windows 서버에서의 정리
- 용량 확인
Get-Volume
Get-PSDrive -PSProvider FileSystem
- 큰 파일 탐색
Get-ChildItem C:\ -Recurse -ErrorAction SilentlyContinue |
Where-Object {!$_.PSIsContainer} |
Sort-Object Length -Descending |
Select-Object FullName, Length -First 50
- 컴포넌트 스토어 정리
Dism.exe /online /Cleanup-Image /StartComponentCleanup /ResetBase
- 임시 파일/다운로드 캐시/Windows Update 캐시 정리: Storage Sense 또는 cleanmgr
- 오래된 Shadow Copy 제거
vssadmin list shadows
vssadmin delete shadows /for=C: /oldest
- 로그/데이터 폴더에 NTFS 압축 적용(읽기 빈도 낮고 CPU 여유 있을 때)
compact /c /s:C:\logs
확장과 스케일링: 용량 문제의 근본 해결
1) 클라우드 블록 스토리지 확장
-
AWS EBS
- ModifyVolume로 크기 증가
- OS에서 파티션 확장
- GPT: growpart로 파티션 확장
- LVM 사용 시 pvresize
- 파일시스템 확장
- ext4:
resize2fs /dev/... - XFS:
xfs_growfs /mountpoint
- ext4:
-
Azure Managed Disk / GCP Persistent Disk
- 포털/CLI로 디스크 크기 변경 → OS 레벨에서 파티션/FS 확장
- 대부분 온라인 확장 가능하나, 백업/스냅샷 선행 권장
확장 후 검증:
lsblk
df -hT
2) LVM으로 유연성 확보
- 디스크 추가 → PV 생성 → VG 확장 → LV 확장 → 파일시스템 확장
pvcreate /dev/nvme1n1
vgextend vg_data /dev/nvme1n1
lvextend -r -L +200G /dev/vg_data/lv_app # -r로 FS 자동 확장
LVM은 온라인 확장이 가능하고, 특정 마운트에만 확장 적용이 쉬워 운영에 유리합니다.
3) RAID/ZFS/Btrfs 풀 확장
- mdadm RAID에 디스크 추가 후 reshape
- ZFS/Btrfs는 풀에 vdev/디스크 추가로 탄력 확장 가능
- ZFS의 압축/디듀플리케이션을 활용하면 실제 사용량을 크게 절감할 수 있음(워크로드 특성 고려)
4) Kubernetes Persistent Volume 확장
- StorageClass에 allowVolumeExpansion: true
- PVC의 storage 요청량을 상향 수정
- 일부 드라이버는 온라인 확장 지원, 그렇지 않다면 파드 재시작 필요
- 파일시스템 레벨에서 자동 확장되지 않는다면 xfs_growfs/resize2fs 실행
5) 데이터 계층화와 외부화
- 정적 콘텐츠/백업/장기 로그 → 오브젝트 스토리지(S3, GCS, Azure Blob)로 이동
- CDN과 연계하여 엣지로 오프로딩
- 데이터베이스 아카이브 파티션 도입(핫/웜/콜드 스토리지 분리)
- 로그 파이프라인(Fluent Bit/Vector)으로 중앙 로그 스토리지(예: S3 + Athena/GLUE, OpenSearch) 전송
6) 경량화 전략
- 컨테이너 이미지 슬림화: multi-stage build, distroless/alpine, 불필요한 패키지 제거
- 애플리케이션 로그 레벨 최적화(INFO→WARN), 구조화된 로그로 불필요한 중복 제거
- 백업 증분화 및 압축 최적화(zstd, lz4 등)
사전 예방: 정책과 자동화로 “다시는” 발생하지 않게
로그와 저널 정책
- journald 제한 예시:
# /etc/systemd/journald.conf
SystemMaxUse=500M
SystemMaxFileSize=50M
MaxRetentionSec=7day
- logrotate 규칙: 일일 회전, 7~14일 보관, 압축, copytruncate로 무중단 회전
- 앱 자체 로그 로테이션 지원 시 해당 기능을 우선 사용
스토리지 할당과 쿼터
- 사용자/그룹 쿼터(ext4): edquota, quotaon
- XFS 프로젝트 쿼터: 팀/서비스 단위 디렉터리 쿼터
- Kubernetes ephemeral-storage requests/limits 설정으로 파드 단위 제어
청소 작업 자동화
- 주기적 캐시/로그 정리 스크립트(systemd timer/cron)
#!/usr/bin/env bash
set -euo pipefail
# 오래된 로그/코어덤프/apt 캐시 정리
journalctl --vacuum-time=14d
apt-get clean || true
find /var/log -type f -name "*.gz" -mtime +30 -delete
find /var/tmp -type f -mtime +7 -delete
coredumpctl purge || true
- Docker 이미지 정리 타이머(미사용 30일 경과)
docker image prune -a --filter "until=720h" -f
모니터링과 용량 계획
- 월간/분기별 용량 리뷰: 상위 소비자, 성장률, 예산/조달 계획
- 예측 경보 도입(predict_linear) 및 슬랙/이메일 통합 알림
- 중요한 마운트(/var, /var/lib/docker, DB 데이터 디렉터리) 별도 대시보드
백업/스냅샷 수명주기
- 스냅샷은 빠른 복구에 유용하지만 무제한 증가는 비용/용량 폭탄
- 수명주기(Lifecycle) 정책으로 N일 이후 자동 삭제
- 오브젝트 스토리지 버전 관리와 Glacier/Archive 이동 정책
시나리오별 실전 대응 가이드
시나리오 1: 로그 폭증으로 /var 가 95% 도달
- 현황 체크
df -hT /var
du -xhd1 /var | sort -h
journalctl --disk-usage
- 응급조치
journalctl --vacuum-time=3d
sudo logrotate -f /etc/logrotate.conf
- 근본 조치
- 앱 로그 레벨 조정, 특정 모듈 디버그 비활성화
- logrotate 정책 강화(일간→시간 단위 회전, 더 짧은 보관)
- 로그를 중앙 수집기로 전송해 로컬 보관 최소화
시나리오 2: Docker overlay2 팽창으로 노드 불안정
- 분석
du -sh /var/lib/docker/*
docker system df
docker image ls --format '{{.Repository}}:{{.Tag}} {{.Size}}' | sort -hk2
- 정리
docker image prune -a
docker container prune
docker volume prune
- 근본 조치
- /var/lib/docker를 전용 디스크로 분리
- CI에서 이미지 슬림화, 오래된 태그 정리, 레지스트리 GC
- Kubernetes라면 ephemeral-storage limit 설정
시나리오 3: 데이터베이스 볼륨 증가 가속
- 단기
- 인덱스 재구성/진공(Autovacuum 튜닝), 오래된 파티션 아카이브
- WAL/아카이브 로그 보관 정책 검토
- 확장
- EBS/PD/Managed Disk 확장 → 파일시스템 온라인 확장
- 읽기 전용 데이터는 외부 오브젝트 스토리지로 오프로딩
- 장기
- 파티셔닝 전략 도입, TTL/ILM으로 자동 아카이빙
- 모니터링에 테이블/인덱스 상위 성장률 대시보드 추가
시나리오 4: inode 고갈로 쓰기 실패
- 확인
df -i
- 원인 탐지
sudo find / -xdev -type f -printf '.' | wc -c
sudo find /var/app/tmp -xdev -type f -size -1M | wc -l
- 조치
- 임시 파일 폴더 정리, 애플리케이션의 temp 파일 만료 로직 강화
- 작은 파일을 주기적으로 tar/zip으로 묶어 보관
- 장기적으로 파일시스템/스토리지 설계 재검토
대시보드와 알림: 실무에서 바로 쓰는 예시
Grafana 패널 아이디어
- Filesystem Usage by Mountpoint: /, /var, /data, /var/lib/docker
- Top Directories by Size: 정적 목록이 아닌 로그 기반 샘플링 또는 에이전트 스크립트 지표화
- Inode Usage Trend
- Predict Time-to-Full: 90%/95% 도달 예상 시간
- Kubernetes Node/Pod Ephemeral Storage Usage
Prometheus 룰 예시
groups:
- name: disk.rules
rules:
- alert: DiskWillFillSoon
expr: |
(node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / 1024^3) < 20
or
predict_linear(node_filesystem_free_bytes{fstype!~"tmpfs|overlay"}[6h], 24*3600) < 0
for: 15m
labels:
severity: warning
annotations:
summary: "Disk nearing capacity on {{ $labels.instance }}:{{ $labels.mountpoint }}"
description: "Less than 20GB free or predicted to fill within 24h."
- alert: InodeUsageHigh
expr: (node_filesystem_files_free / node_filesystem_files) < 0.1
for: 15m
labels:
severity: critical
annotations:
summary: "Inode usage >90% on {{ $labels.instance }}:{{ $labels.mountpoint }}"
유용한 원라이너 모음
- 상위 10개 대용량 디렉터리(한 파일시스템 기준)
du -x --max-depth=1 / | sort -hr | head -10
- 7일 이상 된 압축 로그 제거
find /var/log -type f -name "*.gz" -mtime +7 -delete
- 최근 24시간 생성된 100MB 이상 파일 나열
find / -xdev -type f -size +100M -mtime -1 -printf "%TY-%Tm-%Td %TH:%TM %s %p\n" 2>/dev/null | sort -nr
- 열린 상태의 삭제된 파일 크기 합계
lsof +L1 | awk '{sum+=$7} END {print sum/1024/1024 " MB"}'
사전 체크리스트: 배포 전과 운영 중
배포 전
- 마운트 설계: OS(/), 로그(/var), 컨테이너(/var/lib/docker), 데이터(/data) 분리
- 파일시스템 선택: XFS(온라인 확장 용이), ZFS(압축/스냅샷/검증), ext4(안정성)
- LVM 도입 여부: 향후 유연한 확장 고려
- 모니터링/경보: 필수 지표/대시보드/예측 설정
- 백업/스냅샷 전략: 보관 기간과 비용 검토, 자동 삭제 정책
운영 중
- 월간 용량 리뷰: 상위 소비자, 성장률, 3개월 예측
- 자동 청소 작업 확인: 실패 알림 연계
- 장애 리허설: 유령 파일, inode 고갈, Docker 팽창 시나리오 대응 훈련
- 변경관리: 로그 레벨 상향, 신규 기능 롤아웃 시 용량 임팩트 사전 평가
사고 후
- RCA: 무엇이 얼마나, 왜 늘었는가(로그 레벨, 트래픽 급증, 배치 오류 등)
- 재발 방지: 정책/자동화/모니터링 룰 업데이트
- 확장 정책 반영: 스토리지 클래스/쿼터/ILM/아카이빙
비용과 성능의 균형: 단순 확장만이 해답은 아니다
- 저장소 유형 선택: 고성능(SSD) vs. 대용량(HDD) vs. 오브젝트 스토리지
- 성능 메트릭(I/O 대기, IOPS, 처리량)을 용량 모니터와 함께 본다
- 압축/디듀플은 CPU와의 트레이드오프. 로그/백업에는 효과적, 고TPS DB에는 신중
- 클라우드 스토리지는 용량뿐 아니라 IOPS/스루풋도 과금 요소. 볼륨 타입과 크기를 함께 설계
마이그레이션 팁: 데이터 디렉터리를 안전하게 이동하기
예: /var/lib/docker를 별도 디스크(/dev/nvme1n1, /docker)로 이동
- 서비스 중단(유지보수 창 확보)
sudo systemctl stop docker
- 데이터 복사
sudo rsync -aHAX --numeric-ids /var/lib/docker/ /docker/
- 마운트 스왑
- /etc/fstab에 /docker를 /var/lib/docker에 바인드 마운트
/docker /var/lib/docker none bind 0 0
- 서비스 재시작
sudo systemctl start docker
- 검증 후 기존 데이터 정리
비슷한 절차로 /var/lib/containerd, DB 데이터 디렉터리 등도 안전하게 분리할 수 있습니다.
보안 관점도 잊지 말자
- 임시 정리 스크립트가 민감 데이터를 실수로 삭제하지 않도록 경로 화이트리스트/드라이런(run) 제공
- 로그/백업 압축 시 암호화 적용(예: at-rest encryption, KMS)
- 스냅샷과 오브젝트 스토리지의 접근 제어/IAM 최소 권한
- 파티션 마운트 옵션(nodev,nosuid,noexec)로 리스크 최소화
결론: 모니터링으로 예측하고, 스케일링으로 해소하며, 정책으로 고착화하라
디스크 공간 부족 문제는 “언젠가”가 아니라 “언제” 발생하느냐의 차이입니다. 다음을 바로 실천해 보세요.
- 예측 기반 경보와 대시보드 구축(node_exporter + Grafana + predict_linear)
- 응급 플레이북 마련(df/du/lsof/logrotate/journalctl/Docker prune)
- 빠른 확장 경로 확보(LVM, 클라우드 볼륨 온라인 확장, PVC 리사이즈)
- 로그/캐시/스냅샷 수명주기 정책과 자동 청소
- 데이터 계층화와 오프로딩(오브젝트 스토리지, CDN)
- 정기 용량 리뷰와 RCA 기반 지속 개선
이 6가지만 체계화해도 디스크 관련 장애의 80%는 사전에 차단할 수 있습니다. 나머지 20%는 잘 준비된 플레이북과 자동화가 해결합니다. 오늘 바로 대시보드와 플레이북부터 점검해 보세요.