1. 서론: 새벽 3시의 재앙, No space left on device

리눅스 서버 인프라를 운영하면서 겪는 가장 당혹스럽고 허탈한 장애 원인 중 1위는 단연 **디스크 용량 100% 고갈(Disk Full)**입니다.

웹 서비스 트래픽이 평소보다 조금만 급증해도 Nginx의 access.log나 Tomcat의 catalina.out 파일은 하루에 수 GB에서 수십 GB씩 눈덩이처럼 불어납니다. 디스크가 100% 차는 순간:

  • 데이터베이스(MySQL, PostgreSQL)는 쓰기 작업을 거부하며 즉각 비정상 종료(Crash)됩니다.
  • WAS는 세션 및 임시 파일을 생성하지 못해 500 에러를 뿜어냅니다.
  • 관리자 터미널(SSH) 접속조차 PTY 할당 실패로 막혀버려 긴급 조치조차 어려워집니다.

이러한 참사를 사전에 방지하기 위한 리눅스 표준 솔루션이 바로 **logrotate**입니다. 이번 포스팅에서는 logrotate의 내부 동작 원리(시그널 방식 vs copytruncate), 파일 핸들의 비밀, 서버 3대장(Nginx, Apache, Tomcat)의 프로덕션 설정 템플릿, 그리고 디버깅 검증 기법까지 완벽히 정리합니다.


2. logrotate 동작 메커니즘: 시그널 vs copytruncate

리눅스에서 실행 중인 프로세스는 파일 이름이 아니라 **파일 디스크립터(File Descriptor, Inode)**를 통해 디스크에 로그를 기록합니다. 단순히 mv access.log access.log.bak으로 이름을 바꾸더라도, 프로세스는 이름이 바뀐 백업 파일에 계속해서 로그를 쏟아붓습니다.

logrotate는 이 문제를 해결하기 위해 두 가지 상반된 메커니즘을 제공합니다.

flowchart TD subgraph MethodA ["방식 A: Inode 교체 + 시그널 (Nginx, Apache)"] direction TB A1["1. 기존 access.log -> access.log.1 이름 변경"] A2["2. 빈 access.log 새 파일 생성 (create)"] A3["3. kill -USR1 시그널 전송 -> 프로세스가 새 파일 Inode로 다시 열기(Reopen)"] A1 --> A2 --> A3 end
subgraph MethodB ["방식 B: 내용 복사 + 비우기 (copytruncate - Tomcat catalina.out)"]
    direction TB
    B1["1. 현재 catalina.out 내용을 catalina.out.1로 통째 복사 (Copy)"]
    B2["2. 원본 catalina.out 크기를 0바이트로 절삭 (Truncate)"]
    B3["3. 프로세스는 동일한 Inode에 중단 없이 계속 기록 유지"]
    B1 --> B2 --> B3
end
  • 방식 A (시그널 재오픈): Nginx나 Apache처럼 로그 파일을 다시 열 수 있는 프로세스에 적합하며, 데이터 유실이 전혀 없는 가장 깔끔한 방식입니다.
  • 방식 B (copytruncate): Tomcat의 catalina.out처럼 셸 리다이렉션(>>)으로 열려 있어 시그널을 받을 수 없는 프로세스에 필수적입니다. 단, 복사와 비우기 사이의 찰나의 순간에 쓰인 몇 줄의 로그가 유실될 수 있는 미세한 한계가 있습니다.

3. logrotate 핵심 지시어(Directives) 총정리

/etc/logrotate.d/ 디렉토리에 정의하는 핵심 옵션들의 기능입니다.

지시어 설명 및 동작 실무 팁
daily / weekly 로그 회전 주기 (매일 또는 매주) 트래픽이 많다면 daily 필수
rotate N 회전된 로그 파일을 최대 N개까지 보관 rotate 14 (2주치 보관 후 자동 삭제)
size 100M 주기와 무관하게 파일 크기가 100MB를 넘으면 즉시 순환 대용량 트래픽 서버의 안전장치
compress 회전된 로그 파일을 gzip으로 압축 보관 디스크 사용량을 80~90% 절감
delaycompress 다음 회전 주기까지 압축을 1회 미룸 프로세스가 아직 물고 있는 파일 압축 방지
missingok 대상 로그 파일이 없어도 에러를 내지 않고 패스 불필요한 크론 데몬 에러 알림 방지
notifempty 파일 크기가 0바이트(빈 파일)이면 회전 생략 무의미한 빈 압축 파일 생성 방지
dateext .1, .2 대신 -20260223 형태의 날짜 접미사 사용 날짜별 로그 탐색에 압도적으로 편리
sharedscripts 매치된 로그 파일이 여러 개여도 스크립트를 1번만 실행 postrotate 시그널 중복 전송 방지

4. 서버 3대장별 프로덕션 설정 템플릿

1) Nginx 설정 (/etc/logrotate.d/nginx)

Nginx는 마스터 프로세스에 USR1 시그널을 보내면 다운타임 없이 열려 있는 모든 로그 파일 핸들을 즉시 닫고 새로 생성된 파일로 재연결합니다.

/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    dateext
    dateformat -%Y%m%d
    postrotate
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 $(cat /var/run/nginx.pid)
        fi
    endscript
}

2) Apache HTTP Server 설정 (/etc/logrotate.d/apache2)

Apache는 apachectl graceful을 통해 현재 연결된 클라이언트 세션을 끊지 않고 안전하게 로그를 갱신합니다.

/var/log/apache2/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 0640 root adm
    sharedscripts
    dateext
    dateformat -%Y%m%d
    postrotate
        if /usr/sbin/apachectl configtest > /dev/null 2>&1; then
            /usr/sbin/apachectl graceful > /dev/null 2>&1
        fi
    endscript
}

3) Tomcat WAS 설정 (/etc/logrotate.d/tomcat)

Tomcat의 catalina.out은 JVM 프로세스가 시작될 때 셸 리다이렉션으로 표준 출력(stdout)을 바인딩하므로 프로세스를 재시작하지 않는 한 Inode를 갱신할 수 없습니다. 따라서 **copytruncate**가 절대적 필수입니다.

/opt/tomcat/logs/catalina.out {
    copytruncate
    daily
    size 100M
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    dateext
    dateformat -%Y%m%d
}
  • size 100M 병행: daily 주기라도 갑작스러운 에러 폭풍(스택 트레이스 무한 출력)으로 하루에 10GB씩 쌓이는 것을 막기 위해 100MB 도달 시 즉시 순환하도록 복합 제약 조건을 겁니다.

5. 설정 검증 및 디버깅 명령어

logrotate 설정을 추가하거나 수정한 뒤, 실제로 크론 데몬이 돌기 전에 문법 오류나 권한 문제가 없는지 반드시 테스트해야 합니다.

1) 드라이런(Dry-run) 디버그 모드 (-d)

실제 파일을 삭제하거나 압축하지 않고, 어떤 파일이 어떤 규칙에 의해 회전될지 시뮬레이션 결과만 화면에 출력합니다.

# 디버그 모드 실행 (안전함, 실제 변경 없음)
sudo logrotate -d /etc/logrotate.d/nginx

2) 강제 즉시 실행 테스트 (-vf)

크론 주기와 무관하게 모든 조건을 무시하고 즉시 로그 회전을 1회 강제 실행합니다.

# 상세 출력(-v)과 강제 회전(-f)
sudo logrotate -vf /etc/logrotate.d/tomcat

실행 후 ls -lh /opt/tomcat/logs/를 확인하여 catalina.out의 크기가 0바이트로 초기화되고, catalina.out-20260223 파일이 정상 생성되었는지 확인합니다.


6. 실무 주의사항: 디렉토리 권한 보안 정책

최신 리눅스(Ubuntu 20.04+, RHEL 8+)의 logrotate는 보안 강화를 위해 **로그 대상 디렉토리가 group이나 other에 쓰기 권한(w)이 열려 있으면 실행을 전면 거부(Error: insecure permissions)**합니다.

# 에러 예시:
# error: skipping "/var/log/myapp/app.log" because parent directory has insecure permissions

이 경우 해당 로그 디렉토리의 퍼미션을 소유자 전용 쓰기 권한(chmod 755 또는 chmod 750)으로 조정해야 정상적으로 logrotate가 동작합니다.


7. 결론

로그 파일 관리는 인프라 엔지니어링의 가장 기본적이면서도 가장 소홀해지기 쉬운 영역입니다.

각 웹 서버의 특성에 맞게 Nginx/Apache에는 create + USR1 시그널, Tomcat catalina.out에는 copytruncate + size 100M 규칙을 철저히 적용하여 예측 불가능한 디스크 풀 장애로부터 서비스를 안전하게 지켜내시기 바랍니다.