안녕하세요. 바른호랑이입니다.
이번 게시글에서는 Docker 컨테이너 로깅에 대해서 알아볼 예정입니다.
게시글은 '시작하세요! 도커/쿠버네티스 친절한 설명으로 쉽게 이해하는 컨테이너 관리'를 기반으로 작성하였으니 참고 바랍니다.
컨테이너 내부에서 발생하는 사항들을 아는 것은 디버깅 및 운영 측면에서 매우 중요하기 때문에 이를 관리할 필요가 있습니다. 애플리케이션 레벨에서 로그가 기록되도록 개발하여 별도의 로깅 서비스를 사용하는 것도 가능하지만 도커는 컨테이너의 표준 출력(StdOut)과 에러(StdErr) 로그를 별도의 메타데이터 파일로 저장하며 이를 확인하는 명령어까지 제공해 주기에 이를 활용하는 것도 좋은 방법입니다. Docker가 어떻게 컨테이너 로그를 남기는지 확인해 보기 위해 아래의 명령어로 컨테이너를 작성해 보았습니다.
sudo docker run -d --name mysql \
-e MYSQL_ROOT_PASSWORD=1234 \
mysql:5.7
mysql과 같이 애플리케이션을 구동하는 컨테이너는 포그라운드 모드로 실행되기에 -d 옵션을 써서 백그라운드 모드로 컨테이너를 생성하는 경우가 많으며, 애플리케이션의 구동상태를 알아보기 위해 docker logs 명령어를 사용할 수 있습니다.
sudo docker logs mysql
컨테이너에 오류가 발생했을 경우 해당 내용을 docker logs로 어떻게 확인할 수 있는지 알아보기 위해 오류가 발생하는 컨테이너를 생성 후 docker logs 명령어로 내용을 확인해 보았습니다.
# create container
sudo docker run -d --name no_password_mysql \
mysql:5.7
# check logs
sudo docker logs no_password_mysql
위의 경우는 mysql 실행에 필요한 환경변수를 지정하지 않아 컨테이너가 시작되지 않은 것으로 docker logs를 활용하면 애플리케이션에 발생한 오류를 확인할 수 있습니다. 만약 컨테이너의 로그가 너무 많아 읽기가 힘들다면 --tail 옵션을 써서 출력할 줄 수를 제한하거나 --since옵션을 써서 특정시간 이후의 로그만 조회할 수도 있습니다. 또한 -t 옵션으로 타임스탬프를 표시하거나 -f 옵션으로 로그를 스트림으로 확인하는 것 또한 가능합니다.
sudo docker logs --tail 2 mysql
sudo docker logs --since 2024-08-09T08:00:48Z mysql
sudo docker logs -f -t mysql
docker logs 명령어는 run 명령어에서 -i -t 옵션을 설정하여 docker attach 명령어를 쓸 수 있는 컨테이너에도 사용이 가능하며, 사용 시 컨테이너 내부에서 bash 쉘 등을 입출력한 내용을 확인할 수 있습니다.
# create container
sudo docker run -i -t --name logstest ubuntu:24.04
# command in container
echo test!
# check logs
sudo docker logs logstest
docker logs 명령어를 활용하여 이와 같은 내용을 확인할 수 있는 것은 기본적으로 도커 엔진이 설치된 호스트의 특정위치에 해당 파일들을 저장하기 때문입니다. 컨테이너 로그는 기본적으로 JSON 형태로 도커 내부에 저장되며, 해당 파일은 "/var/lib/docker/containers/${CONTAINER_ID}/${CONTAINER_ID}-json.log"에 저장됩니다.
그렇기에 컨테이너 내부의 출력이 너무 많은 상태로 방치하면 json 파일의 크기가 계속해서 커질 수 있고 이로 인해 저장공간 문제가 발생할 수도 있습니다. 이를 방지하기 위해서는 --log-opt 옵션으로 json 로그 파일의 최대 크기를 지정할 수 있으며, 이때 max-size는 로그 파일의 최대 크기를 max-file은 로그파일의 개수를 의미합니다.
sudo docker run -it \
--log-opt max-size=10k --log-opt max-file=3 \
--name log-test ubuntu:24.04
다른 로깅 드라이버를 사용하여 컨테이너 로그를 수집하게 만들 수도 있는데 대표적인 예로 syslog, journald, fluentd, awslogs 등이 있으며, 애플리케이션 특징에 따라 적합한 로깅 드라이버를 선택하여 작성해야 합니다. 로깅 드라이버를 선택하는 방법으로는 --log-driver 옵션을 사용하면 됩니다.
syslog는 유닉스 계열 운영체제에서 로그를 수집하는 오래된 표준 중 하나로 커널, 보안 등 시스템과 관련된 로그, 애플리케이션의 로그 등 다양한 로그를 수집해 저장할 수 있으며, 대부분의 유닉스 계열 운영체제에서는 syslog를 사용하는 인터페이스가 동일하기 때문에 체계적으로 로그를 수집하고 분석할 수 있다는 장점이 있습니다. 보다 자세한 과정을 알기 위해 실제로 아래 코드를 통해 syslog에 로그를 저장하는 컨테이너를 만들어보았습니다.
# create container for storing log data
sudo docker run -d --name syslog_container \
--log-driver=syslog \
ubuntu:24.04 \
echo syslogtest
syslog 로깅 드라이버는 기본적으로 로컬호스트의 syslog에 저장하므로 운영체제 및 배포판에 따라 syslog 파일의 위치를 알아야 이를 확인할 수 있습니다. ubuntu 24.04는 /var/log/syslog에 해당 내용을 저장하며, 아래의 명령어를 통해 내용을 확인해 볼 수 있습니다.
tail -n 20 var/log/syslog
syslog를 원격 서버에 설치하면 로그 옵션을 추가해 해당 로그 정보를 원격 서버로 전송하는 것이 가능합니다. rsyslog는 이를 구현할 수 있는 대표적인 방법 중의 하나이며, 서버 호스트에 rsyslog 서비스를 사용하는 컨테이너를 생성 및 구동하고, 클라이언트 호스트에서 log를 생성하는 컨테이너를 생성하여 데이터를 전송하는 방식으로 구현이 가능합니다. 이는 아래의 명령어를 통해 보다 명확하게 확인해볼 수 있습니다.
# host ip: 192.168.91.151
# client ip: 192.168.91.152
# create container in server host
sudo docker run -i -t \
-h rsyslog \
--name rsyslog_server \
-p 514:514 -p 514:514/udp \
ubuntu:14.04
# change rsyslog.conf file in container(name: rsyslog_server)
nano /etc/rsyslog.conf
# remove annotation this code to rsyslog.conf file
# ----- content start -----
# provide UDP syslog reception
$ModLoad imupdp
$UDPServerRun 514
# provides TCP syslog reception
$ModLoad imtcp
$UnputTCPServerRun 514
# ----- content end -----
# reboot rsyslog service
service rsyslog restart
서버 호스트에서 컨테이너 생성을 완료했다면 클라이언트 호스트에서 아래 코드를 활용하여 로그를 생성할 컨테이너를 생성해 주었습니다.
# create container in client host
sudo docker run -i -t \
--log-driver=syslog \
--log-opt syslog-address=tcp://192.168.91.151:514 \
--log-opt tag="mylog" \
ubuntu:14.04
# execute simple command
echo test
--log-opt는 로깅 드라이버에 추가할 옵션들을 의미하며 로그를 명확하게 전송하기 위해 syslog-address에는 rsyslog 컨테이너에 접근할 수 있는 주소를, tag에는 로그 데이터가 기록될 때 함께 저장될 태그값을 추가해 주었습니다. 클라이언트 호스트에서 컨테이너를 생성해 준 후에는 정상적으로 로그가 원격으로 쌓이는지 확인하기 위해 아래의 코드로 확인해 보았습니다.
# check syslog data in server host
tail /var/log/syslog
--log-opt 옵션으로 syslog-facility를 사용하면 로그가 저장될 파일을 변경할 수 있으며, 보통 facility는 로그를 생성하는 주체에 따라 로그를 다르게 저장할 때 사용합니다. 기본적으로는 daemon으로 설정되어 있지만 kern, user, email 등 다른 facility의 사용이 가능합니다. 아래의 명령어를 실행하여 해당 내용을 보다 명확하게 확인해 보았습니다.
# create container in client host
sudo docker run -i -t \
--log-driver syslog \
--log-opt syslog-address=tcp://192.168.91.151:514 \
--log-opt tag="maillog" \
--log-opt syslog-facility="mail" \
ubuntu:14.04
rsyslog는 우분투에서 쓸 수 있는 기본적인 로깅 방법으로 별도의 UI는 제공하지 않지만 logentries, LogAnalyzer 등과 같은 로그 분석기와 연동하면 웹 인터페이스를 활용하여 편리하게 활용하는 것도 가능합니다.
컨테이너 로깅을 하는 또 다른 방법으로는 fluentd를 활용하는 방법이 있습니다. fluentd는 각종 로그를 수집하고 저장할 수 있는 기능을 제공하는 오픈소스 도구로서 도커 엔진 컨테이너의 로그를 저장할 수 있도록 플러그인을 제공합니다. 데이터 저장 포맷으로 json을 사용하기 때문에 사용이 용이하고, 수집 데이터를 AWS S3, HDFS(Hadoop Distributed File System), MongoDB 등과 같은 다양한 저장소에 저장할 수 있다는 장점이 있습니다. 이를 보다 명확하게 알아보기 위해 아래와 같은 구조로 서버를 구축한 후 로그를 적재해 보았습니다.
위의 구조를 실현하기 위해 MongoDB 서버를 생성한 후 Docker를 설치해 주고, MongoDB Container를 생성해 주었으며, 포트로는 27017 포트를 사용하기 위해 개방해 주었습니다.
# MongoDB server ip: 192.168.91.153
# create mongoDB container
sudo docker run --name mongoDB -d \
-p 27017:27017 \
mongo
그다음으로는 fluentd 서버의 호스트에서 로그 데이터를 몽고 DB에 전송하고 access라는 이름의 컬렉션에 로그 데이터를 저장하기 위해 fluent.conf 파일을 먼저 작성해 주고, fluentd 이미지에 MongoDB를 연결하는 플러그인을 적용하기 위해 별도의 Docker File을 작성 후 이미지로 만들어주었습니다.
# fluentd server ip:192.168.91.154
# create fluent.conf file
<source>
@type forward
</source>
<match docker.**>
@type mongo
database nginx
collection access
host 192.168.91.153 # mongodb server ip
port 27017
flush_interval 10s
</match>
# create DockerFile
FROM fluent/fluentd:v1.14-1
USER root
RUN apk update && \
apk add musl-dev gcc make ruby-dev && \
fluent-gem install fluent-plugin-mongo
EXPOSE 24284
USER fluent
CMD exec fluentd -c /fluentd/etc/$FLUENTD_CONF -p /fluentd/plugins $FLUENTD_OPT
# build docker image as Dockerfile
sudo docker build -t custom-fluentd ~/
# check image
sudo docker images
이미지와 설정파일을 생성한 후에는 해당 파일들을 이용하여 fluentd 컨테이너를 만들어주었습니다.
# create container
sudo docker run -d --name fluentd -p 24224:24224 \
-v $(pwd)/fluent.conf:/fluentd/etc/fluent.conf \
-e FLUENTD_CONF=fluent.conf \
custom-fluentd
fluentd 서버에 로깅에 사용할 컨테이너까지 정상적으로 생성한 후에는 실제로 로그가 정상적으로 MongoDB까지 적재되는지 확인하기 위해 도커 호스트 서버에 로그 데이터를 적재할 컨테이너를 생성해 주었습니다.
# create container in server host(using fluentd server ip)
sudo docker run -p 80:80 -d \
--log-driver=fluentd \
--log-opt fluentd-address=192.168.91.154:24224 \
--log-opt tag=docker.nginx.webserver \
nginx
컨테이너를 생성한 후 해당 컨테이너 주소로 접근을 1회 이상 시도한 이후 아래의 코드로 mongoDB server에 생성한 mongoDB container를 조회하여 정상적으로 로그 데이터가 적재되고 있는지 확인해 주었습니다.
# check log data in mongoDB container
sudo docker exec -it mongoDB mongosh
# check log data
show dbs
use nginx
show collections
db['access'].find()
데이터가 정상적으로 출력되었으므로 도커엔진에서 생성된 로그 데이터가 fluentd 서버의 컨테이너를 거쳐 몽고 DB 서버의 컨테이너로 적재된 것을 확인할 수 있었습니다.
'IT & 데이터 사이언스 > Data Engineering' 카테고리의 다른 글
[Docker] 도커 이미지 (4) | 2024.10.08 |
---|---|
[Docker] 컨테이너 자원 할당 (1) | 2024.08.29 |
[Docker] Docker 네트워크 (1) | 2024.08.08 |
[Docker] Docker 볼륨 (5) | 2024.08.05 |
[Docker] 컨테이너 외부 네트워크에 오픈하기 (0) | 2024.07.29 |
댓글