1. 도커의 로깅 구성
도커는 표준 출력(stdout), 표준 오류(stderr) 스트림을 주시하면서 스트림을 통해서 출력되는 내용을 수집한다. 이런 표준 입출력들은 운영체제의 커널과 연결된 셸(터미널)로 입력받고, 표시해주는 것을 의미한다. 어쨌든 도커의 컨테이너는 이런 방식을 통해서 수집된다.
포어그라운드로 다음 컨테이너를 실행해보면 터미널에 표준 출력이 출력되는 것을 볼 수 있다. 5초마다 찍힌다.
docker container run diamol/ch15-timecheck:3.0
따라서 애플리케이션이 표준 출력으로 로그를 출력한다면, 도커 컨테이너에서도 이를 감지하여 로그를 저장하거나 출력할 수 있게 된다.
포어그라운드로 실행되는 컨테이너뿐만 아니라 터미널 세션과 분리되어 데몬으로 작동하는 컨테이너와 종료된 컨테이너의 로그를 수집할 수 있도록 로그를 JSON 파일로도 저장한다. 이 JSON 파일은 컨테이너와 동일한 생애주기를 갖는다. 즉 컨테이너가 제거되면 로그 파일도 삭제된다.
docker container run -d --name timecheck diamol/ch15-timecheck:3.0
docker container logs --tail 1 timecheck
# 컨테이너 중지 후 로그 확인
docker container stop timecheck
docker container logs --tail 1 timecheck
# 로그 파일 경로 확인
docker container inspect --format='{{.LogPath}}' timecheck
생성되는 JSON 로그파일 관련한 규칙은 다음과 같다.
- 컨테이너마다 JSON 로그 파일 하나가 생성된다.
- 따로 설정하지 않으면 디스크 용량이 다 찰때까지 로그 파일의 크기가 증가하며, 여러 파일로 나누는 롤링을 적용할 수도 있다.
2. 로그 전달용 유틸리티 활용
도커는 표준 출력 스트림을 감시한다고 했는데, 만약 어떤 애플리케이션에서 표준 출력으로 로그를 내보내는 것이 아니라 별도의 로그용 프레임워크를 경유해서 다른 곳에 로그를 생성하는 경우가 있다. 이런 별도의 로그 저장소를 싱크(sink)라고 부른다.
이런 경우 애플리케이션에서 저장하는 .log 파일을 로그 전달용 유틸리티를 통해 표준 출력으로 컨테이너에서 내보내야한다. 그러면 도커가 stdout 스트림으로 출력된 로그를 컨테이너 로그로 수집한다. 이런 경우 로그 전달용 유틸리티에 에러가 없도록 세심하게 신경써야하며 이중으로 로깅이 되므로 디스크의 용량을 많이 점유한다. 그럼에도 불구하고 애플리케이션이 백그라운드로 동작하거나 반드시 sink에 저장돼야하는 경우라면 로그 전달용 유틸리티를 사용하는 것이 좋다.
예시로 dotnet 애플리케이션에서는 리눅스에서 사용하는 명령어와 이름이 동일한 tail 유틸리티가 있다. 저자의 예시용 이미지의 Dockerfile 명령어의 일부에는 Tail 유틸리티를 실행하는 CMD 인스트럭션이 포함되어있다.
...
CMD dotnet TImeCheck.dll & dotnet Tail.dll /logs timecheck.log
이 이미지를 기반으로 컨테이너를 실행하고 로그 파일을 확인해보면 컨테이너 속 파일 시스템에서도 로그 파일이 확인된다.
docker container run -d --name timecheck4 diamol/ch19-timecheck:5.0
docker container logs timecheck4 # 컨테이너 로그 수집 여부 확인
docker container exec -it timecheck4 sh # 컨테이너에 세션 연결(리눅스 셸)
cat /logs/timecheck.log # 컨테이너 내부 파일 시스템에서 로그 파일 확인
3. fluentd, elasticsearch, kibana
fluentd
앞서 살펴본 tail 유틸리티는 리눅스 표준 명령이라 사용가능하지만 윈도우에서는 tail을 대체할 수 있는 명령이 없다. 환경적인 차이에 구애받지 않도록 애플리케이션에 오픈 소스 로깅 시스템인 fluentd를 적용해볼 것이다. fluentd는 쿠버네티스, 프로메테우스 등 다양한 프로젝트를 관리하는 Cloud Native Computing Foundation(CNCF)에서 관리한다. 성숙도가 높고 매우 유연하다.
cd ch19/exercises/fluentd
# 설정 파일과 표준 포트를 적용하여 fluentd 컨테이너를 실행
docker container run -d -p 24224:24224 --name fluentd -v "$(pwd)/conf:/fluentd/etc" -e FLUENTD_CONF=stdout.conf diamol/fluentd
# fluentd 로그 드라이버가 설정된 애플리케이션 실행
docker container run -d --log-driver=fluentd --name timecheck5 diamol/ch19-timecheck:5.0
docker container logs timecheck5
docker container logs --tail 1 fluentd
마지막 명령어에서 fluentd에서의 로그를 출력해보면 표준 출력으로 애플리케이션의 컨테이너에서 로그가 남겨진 것을 확인할 수 있다.
ElasticSearch, Kibana
대표적인 로깅 아키텍처로 fluentd와 같이 사용한다. 이들을 일컬어 EFK 스택이라고도 부른다. ElasticSearch는 여러 개의 컨테이너에서 각각 fluentd를 통해 모인 로그들에 메타데이터(로그가 남겨진 시각, 컴포넌트 정보 등)이 추가된 형태의 모든 로그들을 통합하여 모아서 관리한다. 그리고 Kibana는 ElasticSearch에 모인 로그들을 시계열 그래프 등으로 표시해주는 UI 도구이다.
이렇게 각 역할을 분리하여 로그용 아키텍처를 구성해놓는 편이 좋다. 그랬을때 로그 수집용 fluentd나 통합 관리용 ElasticSearch 등을 다른 라이브러리로 교체할 수 있다. 어떤 조직은 애플리케이션 로그를 바로 최종 저장소인 ElasticSearch에 저장하기도 하는데, 이것은 약간의 처리 시간과 네트워크 트래픽을 절약할 수는 있지만 유연성이라는 큰 장점을 희생하는 방법이 되어버린다.
4. EFK 스택 사용 실습
여태 사용했던 container들을 삭제하고 아래 명령어를 실행하여 ElasticSearch가 실행되도록 한다.
cd ch19/exercises
docker-compose -f fluentd/docker-compose.yml up -d
docker container run -d --log-driver=fluentd diamol/ch19-timecheck:5.0
에러처리
--> compose 파일을 실행했더니 fluentd에서 참조로하는 diamol/fluentd 이미지가 업데이트가 안되서 그런지 Open JDK64 관련 에러가 났다. 그리고 elasticsearch, kibana 관련 에러도 났다.
원본: Failed
version: "3.7"
services:
fluentd:
image: diamol/fluentd
environment:
FLUENTD_CONF: elasticsearch.conf
volumes:
- ./conf:/fluentd/etc
ports:
- "24224:24224"
- "24224:24224/udp"
elasticsearch:
image: diamol/elasticsearch
ports:
- "9200:9200"
kibana:
image: diamol/kibana
ports:
- "5601:5601"
각 컨테이너에 들어가서 에러를 살펴보고 처리했다. 그냥 띄워보기라도 하고 싶어서 각 이미지를 공식 이미지로 교체했다. elasticsearch와 kibana는 버전 태그를 지정하지 않으니 에러가 나서 도커허브에서 최신 버전으로 태그를 지정해주었다. 그리고 도커허브의 fluentd 페이지에 들어가서 볼륨 마운트 경로를 수정하고 환경설정 부분을 제거했다.
수정본: Success
version: "3.7"
services:
fluentd:
image: fluentd
volumes:
- ./conf:/fluentd/log
ports:
- "24224:24224"
- "24224:24224/udp"
elasticsearch:
image: elasticsearch:8.7.1
ports:
- "9200:9200"
kibana:
image: kibana:8.7.1
ports:
- "5601:5601"
그리고나서 localhost:5601에 접속하여 kibana에 접근한다. 그럼 elasticsearch 설정 페이지가 나온다.
manually로 설정하니 9200번 포트에 elasticsearch가 떠있는데 찾지를 못하고, Configure Elastic 버튼을 눌러도 등록이 필요하다고 나온다. 아마 이 부분도 프로메테우스나 Jenkins 처럼 각 프로젝트가 원하는 방식대로 등록 절차를 수정한 것 같다.
이 정도까지만 알아두고 실제 실습을 필요할때 해야할 것 같다...
'Programming-[Infra] > Docker' 카테고리의 다른 글
도커 교과서(엘튼 스톤맨, 심효섭) - 20. 비동기 통신, 마무리 (0) | 2023.05.23 |
---|---|
도커 교과서(엘튼 스톤맨, 심효섭) - 18. 리버스 프록시-1: nginx, 로드밸런싱, 라우팅과 SSL, Traefik (0) | 2023.05.21 |
도커 교과서(엘튼 스톤맨, 심효섭) - 16. 이미지 최적화, 환경 변수 설정 관리 (0) | 2023.05.14 |
도커 교과서(엘튼 스톤맨, 심효섭) - 15. 다중 아키텍처 빌드 (0) | 2023.05.07 |
도커 교과서(엘튼 스톤맨, 심효섭) - 14. 도커 원격 접속, 보안과 context (0) | 2023.05.06 |