df 는 파티션 단위, du 는 폴더 단위입니다. df 로 어느 파티션이 찼는지 보고 du 로 그 안에서 범인을 좁힙니다.
df -h # 파티션별 사용률, Use% 열
du -sh /var/log /opt/myapp/logs # 폴더 합계
du -ah /opt/myapp/logs | sort -rh | head -n 10 # 큰 파일·폴더 상위 10du -x 를 붙이면 다른 파티션으로 넘어가지 않아 / 에서 시작해도 빠릅니다. sort -rh 는 K·M·G 단위를 이해하고 내림차순 정렬합니다.
find 의 -size 와 -mtime 이 정리의 핵심 조건입니다. 삭제 전에 반드시 -print 로 목록을 눈으로 봅니다.
| 조건 | 뜻 |
|---|---|
-size +100M |
100MB 초과 |
-mtime +30 |
수정한 지 30일 넘음 |
-mtime -1 |
24시간 안에 수정 |
-name '*.log' |
이름 패턴 |
! -name '*.gz' |
패턴 제외 |
-mtime +30 은 "31일 이상" 입니다. 하루 단위로 내림하므로 경계가 하루 어긋날 수 있고, 정확한 시간이 필요하면 -mmin 을 씁니다.
찾은 파일을 처리하는 세 가지 동작입니다. 어느 것을 쓸지는 파일이 지금 열려 있는지에 달렸습니다.
find logs -name 'app.*.log' -mtime +30 -delete # 삭제
find logs -name 'app.*.log' -mtime +7 ! -name '*.gz' -exec gzip {} \; # 압축
: > logs/catalina.out # 열린 파일 비우기gzip 은 원본을 .gz 로 바꾸고 원본을 지웁니다. 압축된 로그는 zcat·zgrep 으로 풀지 않고 읽습니다. 02 레슨의 도구가 그대로 통합니다.
프로세스가 열고 있는 파일을 rm 하면 이름만 사라지고 데이터는 프로세스가 닫을 때까지 남습니다. df 는 그대로이고 du 로는 안 보이는 상태입니다.
lsof +L1 | grep deleted # 삭제됐지만 열린 파일 목록
lsof -p $(pgrep -f app.jar) | grep deleted
: > /proc/PID/fd/N # 그 파일을 비워 공간 회수이래서 열린 로그는 rm 이 아니라 : > 파일 로 비웁니다. 자바 앱을 재시작하면 핸들이 닫혀 공간이 돌아오지만 그건 마지막 수단입니다.
logrotate 는 cron 이 매일 한 번 실행하는 프로그램으로 /etc/logrotate.d/ 의 설정을 읽어 로그를 백업합니다. "백업" 은 파일 이름을 바꾸고 새 파일을 만들고 오래된 것을 압축·삭제하는 것입니다.
| 지시어 | 뜻 |
|---|---|
daily weekly |
백업 주기 |
rotate 14 |
14개 보관 |
maxsize 200M |
주기 전이라도 크기 넘으면 |
compress |
gzip 압축 |
delaycompress |
한 세대 뒤에 압축 |
dateext |
이름에 날짜 붙임 |
missingok |
파일 없어도 에러 안 냄 |
notifempty |
빈 파일은 백업 안 함 |
기본 방식은 파일 이름을 바꾸는 것입니다. 이름이 바뀌어도 자바 프로세스는 옛 파일 핸들에 계속 쓰므로 새 파일이 비어 있는 문제가 생깁니다.
자바 앱의 stdout 이나 catalina.out 처럼 프로세스가 열고 있는 파일은 copytruncate 를 씁니다. 복사한 뒤 원본을 0 으로 비우므로 프로세스는 같은 파일에 계속 씁니다.
/opt/myapp/logs/stdout.log /opt/tomcat/logs/catalina.out {
daily
rotate 14
maxsize 200M
compress
delaycompress
copytruncate
missingok
notifempty
dateext
su myapp myapp
}복사와 비우기 사이에 찍힌 몇 줄은 잃을 수 있지만 stdout 로그에서는 감수합니다. su myapp myapp 은 파일 소유자와 맞춰 권한 경고를 없앱니다.
Spring Boot 의 logback 은 app.2026-09-10.log 처럼 날짜별로 스스로 백업합니다. 이 파일들은 logrotate 가 백업할 필요가 없고 오래된 것을 지우기만 하면 됩니다.
| 로그 | 백업(압축) | 삭제 |
|---|---|---|
app.날짜.log |
logback | logback maxHistory 또는 cron |
stdout.log |
logrotate copytruncate | logrotate rotate |
catalina.out |
logrotate copytruncate | logrotate rotate |
.hprof 덤프 |
없음 | cron find -delete |
logback 의 maxHistory 와 totalSizeCap 을 설정하면 앱이 스스로 정리합니다. 다만 앱이 내려가 있는 동안은 동작하지 않으므로 cron 을 보조로 둡니다.
설정을 만들면 dry run 으로 확인하고, 필요하면 즉시 한 번 백업해 봅니다.
sudo logrotate -d /etc/logrotate.d/myapp # dry run, 무엇을 할지만 출력
sudo logrotate -f /etc/logrotate.d/myapp # 강제로 지금 한 번 백업
cat /var/lib/logrotate/logrotate.status # 마지막 백업 시각 기록-d 출력에 rotating pattern 과 log does not need rotating 이 보이면 설정이 읽힌 것입니다. 이 레슨은 실행 환경이 없어 파일 문법만 검토했고, 서버에서 -d 로 검사합니다.
cron 은 다섯 칸으로 시각을 정합니다. 분, 시, 일, 월, 요일 순서입니다.
| 표현식 | 뜻 |
|---|---|
0 3 * * * |
매일 03:00 |
*/10 * * * * |
10분마다 |
0 9 * * 1-5 |
평일 09:00 |
30 1 1 * * |
매월 1일 01:30 |
0 */6 * * * |
6시간마다 |
요일은 0 과 7 이 일요일입니다. */N 은 N 간격, 1-5 는 범위, 1,15 는 나열입니다.
사용자 단위 예약은 crontab -e, 시스템 단위는 /etc/cron.d/파일 입니다. cron.d 형식은 명령 앞에 실행 사용자 칸이 하나 더 있습니다.
crontab -l # 내 예약 목록
crontab -e # 편집
sudo cat /etc/cron.d/myapp-cleanup # 시스템 예약 파일운영 서버는 cron.d 파일을 권장합니다. 배포 스크립트로 복사할 수 있고 git 에 남으며 어느 계정으로 도는지 파일에 적혀 있습니다.
cron 은 로그인 셸이 아니라 PATH 가 짧고 .bashrc 를 읽지 않습니다. 터미널에서 되던 명령이 cron 에서는 "command not found" 로 실패하는 이유입니다.
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=""
10 3 * * * myapp find /opt/myapp/logs -name 'app.*.log*' -mtime +30 -delete >> /opt/myapp/logs/cleanup.log 2>&1파일 위에 PATH 를 적고, 명령은 절대 경로를 쓰고, 출력을 파일로 남깁니다. MAILTO="" 는 출력을 메일로 보내려다 쌓이는 것을 막습니다. % 는 cron 에서 줄바꿈 뜻이라 date +\%F 처럼 이스케이프합니다.
파일 수가 너무 많아도 디스크는 찹니다. df -h 는 여유가 있는데 파일을 못 만들면 inode 가 찬 것입니다.
df -i # IUse% 열
find /tmp -type f -mtime +7 -delete # 오래된 임시 파일
find /opt/myapp/logs -type f | wc -l자바 앱이 /tmp 에 작은 파일을 매 요청마다 만들고 안 지우면 몇 달 뒤 inode 가 찹니다. RHEL 은 systemd-tmpfiles 가 /tmp 를 10일 기준으로 정리하지만 앱 폴더는 직접 챙깁니다.