본문 바로가기
서버 인프라 실무

로그 보존 자동화: logrotate + systemd-journald로 용량·보존·압축 완전 정복(Ubuntu 24.04)

by yamoojin83 2025. 10. 24.

로그 보존 자동화: logrotate + systemd-journald로 용량·보존·압축 완전 정복(Ubuntu 24.04)

서버가 오래 버티는 비결은 로그 관리입니다. 로그가 무한 증가하면 디스크가 가득 차 서비스가 중단되고, 반대로 너무 공격적으로 지우면 장애 원인을 찾을 수 없습니다. 이 글은 Ubuntu 24.04 기준으로 logrotatesystemd-journald를 조합해 용량 제어·보존 정책·압축·서비스 연동까지 실전 운영 패턴을 정리합니다.


1) 큰 그림: 텍스트 로그 vs 저널 로그

  • 텍스트 로그(예: /var/log/nginx/access.log, app.log): logrotate가 주기적으로 파일을 순환(rotate)·압축·삭제.
  • 저널 로그(journalctl): systemd-journald가 이진 포맷으로 저장, 보존/용량은 journald.conf에서 제어.
  • 둘을 섞어 쓰는 환경이 많습니다. 프록시/DB는 텍스트 로그, 시스템/서비스 표준 출력은 저널로 수집하는 식입니다.

2) logrotate 기본기(동작 원리)

man logrotate
cat /etc/logrotate.conf
ls /etc/logrotate.d/
  • /etc/logrotate.conf: 전역 기본값(주기/압축/보관 개수 등)
  • /etc/logrotate.d/*: 서비스별 규칙 파일(Nginx, rsyslog, 커스텀 등)
  • 크론/타이머로 하루 한 번 실행 → 조건에 맞으면 로테이션 수행
# 전역 기본(예시): /etc/logrotate.conf
weekly
rotate 12
create
compress
delaycompress
include /etc/logrotate.d

용어:

  • rotate N: 과거 파일 N개 보관(.1, .2.gz …)
  • daily/weekly/monthly 또는 size 100M: 회전 조건(시간/크기)
  • compress/delaycompress: gzip 압축(바로/다음 회전 시)
  • copytruncate vs postrotate/sharedscripts: 파일 핸들 재오픈 전략(아래 5장)

3) Nginx 예시: 트래픽 많은 서비스의 정석

# /etc/logrotate.d/nginx (권장 템플릿)
 /var/log/nginx/*.log {
     daily                  # 매일
     missingok
     rotate 14              # 2주 보관
     compress
     delaycompress
     notifempty
     create 0640 www-data adm
     sharedscripts
     postrotate
         test -f /var/run/nginx.pid && kill -USR1 $(cat /var/run/nginx.pid)
     endscript
 }

Nginx는 SIGUSR1을 보내면 파일 핸들을 새로 열어 이어서 씁니다. copytruncate보다 안전/정합성이 좋아 postrotate + USR1 방식을 권장합니다.


4) 스프링부트 앱 로그(파일로 남기는 경우)

Logback 등으로 파일 출력(app.log)을 쓰는 경우:

# /etc/logrotate.d/myapp
/var/log/myapp/app.log {
    daily
    rotate 10
    size 50M               # 크기 조건도 병행
    missingok
    compress
    delaycompress
    notifempty
    create 0640 app app
    sharedscripts
    postrotate
        # systemd 서비스 재시작 아님! 로그 핸들만 reopen 하도록 신호를 주는 스크립트가 있으면 최상
        # 없으면 copytruncate 대안(아래 5장) 고려
    endscript
}

대안 A: 파일 대신 표준 출력에 로그를 쓰고 systemd가 저널로 수집하도록 하면 파일 핸들 문제에서 해방됩니다(아래 7장).


5) copytruncate가 필요한 경우(차선책)

애플리케이션이 로그 핸들 재오픈을 지원하지 않으면 회전 시 파일 이름만 바뀌고 새 로그가 구파일로 계속 쓰이는 문제가 생깁니다. 이때 copytruncate현재 파일을 복사해 백업을 만들고, 원본을 0바이트로 잘라 이어 쓰게 만듭니다.

/var/log/myapp/app.log {
    daily
    rotate 7
    size 100M
    compress
    delaycompress
    copytruncate     # <-- 차선책
    notifempty
    missingok
}

주의: 회전 타이밍에 몇 줄 손실 위험이 있습니다. 가능하면 postrotate로 핸들 reopen을 지원하도록 애플리케이션을 조정하세요.


6) 사이즈 기반 회전 + 시간 혼합

버스트 트래픽 환경에서는 날짜만 믿지 말고 size 조건을 함께 쓰는 게 안전합니다.

/var/log/app/*.log {
    daily
    size 200M
    rotate 14
    compress
    delaycompress
    notifempty
    missingok
}

7) 저널(journald) 보존/용량 정책

systemd 서비스(ExecStart 앱)가 표준 출력/에러로 쓰는 로그는 journald가 수집합니다. 디스크에 영구 저장하려면 아래처럼 설정하세요.

# 영구화: 재부팅 후에도 보존
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
# /etc/systemd/journald.conf (핵심 발췌)
[Journal]
Storage=persistent
SystemMaxUse=2G           # 총 사용 상한
SystemMaxFileSize=200M    # 파일 단위 상한
MaxRetentionSec=30day     # 보존 기간
Compress=yes

확인:

journalctl --disk-usage
journalctl -u myapp.service --since "1 hour ago"

: 텍스트 파일로 남기던 애플리케이션 로그를 표준 출력으로 전환해 journald로 일원화하면, logrotate 규칙을 크게 줄일 수 있습니다.


8) systemd 서비스와 로그 전략 일원화

# /etc/systemd/system/myapp.service
[Unit]
Description=My Spring Boot App
After=network.target

[Service]
User=app
Group=app
WorkingDirectory=/srv/myapp
ExecStart=/usr/bin/java -jar app.jar --spring.profiles.active=prod
Restart=on-failure
# 로그는 표준 출력으로 → journald가 수집
StandardOutput=journal
StandardError=journal

# 리소스 제한(옵션)
MemoryMax=1G
CPUQuota=150%

[Install]
WantedBy=multi-user.target

이렇게 하면 journalctl -u myapp로 통합 조회가 가능하며, 보존/압축/용량은 journald.conf에서 제어합니다.


9) 수집·보관·검색: 외부로 보내기

  • 텍스트 로그: logrotate로 용량 관리 + Promtail/Filebeat로 중앙 수집
  • 저널 로그: promtailsystemd-journal 입력을 직접 읽어 Loki 등으로 전송
# Promtail 예시 스니펫
scrape_configs:
- job_name: systemd-journal
  journal:
    json: false
    path: /var/log/journal
  relabel_configs:
  - source_labels: ['__journal__systemd_unit']
    target_label: 'unit'

10) 운영 점검 루틴

# logrotate 강제 실행(테스트)
sudo logrotate -d /etc/logrotate.conf   # dry-run
sudo logrotate -f /etc/logrotate.conf   # 강제 회전

# 마지막 실행 로그(우분투 기본)
sudo cat /var/lib/logrotate/status | tail

# 저널 용량
journalctl --disk-usage

# 특정 서비스 최근 에러
journalctl -u nginx -p 3 -n 50 --no-pager

11) 흔한 함정과 해결

  • 회전했는데 파일 크기가 계속 증가 → 앱이 여전히 구파일 핸들에 쓰는 중. postrotate로 reopen 신호(예: Nginx USR1). 미지원 앱은 copytruncate 고려.
  • 압축이 안 된다compress/delaycompress 확인. 바로 압축하면 다음 회전까지 tail이 불편할 수 있어 delaycompress 권장.
  • 저널이 디스크를 가득 채움SystemMaxUse, MaxRetentionSec 설정 후 systemctl restart systemd-journald.
  • 중앙 수집 중복 → 같은 로그를 파일/저널 둘 다 수집하지 않게 경로·입력을 정리.

12) 최종 체크리스트

  • Nginx/DB/애플리케이션 로그에 logrotate 규칙 존재(시간+사이즈 혼합, 압축, 보관 수)
  • 재오픈 지원 서비스는 postrotate 신호, 미지원은 copytruncate로 차선
  • 저널은 /var/log/journal 영구화 + SystemMaxUse/MaxRetentionSec 설정
  • 중앙 수집 경로 일원화(Promtail/Filebeat), 중복 수집 제거
  • 정기 점검: logrotate --debug, journalctl --disk-usage, 알람 임계치 설정

이 구성을 적용하면 “로그가 디스크를 먹어치우는 문제”와 “필요한 순간 로그가 없는 문제”를 동시에 피할 수 있습니다. 다음 글에서는 Nginx 리버스 프록시 + Spring Boot 조합에서 CORS, 타임아웃, 업로드 제한을 운영 친화적으로 맞추는 실전 설정을 다룹니다.