Docker 로그 파일 관리로 해결하는 EC2 스토리지 부족 문제(logrotate)
Resolving EC2 Storage Shortage Issues Through Docker Log File Management (logrotate)
Oct 22, 2024
원인
회사의 특정 서비스는 온 디맨드 인스턴스 위에 올라가 있습니다. 브랜딩 사이트나 내부 프로세스 처리를 위한 간단한 기능들이 모여있는 서비스들이 그렇습니다. 과거에 작성되어 운영되고 있던 이런 사이트들이 레거시 프로젝트로 존재하고 있습니다.
서비스 기획 팀으로부터 특정 프로덕션 환경의 서비스가 실행이 안된다는 연락을 받아, 장애가 발생한 서비스를 확인해 봤습니다.
docker ps로 확인해보니, 정상적으로 실행되고 있어 각 Application의 실행로그를 살펴 봤습니다. 각 애플리케이션의 실행 로그를 살펴본 결과, 레디스 쪽에 문제가 있는 것으로 보였습니다. 레디스 로그를 열어본 결과, 다음과 같은 로그를 확인했습니다.
Failed opening the temp RDB file temp-631.rdb (in server root dir /data) for saving: No space left on device
이 오류 메시지는 Redis 서버가 임시 RDB 파일을 저장하려고 시도했지만, 저장할 공간이 부족하여 실패했다는 것을 나타냅니다. "No space left on device"는 디스크 공간이 부족하다는 의미입니다.
메모리 공간이 부족하다는 문구가 아닌, Disk가 부족하다고 나와서 AWS 공식문서에 나와 있는 Amazon Linux 커맨드인
df -hT /dev/xvda1
를 사용하여 현재 내 루트 경로 EBS 볼륨의 사용량을 확인해봅니다.
Filesystem Type Size Used Avail Use% Mounted on /dev/nvme0n1p1 xfs 8.0G 8.0G 0.0G 100% /
위와 같이 전체 사용량이 100%로 나타났습니다. 인스턴스 스토리지가 모두 사용되고 있는 경우, 몇 가지 원인을 고민해야 합니다.
- 로그 파일이 시간이 지남에 따라 크기 증가한 문제인 지
- Docker 이미지가 남아 있는 지
- 서버 내에서 데이터를 저장하는 코드나 스크립트가 존재하는 지
- 웹 서버 캐시 및 패키지 관리자 문제인 지
첫 번째 사유 먼저 조사하기 위해, 실행중인 서버의 이미지를 확인합니다.
docker inspect <Container Image Name>
실행중인 이미지를 확인하면, 로그 경로를 알 수 있습니다.
"LogPath": "/var/lib/docker/containers/<Container_ID>/<Container_ID>-json.log"
경로를 찾으면 로그 파일의 크기를 확인할 수 있습니다.
du -sh /var/lib/docker/containers/<Container_ID>/<Container_ID>-json.log 3.9G
를 하면, 로그파일의 크기를 알 수 있습니다.
로그 파일의 크기를 확인하면, 3.9GB의 로그 파일이 디스크 공간의 상당 부분을 차지하고 있음을 알 수 있습니다. 인스턴스에 8GB EBS 볼륨이 있고 기본 시스템이 이미 4.1GB를 사용하고 있다면, Docker 로그 파일이 남은 공간을 모두 차지하여 전체 디스크 문제가 발생하는 원인이 됩니다.
해결
1. 로그 파일 truncate
이 문제는 도커 로그 파일을 간단히 비우는 것으로 해결할 수 있습니다.
sudo find /var/lib/docker/containers/ -name '*-json.log' -exec truncate -s 0 {} \; // /var/lib/docker/containers/ 디렉토리 아래에 있는 모든 *-json.log 파일의 크기를 0으로 // 만들어 줍니다.
해당 서버는 3개월 동안 배포가 이루어지지 않아 로그가 쌓여서 발생한 문제일 수 있습니다. 따라서, 일주일 전의 로그만 지우는 방식으로 리눅스의 크론탭을 사용해 스케줄링할 수 있습니다. 그러나 로그를 삭제하면 과거의 특정 날짜의 로그를 확인할 수 없으므로, 이 점도 고려해야 합니다.
sudo crontab -e 0 2 * * * find /var/lib/docker/containers/ -name '*-json.log' -mtime +7 -exec truncate -s 0 {} \;
2. Docker rotate
Docker에서는 로그 파일 관리를 위해 로깅 드라이버를 사용합니다. 기본적으로 docker run 또는 docker-compose up 명령어를 실행하면
json-file
로깅 드라이버가 활성화되며, 이 드라이버는 로그를 /var/lib/docker/containers/<Container_ID>/<Container_ID>-json.log
경로에 기록합니다.json-file
로깅 드라이버는 기본적으로 로그 로테이션을 지원하지 않지만, Docker는 로그 파일의 크기를 관리할 수 있는 옵션을 제공합니다. 로그 로테이션은 Docker 컨테이너에서 생성되는 로그 파일의 크기를 조절하고, 로그 파일이 너무 커지지 않도록 주기적으로 새로운 로그 파일로 교체하는 과정을 의미합니다.이러한 기능을 활용하면 별도의 스케줄링 없이도 로그 파일을 효과적으로 관리할 수 있어 예기치 않은 결과를 방지할 수 있습니다. 도커 로테이트는 아래와 같이 사용하여 적용할 수 있습니다.
vi /etc/docker/daemon.json { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }
3. logrotate
하지만, 좀 더 세밀한 설정이 필요할 때는 로그 로테이트 파일의 설정에 따라 로그 데이터의 볼륨을 제한, 압축 등을 통한 로그 파일의 크기를 작게 유지할 수 있도록 도와주는 유틸리티인 linux의 logrotate를 사용할 수 있습니다. 여기서는 Docker rotate가 아닌, logrotate를 사용하여 docker data directory에 containers에 저장된 로그파일을 더 디테일하게 관리하겠습니다.
먼저, Docker root 경로를 확인합니다.
docker info | grep "Docker Root Dir" // Docker Root Dir: /var/lib/docker
Docker 로그를 관리하기 위한 logrotate 설정 파일을 생성하고, 다음 내용을 설정 파일에 추가합니다
sudo vi /etc/logrotate.d/docker // <Docker Root Dir>/containers/*/*.log { rotate 3 size 1G daily compress missingok copytruncate }
logrotate 설정은 아래와 같습니다.
옵션 | 설명 |
rotate [숫자] | 로그파일 개수가 선택한 숫자 이상이면 오래된 로그 파일 삭제 |
daily | 로테이트 실행 주기 옵션yearly(연단위), monthly(월단위), weekly(주단위), daily(일 단위) |
size [숫자 K,M,G] | 로그 파일이 크기가 설정보다 커지면 로테이트 실행 |
create [권한] [유저] [그룹] | 로테이트 될때 생성되는 로그파일 권한 및 소유자 지정 |
notifempty | 로그 내용이 없으면 로테이트를 실행하지 않음 |
ifempty | 로그 내용이 없어도 로테이트를 진행 |
compress | 로테이트로 생성되는 로그파일 gzip으로 압축생성 |
nocompress | 로테이트로 생성되는 로그파일을 압축하지 않고 생성 |
missingok | 로그파일을 발견하지 못해도 에러처리 하지 않음 |
dateext | 로테이트 파일의 이름에 날짜가 들어가도록 생성 |
copytruncate | 복사본 저장 후 원본 로그파일을 빈 파일로 생성 |
- logrotate를 미리 실행해 보기(dry-run)
/usr/sbin/logrotate -vd /etc/logrotate.d/docker
- logrotate를 강제로 실행하기
/usr/sbin/logrotate -vf /etc/logrotate.d/docker
- logrotate를 바로 실행하기
/usr/sbin/logrotate -v /etc/logrotate.d/docker
- logrotate 실행 시간 변경하기(daily 조건이 설정된 경우, 24시간 이전에 실행됐다 하더라도 이미 로테이션 됐다고 하여 수행되지 않는다고 합니다. 그럴 때 logrotate 실행시간을 변경하는 것으로 로테이션을 수행시킬 수 있다고 합니다.)
vi /var/lib/logrotate/logrotate.status /var/lib/docker/containers/<Container_ID>/<Container_ID>-json.log" <날짜 입력>
이제 강제로 logrotate를 실행하고 파일크기를 확인해보면
/usr/sbin/logrotate -vf /etc/logrotate.d/docker du -sh /var/lib/docker/containers/<Container_ID>/<Container_ID>-json.log rotate 3 4k Filesystem Type Size Used Avail Use% Mounted on /dev/nvme0n1p1 xfs 8.0G 5.7G 2.4G 71% / // rotate 2 Filesystem Type Size Used Avail Use% Mounted on /dev/nvme0n1p1 xfs 8.0G 5.2G 2.9G 65% /
rotate에 따라 크기가 줄고 늘어나는 것을 확인할 수 있습니다. 실제 컨테이너 로그로 가보면
<Container_ID>-json.log <Container_ID>-json.log.1.gz <Container_ID>-json.log.2.gz
위 처럼 로그가 압축되 있는 모습을 확인하실 수 있습니다.
운영환경에서 인스턴스 스토리지와 서비스 가용성을 복구하고, 로그 관리의 중요성에 대해서 깨닫게 된 시간이었습니다.
참고한 글
Share article