Profile picture

[Docker] 컨테이너 로깅 - syslog / rsyslog

JaehyoJJAng2023년 04월 10일


컨테이너 내부에서 어떤 상황이 발생하는지 확인하는 것은 디버깅 및 운영 측면에서 매우 중요하다. 애플리케이션 레벨에서 로그가 기록되도록 개발하여 별도의 로깅 서비스를 사용할 수도 있겠지만, 도커는 컨테이너의 표준 출력과 표준 에러 로그를 별도로 메타데이터로 저장하고 있고, 이를 확인하는 명령어 또한 도커에서 제공하고 있다.


로깅 드라이버

1. json-file 로그

기본적으로 컨테이너 로그는 JSON 형태로 도커 내부에 저장된다.
mysql 컨테이너를 생성하여 간단한 로그를 남겨보자.

$ docker run -d -it --name mysql \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:5.7

mysql과 같은 애플리케이션은 포그라운드(foreground)에서 동작하기 때문에 -d옵션을 사용하여 백그라운드 모드로 컨테이너를 생성하는 경우가 많다. 따라서 -d 옵션을 사용하면 애플리케이션이 정상적으로 구동되는지 여부를 알 방법이 없지만 docker logs 명령을 통하여 컨테이너의 표준 출력을 확인해 애플리케이션의 상태를 확인할 수가 있다.

docker logs: 컨테이너 내부에서 출력을 보여주는 커맨드

image

💡 TIP!

  • 로그가 너무 많다면 --tail <숫자> 옵션을 사용하여 마지막 로그부터 출력할 줄의 수를 설정할 수 있음
  • --since 옵션에 유닉스 시간을 입력해 특정 시간 이후의 로그를 확인할 수 있음
  • -t 옵션으로 타임스탬프 표시 가능
  • -f 옵션을 사용하면 로그를 실시간 스트림으로 확인할 수 있음

기본적으로 컨테이너 로그는 JSON 형태로 도커 내부에 저장되는데, 이 JSON 파일은 아래 경로에서 컨테이너의 ID로 시작하는 파일명으로 저장이된다.

$ sudo find /var -name "*json.log" -type f 2>/dev/null -exec sh -c "sudo ls -lh {}" \;
-rw-r----- 1 root root 6.6K  828 16:00 /var/lib/docker/containers/aa2f05b2a188254f1747846e90a7b3772231140dfdf6675acbe93d44f40bee03/aa2f05b2a188254f1747846e90a7b3772231140dfdf6675acbe93d44f40bee03-json.log

하지만 컨테이너 내부의 출력이 너무 많은 상태로 방치하게 되면, JSON 로그 파일의 크기가 너무 커져 호스트의 남은 저장 공간을 전부 사용해 버리는 불상사가 생길 수 있다. 이러한 상황을 방지하기 위해 --log-opt 옵션을 사용하면 컨테이너 JSON 로그 파일의 최대 크기를 지정할 수 있게된다.

$ docker run -d -it --name mysql \
-e MYSQL_ROOT_PASSWORD=secret \
--log-opt max-size=10k --log-opt max-file=3 \
mysql:latest

max-size는 로그 파일의 최대 크기, max-file은 로그 파일의 개수를 의미함.


로그 관련하여 어떠한 설정도 하지 않았다면, 도커는 기본적으로 위와 같은 컨테이너 로그를 JSON 파일로 저장하지만, 그 밖에도 각종 로깅 드라이버를 사용하고 로그를 수집할 수 있다.
대표적인 예로 syslog, journald, fluentd, awslogs 등이 있으며, 애플리케이션의 특징에 적합한 로깅 드라이버를 선택하면 된다.

💡 TIP!

로깅 드라이버는 기본적으로 json-file로 설정되지만, 도커 데몬 시작 옵션에서 --log-driver 옵션을 사용하여, 기본적으로 사용할 로깅 드라이버를 변경할 수 있다. 또한 위에서 살펴본 max-size와 같은 --log-opt 옵션 또한 도커 데몬에 적용함으로써 모든 컨테이너에 일괄적으로 적용이 가능하다


2. syslog

syslog는 유닉스 계열 운영체제에서 로그를 수집하는 오래된 표준 중 하나이다. 커널, 보안 등 시스템과 관련된 로그, 애플리케이션 로그 등 다양한 종류의 로그를 수집해 저장한다.
대부분의 유닉스 계열 운영체제에서는 syslog를 사용하는 인터페이스가 동일하기 때문에 체계적으로 로그를 수집하고 분석할 수 있는 장점이 있다.


다음 커맨드를 사용하여 syslog에 로그를 저장하는 ubuntu 컨테이너를 생성해보자. 컨테이너의 커맨드가 echo syslogtest로 설정되기 때문에, 컨테이너는 생성되면서 syslogtest를 출력하고 종료될 것이다. (-d 옵션을 주었기에 백그라운드로 실행되어 호스트에는 해당 출력문이 보이지 않을 것이다)

$ docker run -d -it --name syslog_container \
--log-driver=syslog \
ubuntu:20.04 \
echo syslogtest

syslog 로깅 드라이버는 기본적으로 로컬호스트의 syslog에 저장하므로 운영체제 및 배포판에 따라 syslog 파일의 위치를 알아야한다. 우분투 14.04 버전의 경우 /var/log/syslog에서 확인 가능하고, 우분투 16.04 이상은 journalctl -u docker.service 커맨드로 확인 가능하다.

현재 필자의 경우 Ubutnu 18.04를 사용 중이므로 journalctl -u docker.service 커맨드를 입력하여 마지막 부분을 보면 syslogtest를 확인할 수 있다

$ journalctl -u docker.service | grep 'syslogtest'
 828 17:12:56 docker-virtual-machine 34ac8bd23589[1261]: syslogtest

위 명령어 말고 Ubuntu에서는 /var/log/syslog 파일에서 로그를 확인해 볼수도 있기는 하다.

$ cat /var/log/syslog | grep 'syslogtest'

Centos는 /var/log/messages 에서 확인 가능하다


3. rsyslog

rsyslog는 리눅스에서 널리 사용되고 있는 로깅 서비스 중 하나이다.

syslog를 원격 서버에 설치하면 로그 옵션을 추가해 로그 정보를 원격 서버로 보낼 수도 있다.

연습하기 위해서는 서버 호스트와 클라이언트 호스트, 두 개의 머신이 필요하다. 아래의 방법으로 테스트 해볼 수 있다.


3.1. 예제

  1. 서버 호스트: 192.168.121.101/24
  2. 클라이언트 호스트: 192.168.121.102/24

두 개의 머신을 준비하도록 하자.


1. 서버호스트에 rsyslog 서비스가 시작되도록 설정된 컨테이너를 생성

ubuntu:20.04 이미지에서 테스트를 해보려고 했으나 rsyslog가 구동조차 하지 않아서
https://github.com/rsyslog/rsyslog-docker/tree/master/appliance/alpine

rsyslog가 설치된 rsyslog/syslog_appliance_alpine 이미지를 다운받아서 컨테이너로 실행하도록 할거다.

$ docker run -d -it --name rsyslog_server \
-p 514:514 -p 514:514/udp \
rsyslog/syslog_appliance_alpine

2. 컨테이너를 빠져나온 뒤 클라이언트 호스트에서 아래의 명령어를 입력하여 컨테이너 생성. 그리고 컨테이너의 로그를 기록하기 위해 간단한 echo 명령어도 실행

$ docker run -d -it --name client_server \
--log-driver=syslog \
--log-opt syslog-address=tcp://192.168.121.128:514 \
--log-opt tag="mylog" \
ubuntu:20.04

💥 옵션 설명

  • --log-opt: 로깅 드라이버에 추가할 옵션
  • syslog-address: rsyslog 컨테이너(서버 호스트)에 접근할 수 있는 주소 입력
  • tag="mylog": 로그 데이터가 기록될 때 함께 저장될 태그이며, 로그를 분류하기 위해 사용됨

client_server 컨테이너 내부로 접속하여 echo 명령을 여러개 날려보자

$ docker exec -it client_server /bin/bash
root# echo "Hello"
root# echo "Bye"

4. 다시 서버의 rsyslog 컨테이너로 돌아와서 컨테이너 내부에 syslog 파일을 확인하면 로그가 전송된 것을 확인할 수 있을 것이다. 각 로그 앞에는 mylog라는 명칭이 추가되어 있다

# 디렉토리 확인
$ ls -lh /logs/hosts
drwx------    2 root     root        4.0K Aug 28 11:21 192.168.121.129
drwx------    2 root     root        4.0K Aug 28 11:17 220969e5e165

# 로그(messages) 확인
$ tail /logs/hosts/192.168.121.129/messages.log
/home/appliance # tail /logs/hosts/192.168.121.129/messages.log
2023-08-28T20:21:54+00:00 192.168.121.129 mylog[1365]: #033]0;root@3a6b23e658c8: /#007root@3a6b23e658c8:/# #015#033[K#033]0;root@3a6b23e658c8: /#007root@3a6b23e658c8:/# #007#007#007clear #015
2023-08-28T20:21:55+00:00 192.168.121.129 mylog[1365]: #033[H#033[2J#033[3J#033]0;root@3a6b23e658c8: /#007root@3a6b23e658c8:/# docker ps#015
2023-08-28T20:21:55+00:00 192.168.121.129 mylog[1365]: bash: docker: command not found#015
2023-08-28T20:22:13+00:00 192.168.121.129 mylog[1365]: #033]0;root@3a6b23e658c8: /#007root@3a6b23e658c8:/# #007docker #010 #010#010 #010#010 #010#010 #010#010 #010#010 #010#010 #010e#010 #010h#010 #010ercho#010 #010#010 #010#010 #010#010 #010#010 #010ecx#010 #010ho "Hello" #010 #010d#010 #010 #010 #010#015
2023-08-28T20:22:13+00:00 192.168.121.129 mylog[1365]: Hello#015
2023-08-28T20:22:15+00:00 192.168.121.129 mylog[1365]: #033]0;root@3a6b23e658c8: /#007root@3a6b23e658c8:/# echo "Bye" #010 #010#015
2023-08-28T20:22:15+00:00 192.168.121.129 mylog[1365]: Bye#015
2023-08-28T20:22:16+00:00 192.168.121.129 mylog[1365]: #033]0;root@3a6b23e658c8: /#007root@3a6b23e658c8:/# clear #015
2023-08-28T20:22:17+00:00 192.168.121.129 mylog[1365]: #033[H#033[2J#033[3J#033]0;root@3a6b23e658c8: /#007root@3a6b23e658c8:/# exit#015
2023-08-28T20:22:17+00:00 192.168.121.129 mylog[1365]: exit#015

Loading script...