컨테이너 내부에서 어떤 일이 일어나는지 아는 것은 디버깅뿐만 아니라 운영 측면에서도 중요합니다. 어플리케이션 레벨에서 로그가 기록되도록 개발해서 별도의 로깅 서비스를 쓸 수도 있지만 도커는 컨테이너의 표준 출력(StdOut)과 에러(StdErr) 로그를 별도의 메타데이터 파일로 저장하며 이를 확인하는 명령어를 제공합니다.
이번 포스트에서는 도커 컨테이너 로깅
에 대해 정리하겠습니다.
json-file 로그 사용하기
json-file 로그 명령어
$ docker logs [Container Id or Name]
docker logs
명령어를 사용하면 컨테이너의 로그를 확인할 수 있습니다.
--tail 옵션
-> 컨테이너의 로그가 너무 많아 읽기 힘들다면 --tail 옵션을 사용하여 마지막 로그 줄부터 출력할 줄 수를 설정할 수 있습니다.
--since 옵션
-> --since 옵션에 유닉스 시간을 입력해 특정 시간 이후의 로그를 확인할 수 있습니다.
-t 옵션
-> 컨테이너의 로그에 타임스탬프를 추가할 수 있습니다.
-f 옵션
-> 컨테이너의 로그를 스트림으로 확인할 수 있습니다. 이 옵션은 어플리케이션을 개발할 때 유용합니다.
json-file 예시
먼저 컨테이너를 생성해서 간단하게 json-file
로 로그를 남겨보겠습니다.
아래 명령어는 mysql 5.7 버전의 컨테이너를 생성합니다.
$ docker run -d --name mysql \
-e MYSQL_ROOT_PASSWORD=1234 \
mysql:8
mysql과 같은 어플리케이션을 구동하는 컨테이너는 포그라운드 모드로 실행이 되므로 -d 옵션을 써서 백그라운드 모드로 컨테이너를 생성하는 경우가 많습니다. 따라서 어플리케이션이 잘 구동되는지 여부를 알 수는 없지만 docker logs 명령어를 써서 컨테이너의 표준 출력을 확인함으로써 어플리케이션의 상태를 알 수 있습니다.
docker logs
명령어는 컨테이너 내부에서 출력을 보여주는 명령어입니다.
이번에는 다른 방법으로 컨테이너를 생성해 보겠습니다. 동일한 mysql 컨테이너를 생성하되, -e 옵션을 제외합니다.
$ docker run -d --name no_password_mysql \
mysql:8
위 명령어를 실행한 뒤 docker ps 명령어로 컨테이너의 목록을 확인하면 no_password_mysql 컨테이너는 생성이 되었으나 실행이 되지 않았습니다. 내부적으로 오류가 있기 때문입니다.
이럴 때 docker logs
명령어를 사용하면 어플리케이션에 무슨 문제가 있는지 확인할 수 있습니다. 위의 경우는 mysql 실행에 필요한 환경변수를 지정하지 않아 컨테이너가 시작되지 않은 것입니다. 이처럼 컨테이너가 정상적으로 실행 및 동작하지 않고 docker attach 명령어도 사용하지 못하는 개발 환경에서 docker logs 명령어를 쓰면 간단하고 빠르게 에러를 확인할 수 있습니다.
$ docker logs no_password_mysql
컨테이너의 로그가 너무 많아 읽기 힘들다면 --tail 옵션
을 써서 마지막 로그 줄부터 출력할 줄의 수를 설정할 수 있습니다.
--since 옵션
에 유닉스 시간을 입력해 특정 시간 이후의 로그를 확인할 수 있고, -t 옵션
을 추가하여 타임스탬프를 추가할 수도 있습니다. 컨테이너에서 실시간으로 출력되는 내용을 확인하려면 -f 옵션
을 써서 로그를 스트림으로 확인할 수 있습니다. 특히, -f 옵션
은 어플리케이션을 개발할 때 유용합니다.
docker logs 명령어는 run 명령어에서 -i -t 옵션을 설정해 docker attach 명령어를 사용할 수 있는 컨테이너에도 사용할 수 있으며, 컨테이너 내부에서 bash 쉘 등을 입출력한 내용을 확인할 수 있습니다.
$ docker run -i -t --name logtest ubuntu:focal
# 컨테이너 접속 후
$ echo test!
$ docker logs logtest
기본적으로 위와 같은 컨테이너 로그는 JSON 형태로 도커 내부에 저장됩니다. 이 파일은 아래 경로의 컨테이너 ID로 시작하는 파일명으로 저장됩니다. 아래의 log 파일의 내용을 cat, vi 편집기 등으로 확인하면 logs 명령으로 정제되지 않은 JSON 데이터를 볼 수 있습니다.
$ cat /var/lib/docker/containers/${CONTAINER_ID}/${CONTAINER_ID}-json.log
어떠한 설정도 하지 않았다면 도커는 위와 같이 컨테이너 로그를 JSON 파일로 저장하지만 그 밖에도 각종 로깅 드라이버를 사용하게 설정해 컨테이너 로그를 수집할 수 있습니다. 사용 가능한 드라이버의 대표적인 예로 syslog, journald, fluentd, awslogs 등이 있고, 어플리케이션의 특징에 적합한 로깅 드라이버를 선택합니다.
syslog 로그
컨테이너의 로그는 JSON뿐 아니라 syslog로 보내 저장하도록 설정할 수 있습니다. syslog는 유닉스 계열 운영체제에서 로그를 수집하는 오래된 표준 중 하나로서, 커널, 보안 등 시스템과 관련된 로그, 어플리케이션의 로그 등 다양한 종류의 로그를 수집해 저장합니다. 대부분의 유닉스 계열 운영체제에서 syslog를 사용하는 인터페이스가 동일하기 때문에 체계적으로 로그를 수집하고 분석할 수 있다는 장점이 있습니다.
아래의 명령어를 입력해 syslog에 로그를 저장하는 컨테이너를 생성합니다. 컨테이너의 커맨드가 echo syslogtest로 설정되기 때문에 syslogtest라는 문구를 출력하고 컨테이너는 종료될 것입니다.
$ docker run -d --name syslog_container \
--log-driver=syslog \
ubuntu:22.04 \
echo syslogtest
syslog 로깅 드라이버는 기본적으로 로컬호스트의 syslog에 저장하므로 운영체제 및 배포판에 따라 syslog 파일의 위치를 알아야 이를 확인할 수 있습니다. 우분투 14.04는 /var/log/syslog, 우분투 16.04와 CoreOS는 journalctl -u docker.service 명령어로 확인할 수 있습니다.
현재 날짜 기준으로 최신버전인 우분투 22.04 기준으로도 journalctl -u docker.service 명령어로 확인할 수 있습니다. 아래는 우분투에서 syslog가 기록된 예시입니다.
syslog를 원격 서버에 설치하고 로그 정보를 원격 서버로 보낼 수 있습니다. 서버 두 개가 필요하므로 기회될 때 실습해보도록 하겠습니다.
fluentd 로깅
fluentd
는 각종 로그를 수집하고 저장할 수 있는 기능을 제공하는 오픈소스 도구로서, 도커 엔진의 컨테이너의 로그를 fluentd를 통해 저장할 수 있도록 플러그인을 공식적으로 제공합니다. fluentd는 데이터 포맷으로 JSON을 사용하기 때문에 쉽게 사용할 수 있을뿐만 아니라 수집되는 데이터를 AWS S3, HDFS(Hadoop Distributed File System), MongoDB 등 다양한 저장소에 저장할 수 있다는 장점이 있습니다.
아래의 그림은 fluentd를 통해 로그가 수집되는 흐름을 보여줍니다. fluentd와 몽고DB(MongoDB)를 연동해 데이터를 저장하는 것을 나타낸 것이고 특정 호스트에 생성되는 컨테이너는 하나의 fluentd에 접근하고, fluentd는 몽고DB에 데이터를 저장하는 구조입니다.
위 그림대로라면 도커 서버, fluentd 서버, 몽고 DB 서버로 구성되므로 서버는 최소 3대가 필요하지만 사용자의 환경에 맞게 변경해서 사용하면 됩니다. 예를 들면, 각 서버 호스트에 fluentd를 설치할 수도 있고, 테스트를 위해 몽고DB 서버, fluentd 서버, 도커 서버가 하나의 물리 머신에서 동작하도록 구현할 수 있습니다.
동작 실습은 이번에는 패스하도록 하겠습니다!
Amazon 클라우드워치 로그
AWS(Amazon Web Service)에서는 로그 및 이벤트 등을 수집하고 저장해 시각적으로 보여주는 클라우드워치(CloudWatch)를 제공합니다. 도커를 AWS EC2에서 사용하고 있다면 다른 도구를 별도로 설치할 필요 없이 컨테이너에서 드라이버 옵션을 설정하는 것만으로 클라우드워치 로깅 드라이버
를 사용할 수 있습니다.
클라우드 워치를 사용하는 것은 아래와 같은 단계를 따릅니다.
1. 클라우드워치에 해당하는 IAM 권한 생성
2. 로그 그룹 생성
3. 로그 그룹에 로그 스트림(LogStream) 생성
4. 클라우드워치의 IAM 권한을 사용할 수 있는 EC2 인스턴스 생성과 로그 전송
1. 클라우드워치에 해당하는 IAM 권한 생성
먼저, AWS에 접속한 후에 콘솔에서 로그인 해줍니다.
도커에서 AWS의 클라우드워치를 사용할 수 있는 권한을 설정하려면 IAM Role을 설정해야 합니다.
먼저, [Security, Identity & Compliance] -> [IAM] -> [Policies]에 들어가줍니다.
[Policies] -> [CreatePolicy]를 클릭합니다.
1단계에서는 AWS 권한을 설정해줍니다. Service는 CloudWatch를 선택합니다.
Actions는 All CloudWatch actions를 선택합니다.
3단계의 Summary에서 CloudWatch에 대한 Access level이 Full access 확인합니다.
확인되었으면 [Create policy]를 클릭해서 생성합니다.
2. 로그 그룹 생성
그리고 [Management & Governance] -> [CloudWatch]에 들어갑니다.
Create log group 클릭하고 로그 그룹을 생성해줍니다.
3. 로그 스트림 생성
생성된 로그 그룹을 선택해서 로그 스트림을 생성합니다. [Create Log Stream]을 클릭해서 로그 스트림을 생성합니다.
4. EC2 인스턴스에 IAM 권한 설정 및 로그 전송
EC2 인스턴스에 CloudWatch를 사용할 수 있도록 권한을 추가해야 합니다.
실행중인 EC2 인스턴스 아이디를 클릭해 접속한 후, [Actions] -> [Security] -> [Modify IAM role]을 클릭합니다.
그리고 아까 생성하였던 CloudWatch에 대한 권한을 추가해줍니다.
그리고 IAM을 사용하도록 설정한 EC2 인스턴스의 도커 엔진에서 아래의 명령어를 입력해 컨테이너를 생성합니다. 로깅 드라이버로 awslogs(클라우드워치)를 사용할 수 있도록 설정하고 로그 그룹과 스트림은 생성하였던 로그 그룹, 로그 스트림을 사용합니다. 리전은 EC2의 인스턴스가 아닌 로그 그룹 및 스트림이 생성된 리전을 입력해야 합니다.
$ docker run -i -t \
--log-driver=awslogs \
--log-opt awslogs-region=ap-northeast-2 \
--log-out awslogs-group=mylogs \
--log-out awslogs-stream=mylogstream \
ubuntu:focal
# 컨테이너 접속 후
$ echo test!