로그별 소유자·쓰기 프로세스·일평균 및 최대 증가량 측정값
운영체제 · 구성 레시피
logrotate·journald 용량 제한 구성
파일 로그와 systemd journal의 실제 사용량을 먼저 측정하고, 애플리케이션의 로그 재열기 방식과 보존 정책을 확인한 뒤 점진적으로 용량 상한을 적용합니다.BEFORE YOU START
시작 전에 준비하세요
보안·감사·개인정보 보존 기간과 외부 수집 여부
애플리케이션이 지원하는 로그 reopen 또는 systemd ExecReload 방식
sudo 권한과 설정 변경 전 백업·복구 시간
권장 대상 로그로 인한 디스크 고갈을 예방하면서 장애 분석에 필요한 보존 기간을 유지하려는 서버 운영자
FOLLOW THE RECIPE
8단계 구성·점검 레시피
로그 저장 방식과 파일시스템 확인
journal이 persistent인지 volatile인지, 애플리케이션이 파일과 journal 중 어디에 기록하는지 먼저 확인합니다. 같은 로그를 이중 보관하는지도 찾습니다.
cat /etc/os-release
systemd --versionls -ld /var/log/journal /run/log/journal
systemd-analyze cat-config systemd/journald.confdf -hT /var /var/logsystemctl status logrotate.timer --no-pager
logrotate --version- persistent journal과 runtime journal 중 실제 사용 경로를 확인했다.
- 파일 로그와 journal 중 중복 수집 여부를 확인했다.
- 로그 파티션의 총량과 반드시 남겨야 할 여유 공간을 정했다.
SystemMaxUse는 /var/log/journal이 사용될 때, RuntimeMaxUse는 /run/log/journal에 적용됩니다. 실제 저장 모드에 맞는 값을 설정합니다.
현재 사용량·증가량·열린 파일과 기존 회전 정책을 측정합니다.
실제 사용량과 기존 정책 측정
상한값을 추측하지 않고 현재 디스크 사용량, journal 사용량, 큰 파일, 기존 logrotate 상태를 읽기 전용으로 조사합니다.
journalctl --disk-usagesudo du -x -h --max-depth=1 /var/log | sort -hsudo find /var/log/myapp -maxdepth 1 -type f -name '*.log' -printf '%s %TY-%Tm-%Td %TH:%TM %p\n' | sort -n
sudo lsof /var/log/myappsudo grep -R -n -E '/var/log/myapp|SystemMaxUse|RuntimeMaxUse|MaxRetentionSec' /etc/logrotate.conf /etc/logrotate.d /etc/systemd/journald.conf /etc/systemd/journald.conf.d- 정상일과 장애일의 로그 증가량을 구분했다.
- 파일을 계속 열고 쓰는 프로세스와 공식 reopen 방식을 확인했다.
- 기존 정책의 보존 개수·압축·소유권을 기록했다.
디스크가 이미 임계 상태면 설정 변경과 별개로 디스크 풀 장애 가이드에 따라 큰 파일의 소유 프로세스를 먼저 확인합니다.
필요한 배포판 패키지를 설치하고 timer 상태를 확인합니다.
logrotate 패키지와 timer 준비
배포판 기본 logrotate를 사용합니다. Ubuntu와 Rocky 명령 중 현재 배포판에 맞는 한 분기만 실행합니다.
sudo apt updateapt-get --simulate install logrotatesudo apt-get install logrotatesudo dnf info logrotatesudo dnf install logrotatesystemctl cat logrotate.timer
systemctl list-timers logrotate.timer- 현재 배포판에 맞는 설치 분기만 사용했다.
- logrotate.service와 timer의 배포판 기본 구성을 확인했다.
- 별도 cron과 timer가 중복 실행하지 않는다.
timer와 cron이 둘 다 있으면 중복 회전 가능성을 확인하고 배포판 기본 스케줄 하나만 사용합니다.
기존 파일을 백업하고 애플리케이션·journal 제한을 작성합니다.
회전 정책과 journal drop-in 작성
보존 개수와 크기는 측정값·감사 요구사항에서 정합니다. 애플리케이션이 systemd reload로 로그를 다시 여는 것이 검증된 경우에만 postrotate를 사용합니다.
date -u +%Y%m%dT%H%M%SZsudo cp --preserve=all --no-clobber /etc/logrotate.d/myapp /etc/logrotate.d/myapp.<BACKUP_SUFFIX>.bak기존 파일이 있을 때만 실행합니다.sudo install -d -m 0755 -o root -g root /etc/systemd/journald.conf.dsudo cp --preserve=all --no-clobber /etc/systemd/journald.conf.d/60-storage-limits.conf /etc/systemd/journald.conf.d/60-storage-limits.conf.<BACKUP_SUFFIX>.bak기존 파일이 있을 때만 실행합니다.sudoedit /etc/logrotate.d/myappsudoedit /etc/systemd/journald.conf.d/60-storage-limits.conf/var/log/myapp/*.log {
daily
rotate 14
maxsize 100M
compress
delaycompress
missingok
notifempty
su appsvc adm
create 0640 appsvc adm
sharedscripts
postrotate
/bin/systemctl reload myapp.service
endscript
}myapp.service의 CanReload=yes와 공식 로그 reopen 동작을 먼저 확인합니다. 지원하지 않으면 이 postrotate를 그대로 쓰지 말고 애플리케이션 공식 reopen 방법을 검토합니다. copytruncate는 일부 로그가 유실될 수 있어 기본값으로 사용하지 않습니다.[Journal]
SystemMaxUse=<PERSISTENT_MAX_USE>
SystemKeepFree=<PERSISTENT_KEEP_FREE>
RuntimeMaxUse=<RUNTIME_MAX_USE>
RuntimeKeepFree=<RUNTIME_KEEP_FREE>
MaxRetentionSec=<RETENTION_PERIOD>예: 1G, 2G, 256M, 512M, 30day. 실제 파티션 크기·장애 분석 기간에 맞춰 정하고 KeepFree를 운영 여유 공간보다 작게 잡지 않습니다.- 보존량은 실제 증가량과 감사 기간에서 계산했다.
- postrotate reload가 앱의 공식 로그 reopen 동작임을 확인했다.
- create와 su의 사용자·그룹이 실제 로그 작성자와 맞다.
- System·Runtime 상한과 KeepFree를 모두 설정했다.
maxsize는 logrotate가 실행될 때만 평가되는 조기 회전 조건이며 실행 사이의 실시간 용량 상한이 아닙니다. 급격한 증가를 즉시 제한해야 하면 애플리케이션 자체 회전 또는 별도로 검증한 고빈도 timer를 설계합니다.
강제 회전 없이 debug 검사하고 journal 유효 구성을 확인합니다.
debug 검사 후 정상 스케줄로 반영
첫 검증에서 강제 회전 옵션을 사용하지 않습니다. 강제 회전은 보존 파일과 postrotate를 즉시 실행해 서비스에 영향을 줄 수 있습니다.
sudo logrotate --debug /etc/logrotate.d/myappdebug 모드는 상태 파일을 갱신하거나 실제 회전을 수행하지 않습니다.systemd-analyze cat-config systemd/journald.confsudo systemctl restart systemd-journald.servicesudo systemctl enable --now logrotate.timersystemctl status logrotate.timer systemd-journald.service --no-pager
sudo journalctl -u logrotate.service -n 80 --no-pager- logrotate debug에 문법·소유권 오류가 없다.
- 강제 회전을 실행하지 않았다.
- cat-config에서 자리표시자를 바꾼 실제 제한값을 확인했다.
- journal 재시작 후 현재 SSH와 서비스 로그가 계속 기록된다.
debug 성공은 애플리케이션 reopen 성공을 보장하지 않습니다. 다음 정상 회전 때 열린 파일과 로그 연속성을 확인합니다.
다음 정상 timer 실행 후 파일·journal 사용량과 로그 연속성을 검증합니다.
정상 회전과 사용량 추세 검증
스케줄에 따른 실제 회전 후 새 로그가 기록되고 애플리케이션이 오래된 inode를 계속 잡지 않는지 확인합니다.
systemctl list-timers logrotate.timersudo find /var/log/myapp -maxdepth 1 -type f -printf '%M %u:%g %s %TY-%Tm-%Td %TH:%TM %p\n' | sortsudo lsof +L1 /var/log/myappjournalctl --disk-usage
sudo journalctl --verifysudo journalctl -u myapp.service --since '-30 minutes' --no-pager- 회전 뒤 새 로그에 계속 기록되고 소유권이 맞다.
- 애플리케이션이 삭제되거나 오래된 로그 inode를 계속 잡지 않는다.
- journal 파일 검증에 손상이 없다.
- 일주일 이상 사용량 추세가 정한 상한과 보존 요구를 만족한다.
SystemMaxUse 변경은 기존 활성 journal을 즉시 목표값 아래로 줄이지 않을 수 있습니다. archived 파일만 정리된다는 동작을 고려해 추세를 봅니다.
민감 로그·권한·외부 수집·강제 작업 절차를 점검합니다.
로그 권한과 보존 정책 최종 점검
로그에는 토큰·쿠키·개인정보가 남을 수 있습니다. 용량만 제한하지 말고 수집 항목·권한·보존·외부 반출을 함께 검토합니다.
sudo stat -c '%U:%G %a %n' /etc/logrotate.d/myapp /etc/systemd/journald.conf.d/60-storage-limits.confsudo find /var/log/myapp -maxdepth 1 -type f -printf '%M %u:%g %p\n'systemctl --failed --no-pager
sudo journalctl -u logrotate.service -p warning --no-pager- 로그에 인증정보·세션·원문 개인정보를 기록하지 않는다.
- 파일은 필요한 운영 그룹만 읽을 수 있다.
- 보존 기간과 외부 수집 정책이 조직 규정과 맞다.
- 강제 회전·vacuum은 승인된 유지보수 절차에서만 수행한다.
- 로그 상한이 사고 조사 기간을 과도하게 줄이지 않는다.
용량 급증 원인이 민감정보 반복 출력이라면 상한 조정보다 애플리케이션 로깅 자체를 먼저 수정합니다.
문제 시 신규 정책만 비활성화하고 이전 설정을 검증해 복원합니다.
회전·journal 정책 원복
이미 회전된 로그를 합치거나 삭제하지 않습니다. 정책 파일만 보존·복원하고 로그 연속성과 journal 기록을 다시 확인합니다.
journalctl --disk-usage
systemctl status logrotate.timer systemd-journald.service --no-pagersudo mv /etc/logrotate.d/myapp /etc/logrotate.d/myapp.disabled.<ROLLBACK_SUFFIX>sudo cp --preserve=all /etc/logrotate.d/myapp.<BACKUP_SUFFIX>.bak /etc/logrotate.d/myapp && sudo logrotate --debug /etc/logrotate.d/myapp작업 전 실제 백업이 있었던 경우에만 실행합니다.sudo mv /etc/systemd/journald.conf.d/60-storage-limits.conf /etc/systemd/journald.conf.d/60-storage-limits.conf.disabled.<ROLLBACK_SUFFIX>sudo cp --preserve=all /etc/systemd/journald.conf.d/60-storage-limits.conf.<BACKUP_SUFFIX>.bak /etc/systemd/journald.conf.d/60-storage-limits.conf작업 전 실제 백업이 있었던 경우에만 실행합니다.sudo systemctl restart systemd-journald.service && journalctl --disk-usagesudo journalctl -u myapp.service --since '-10 minutes' --no-pager
sudo lsof /var/log/myapp- 정책만 원복하고 회전된 로그를 삭제·합치지 않았다.
- 실제 백업이 있었던 파일만 복원했다.
- 복원한 logrotate 정책을 debug 검사했다.
- journal과 애플리케이션 로그가 계속 기록된다.
원복 후에도 디스크가 증가하면 정책 문제가 아니라 로그 생성량·열린 삭제 파일·다른 디렉터리를 조사합니다.
로그 소유 프로세스와 증가 원인을 분리해 보존 정책을 다시 산정합니다.
SECURITY CHECK
운영 전 마지막 보안 점검
- 실제 사용량과 증가량을 측정한 뒤 상한을 정한다.
- 애플리케이션의 공식 reopen 방식을 확인하고 copytruncate를 기본 사용하지 않는다.
- 첫 시험에서 강제 회전이나 journal vacuum을 실행하지 않는다.
- 로그 파일 권한과 민감정보 마스킹을 함께 점검한다.
- SystemMaxUse와 KeepFree를 함께 사용해 디스크 여유를 보존한다.
COMMON ERRORS
자주 막히는 지점
회전 후 애플리케이션 로그가 멈춤
- 증상
- 새 파일은 생겼지만 기록이 없거나 서비스가 종료됐습니다.
- 가능한 원인
- 서비스가 reload를 지원하지 않거나 로그 파일 reopen 방식이 다를 수 있습니다.
- 확인 순서
- 공식 reopen 신호·ExecReload를 확인하고 이전 정책을 복원합니다. 강제 회전을 반복하지 않습니다.
제한값을 낮춰도 journal 사용량이 즉시 줄지 않음
- 증상
- journalctl --disk-usage가 설정값보다 크게 보입니다.
- 가능한 원인
- journald는 활성 파일을 즉시 제거하지 않고 archived 파일을 기준으로 정리합니다.
- 확인 순서
- 새 제한 적용과 정상 회전을 확인하고, 긴급 vacuum은 보존 승인 후 별도 절차로 수행합니다.
회전했는데 디스크 공간이 반환되지 않음
- 증상
- 파일은 사라졌지만 df 사용량이 그대로입니다.
- 가능한 원인
- 프로세스가 삭제된 로그 inode를 계속 열고 있을 수 있습니다.
- 확인 순서
- lsof +L1으로 소유 프로세스를 찾고 공식 reopen 또는 안전한 reload를 수행합니다.
PRIMARY REFERENCES
공식 문서
설치 저장소와 지원 버전은 바뀔 수 있습니다. 검토일 이후에는 링크된 공식 문서와 현재 서버의 패키지 후보 버전을 함께 확인하세요.