logrotate 설정 오류로 100GB 로그가 생겼을 때 복구 경험 정리

조회수: 1

로그가 100GB가 되었을 때 나타나는 증상

운영 중인 서버에서 로그 파일 하나가 100GB 이상으로 커지면 보통 이런 현상부터 체감하게 된다.

  • 디스크 사용량이 갑자기 100퍼센트에 가까워진다
  • 신규 배포나 패키지 설치가 실패한다
  • 애플리케이션이 파일을 쓰지 못해 에러를 뿜기 시작한다
  • 심하면 데이터베이스도 쓰기 실패로 장애를 일으킨다

이런 상황에서 panic 상태로 서버를 재부팅하는 것은 최악의 선택에 가깝다. 재부팅으로 상황이 나아지지 않을 뿐 아니라, 부팅 과정에서 더 많은 로그를 쓰다 멈춰 버릴 수도 있다.
먼저 해야 할 일은 침착하게 디스크를 차지한 범인을 찾아내고, 서비스에 최소한의 영향을 주는 선에서 공간을 확보하는 것이다.

어떤 로그가 얼마만큼 차지하는지 빠르게 파악하기

가장 먼저 해야 할 일은 진짜 문제를 일으키는 파일을 특정하는 것이다. 무작정 rm을 치기 전에 어느 디렉터리 아래에서 폭발이 일어났는지 확인한다.

파일 크기 순으로 상위 디렉터리 찾기

루트 파일 시스템이 꽉 찼다고 가정하면 다음처럼 점검할 수 있다.

sudo du -xhd1 /

이 명령은 루트 파티션 안에서 상위 디렉터리별 사용량을 보여준다. 보통 var 디렉터리 비율이 비정상적으로 커져 있을 것이다.

그 다음 단계는 로그 디렉터리 내부 점검이다.

sudo du -xhd1 /var/log

여기에서 특정 애플리케이션 디렉터리나 파일 하나가 수십 기가바이트를 먹고 있는 것이 보이면 범인을 찾은 셈이다.

개별 파일 크기 확인

애플리케이션 로그 디렉터리를 찾았다면 ls 옵션으로 파일 크기까지 정렬해 본다.

ls -lhS /var/log/myapp

제일 위에 있는 로그 파일이 바로 100GB의 주인일 가능성이 크다. 이 파일의 이름과 위치를 잘 기억해 두자.

rm을 바로 치지 말고 열린 파일부터 확인하기

많은 사람이 여기에서 바로 rm을 떠올리지만, 로그 파일은 대부분 애플리케이션이 계속 쓰고 있는 상태다. 이때 파일을 지우면 디스크 사용량이 바로 줄지 않을 수 있다.
리눅스에서는 프로세스가 파일을 열고 있으면 실제 데이터는 그대로 남아 있고, 단지 경로 이름만 사라지는 상태가 되기 때문이다.

어떤 프로세스가 로그를 잡고 있는지 확인

lsof 명령을 이용해 해당 파일을 열고 있는 프로세스를 찾는다.

sudo lsof | grep myapp.log

또는 파일 경로를 직접 지정해서 확인할 수 있다.

sudo lsof /var/log/myapp/myapp.log

여기서 프로세스 아이디와 실행 중인 프로세스를 확인해 둔다.
만약 삭제된 파일을 여전히 잡고 있는 프로세스가 있는지 전체적으로 보고 싶다면 다음 명령도 자주 사용한다.

sudo lsof | grep deleted

이미 누군가 로그 파일을 지웠는데도 디스크 사용량이 줄지 않았다면 이런 삭제된 파일 핸들이 남아 있을 확률이 높다.

서비스 중단 없이 로그 파일 비우기

실제 서비스 장애를 최소화하려면 가능하면 애플리케이션을 재시작하지 않고 로그 파일 용량만 비우는 방향을 먼저 고려하게 된다. 이때 안전하게 쓸 수 있는 방법이 몇 가지 있다.

truncate 명령 사용

로그 파일 내용을 모두 지우고 크기를 0으로 만드는 simplest 방법이다.

sudo truncate -s 0 /var/log/myapp/myapp.log

이렇게 하면 파일 자체는 그대로 살아 있고, 파일 핸들을 쥐고 있는 프로세스도 동일한 파일에 계속 쓴다. 이름과 권한이 바뀌지 않기 때문에 애플리케이션 입장에서는 아무 변화가 없다.

빈 파일로 덮어쓰기

환경에 따라 truncate가 없거나 익숙하지 않을 때는 cat과 리다이렉션으로 비울 수도 있다.

sudo sh -c 'cat /dev/null > /var/log/myapp/myapp.log'

마찬가지로 파일의 내용만 없어지고 프로세스는 동일한 파일에 계속 로그를 쓴다.

두 방법 모두 실행 직후 df로 다시 확인하면 디스크 사용량이 눈에 띄게 줄어드는 것을 볼 수 있다.

df -h /

단, 파일 시스템이 즉시 공간을 반환하지 않는 특수한 경우도 있으므로 반드시 사용량 변화를 확인해 봐야 한다.

logrotate 설정을 잘못했을 때 흔한 패턴

로그 폭발이 발생한 뒤에는 왜 logrotate가 제대로 동작하지 않았는지 꼭 짚고 넘어가야 한다. 실제로 자주 보이는 문제 패턴은 대략 다음과 같다.

  • 특정 애플리케이션 전용 logrotate 설정 파일을 만들지 않았다
  • rotate 조건을 size가 아니라 weekly 등으로 설정해두고 트래픽 증가를 반영하지 못했다
  • copytruncate 옵션 없이 postrotate에서 서비스 재시작을 빼먹었다
  • logrotate 자체가 cron이나 systemd timer에 연결돼 있지 않아 아예 실행이 안 되고 있었다

각각을 조금 더 자세히 보면 재발 방지에 도움이 된다.

logrotate 구성 파일 구조 간단 정리

리눅스에서 logrotate 설정은 보통 두 군데에서 관리한다.

  • 전체 기본 설정
    • etc logrotate.conf
  • 개별 서비스 설정
    • etc logrotate.d 아래 파일들

기본 설정 파일 안에서 include 지시어로 logrotate.d 디렉터리를 포함하는 식으로 구성한다.
애플리케이션 로그가 등 var log myapp 경로에 있다면 myapp이라는 이름으로 설정 파일을 하나 만드는 경우가 많다.

크기 기준 회전 설정 예시

실제 운영 환경에서는 기간 기준보다 크기 기준으로 회전시키는 편이 더 안전한 경우가 많다. 예를 들어 일일 트래픽이 크게 출렁이는 웹 서비스라면 하루치 로그가 100메가일 때도 있고 5기가일 때도 있을 수 있기 때문이다.

애플리케이션 로그 회전 예시는 다음처럼 잡을 수 있다.

/var/log/myapp/*.log {
    daily
    size 100M
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}

각 옵션의 의미를 짚어 보면 다음과 같다.

  • daily
    • 최소 하루에 한 번은 회전 후보로 삼는다
  • size 100M
    • 파일 크기가 100메가 이상이면 회전한다
  • rotate 14
    • 최대 14개까지 백업을 남기고 그 이상은 삭제한다
  • compress
    • 회전된 파일을 gzip으로 압축한다
  • delaycompress
    • 막 회전된 가장 최신 로그 하나는 압축하지 않고 다음 회전 때부터 압축한다
  • missingok
    • 파일이 없어도 에러를 내지 않고 넘어간다
  • notifempty
    • 파일이 비어 있으면 회전하지 않는다
  • copytruncate
    • 현재 파일을 복사한 뒤 원본 파일 내용을 0으로 비운다

여기서 copytruncate가 중요하다. 로그 파일을 쓰고 있는 프로세스를 건드리지 않으면서 새 파일을 만들어 회전시키기 위해 쓰는 옵션이다.

copytruncate를 쓸 때와 쓰지 않을 때

copytruncate는 매우 편리하지만 트레이드오프도 있다.

장점

  • 애플리케이션을 재시작하지 않아도 된다
  • 대부분의 상황에서 안전하게 로그 회전이 가능하다

단점

  • 회전하는 순간에 기록되는 몇 줄의 로그가 유실될 수 있다
  • 아주 높은 쓰기 속도의 로그에서는 데이터 일관성 문제가 생길 수 있다

반대로 copytruncate를 쓰지 않을 경우에는 postrotate 블록에서 애플리케이션 로그 핸들을 갱신해 줘야 한다. 예를 들어 웹 서버나 일부 데몬은 로그 파일을 다시 열라는 신호를 보내야 새 파일에 쓰기 시작한다.

대략적인 패턴은 다음과 같다.

postrotate
    systemctl kill -s HUP myapp.service
endscript

각 서비스마다 로그 파일 재오픈 방법이 다르기 때문에, 해당 애플리케이션 문서를 확인해 logrotate와 어떻게 연동하는지 미리 숙지해 두는 것이 좋다.

logrotate가 실제로 동작하는지 확인하는 방법

설정을 변경한 뒤에는 반드시 logrotate 실행 여부를 확인해야 한다.
수동으로 테스트하려면 다음 명령을 사용한다.

sudo logrotate -d /etc/logrotate.conf

d 옵션은 실제 회전은 하지 않고 어떤 동작을 할지 시뮬레이션만 보여준다. 설정이 의도대로 읽히는지 확인하기에 좋다.

실제 회전을 강제로 실행해 보고 싶다면 f 옵션을 함께 쓴다.

sudo logrotate -f /etc/logrotate.conf

실행 후 로그 디렉터리를 보면 log.1 log.2.gz 같은 파일이 생기며 회전이 일어난 것을 확인할 수 있다.

또한 logrotate가 주기적으로 실행되는지 확인하려면

  • cron 기준
    • etc cron.daily 아래 logrotate 스크립트 존재 여부
  • systemd timer 기준
    • systemctl list-timers 명령에서 logrotate 관련 타이머 상태

등을 점검해 보면 된다.

100GB 로그 사건 이후 재발 방지 체크리스트

실제 장애를 한 번 겪고 나면 같은 일이 다시 일어나지 않도록 최소한의 체크리스트를 만들어 두는 것이 좋다. 예를 들어 다음 항목을 정기적으로 확인할 수 있다.

  • 디스크 사용량 경고 알림
    • 특정 파티션이 80퍼센트를 넘으면 알람
  • 대형 파일 모니터링
    • du와 find를 자동화해 일정 크기 이상 파일 리스트를 주기적으로 확인
  • logrotate 설정 점검
    • 새로 추가된 애플리케이션마다 logrotate 설정 파일을 반드시 함께 배포
  • swappiness와 기타 시스템 설정
    • 메모리 부족으로 인해 로그 폭발이 더 크게 체감되는 경우도 많으므로 함께 점검

또한 신규 서비스가 추가될 때 운영 체크리스트에 로그 경로와 logrotate 설정 여부를 포함해 두면 같은 유형의 실수를 크게 줄일 수 있다.

마무리 logrotate와 디스크를 다루는 사고방식

logrotate 설정 실패로 로그가 100GB까지 커지는 경험은 한 번쯤 누구나 겪을 만한 사고다. 이때 중요한 것은

  • 당황해서 rm부터 치지 말고
  • 어느 파일이 얼마나 차지하는지 정확히 확인하고
  • 서비스 중단을 최소화하는 방향으로 공간을 확보한 뒤
  • logrotate 설정과 실행 경로를 재점검하는 것

이다.
단순한 실수처럼 보이지만, 이 과정을 한 번 차분하게 밟아 보면 로그 관리와 디스크 모니터링에 대한 관점이 크게 달라진다. 결국 로그는 장애 분석의 가장 중요한 단서이자 동시에 디스크를 잠식하는 잠재적인 위험 요소다. 운영자는 이 두 얼굴을 모두 이해하고 균형 있게 다루는 기술을 익혀야 한다.