[Docker Swarm으로 고가용성 서버 구축하기 - 4] 편리한 운영을 위한 다양한 Tool 도입하기
이번엔 Docker swarm을 운영하면서 다양한 편리한 Tool 또는 기능을 소개해보겠습니다. 소개할 기술은 총 3가지입니다.
- 정적 Resource 파일을 관리하기 위한 Docker swarm config
- Docker 운영 GUI툴인 Portainer
- apm monitoring 위한 scouter 연동
Docker Swarm Config
Docker swarm config는 Kubernetes의 configmap과 비슷한 기능을 제공합니다. 정적인 파일들을 관리하고 서비스 단위로 공유가 가능합니다. 또한 볼륨을 주입해줄 수 있어 클러스터간 파일을 공유할 수 있습니다. 하지만 k8s의 RBAC(Role-Based-Access-Control)이나 etcd를 이용한 전체 데이터 암호화 등의 기능은 제공하지 않기 때문에 민감한 정보는 저장하기 어려울 수 있습니다.
필자는 다국어 파일이나 간단한 세팅 파일들을 저장해볼려 합니다. 예를 들어 message.properties이라는 다국어 코드를 저장하고 있는 파일이 있다고 가정해보겠습니다.
다음과 같은 파일이 있습니다.
text.hello=안녕, 반가워
text.bye=잘가 즐거웠어
docker config를 통해서 파일을 저장해봅시다.
server1 $ docker config create {config_name} ./message.properties
server1 $ docker config ls
ID NAME CREATED UPDATED
dg426haahpi5ezmkkj5kyl3sn golf_langauge 7 seconds ago 7 seconds ago
이제 이를 docker-compose를 통해 app에 적용시켜봅시다.
version: "3.8"
services:
app:
image: ilgolf/bank:{version}
hostname: kotlin-bank
networks:
- golf
# .. 중략
configs:
- source: golf_language
target: /config/language.properties
# .. 중략
configs:
golf_language:
external: true
필자는 컨테이너 볼륨에 파일을 주입해주는 방식을 택했습니다. 상황에 따라 config안에 파일 자체를 넣어줄 수도 있고 환경변수로 사용할 수도 있습니다.
또한 이렇게 관리되는 config 파일은 여러 컨테이너에서 공유할 수 있기 때문에 유연한 컨테이너 확장이 가능합니다.
그럼 두 번째 portainer를 살펴봅시다.
Portainer
version: "3.8"
services:
portainer:
image: portainer/portainer-ce:2.18.3
ports:
- "8000"
- "9000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /home/golf/portainer/data:data
networks:
- golf
deploy:
replicas: 1
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
placement:
constraints:
- node.role == manager
labels:
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.golf.kr`)"
- "traefik.http.routers.portainer.entrypoints=web"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
networks:
golf:
external: true
세부적으로 살펴보면 우선 8000 port와 9000 port가 존재합니다. 각각 용도를 살펴봅시다.
- 8000 port : Edge Agnet의 port입니다. 원격으로 Docker 환경을 관리하도록 설계된 agent이며 8000 port를 통해 원격으로 Docker와 통신하며 정보를 가져옵니다.
- 9000 port : GUI 서버에 직접적으로 접근하는 port입니다. 실제로는 해당 port로 접근하여 GUI를 활용할 수 있습니다.
또한 외부로는 80 port외엔 열지 않을 것이므로 80 port로 portainer.golf.kr 요청을 받아 처리하도록 traefik label을 설정해줍니다. 그리고 docker socket정보를 읽을 수 있게 local docker.sock파일을 볼륨 마운팅해줍니다.
접속해봅시다.
로그인을 한 후 접속하면
다음과 같이 docker container들을 관리하는 화면에 접속이 가능합니다. 내부에선 다음과 같은 기능들을 제공해줍니다.
- service 관리 (log, 배포, resource limit 등)
- registry 추가 및 관리
- conatiner 성능 모니터링 (단, 다른 노드에 있는 container는 불가)
- user 생성 및 권한 관리 (다만, 권한에 따른 다양한 세부적인 기능은 유료 버전 부터 가능)
자 이제 portainer까지 살펴봤습니다. 실제로 필자는 해당 툴을 이용하여 배포를 하고 있는데 service update 버튼 하나로 손쉽게 배포가 가능해서 매우 편리하게 사용하고 있다.
APM Tool 인 Scouter 적용하여 모니터링하기
APM이란?
Application Perfomance Monitoring의 앞글자를 딴 APM은 애플리케이션의 성능을 모니터링 하는 프로세스로 높은 수준의 서비스를 유지하며 고객이 불편을 겪지 않기 위해 치명적인 API들을 모니터링하여 잡아내기 위해 보통 사용합니다. APM을 이용하여 slow query나 slow api 에러에 대한 모니터링 모두 가능합니다.
대표적인 tool로 Data dog, scouter, pinpoint 등이 존재합니다.
Data dog은 유료 솔루션이기 때문에 무료 오픈 소스인 scouter를 써서 보여드리겠습니다.
우선 scouter를 소개하는 자리가 아니기 때문에 scouter 서버를 설치하고 연동하여 metric 또는 Log를 수집하는 프로세스 전부를 보여드리진 않습니다. 서버가 이미 설치 되어있다는 가정하에 들어갑니다.
우선 scouter를 연동하기 위해 Spring의 경우 실행 옵션에 scouter를 같이 실행해주어야 합니다.
"java -Dspring.profiles.active=prd -javaagent:/scouter/agent.java/scouter.agent.jar -Djob_name={OBJ_NAME} -Dobj_name={JOB_NAME} -jar build/libs/bank.jar"
하지만 문제점이 있습니다. scouter.agent.jar 파일은 외부 파일이고 내부 config 파일도 세팅해줘야하는 문제가 있습니다.
scouter.conf
### scouter java agent configuration sample
#obj_name=WAS-01
net_collector_ip=golf.kr
net_collector_udp_port=6100
net_collector_tcp_port=6100
다음 문제를 해결하기 위해 저는 tar.gz 파일을 만들어 git repository에 넣어주는 선택을 했습니다.
## Dockerfile
FROM openjdk:11-jre-slim
EXPOSE 8091
ARG JAR_FILE=/build/libs/kotlin-0.0.1-SNAPSHOT.jar
ADD config/agent.java.tar.gz /
VOLUME ["/logs"]
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar", "-Duser.timezone=Asia/Seoul", "-Dspring.profiles.active=dev","/app.jar"]
이미지 빌드 단계에서 ADD 명령어로 tar 파일을 압축을 풀어준 상태로 root 경로에 저장해줍니다.
자 이제 배포를 해볼까요? 먼저 docker-compose-app.yml 파일을 수정합시다.
docker-compose-app.yml
version: "3.8"
services:
app:
image: ilgolf/bank:latest
hostname: kotlin-bank
extra_hosts:
- "scouter.golf.kr:10.42.32.78"
networks:
- golf
environment:
TZ: Asia/Seoul
OBJ_NAME: golf-{{.Task.Slot}}
JOB_NAME: golf-{{.Task.Slot}}
# .. 중략
entrypoint:
- /bin/sh
- -c
- java
- -Dspring.profiles.active=prd
- -javaagent:/scouter/agent.java/scouter.agent.jar
- -Dobj_name=$$OBJ_NAME
- -Djob_name=$$JOB_NAME
- -jar
- app.jar
# .. 중략
extra_hosts: env파일에 local dns를 위한 host정보를 추가해줬다. scouter.golf.kr을 입력하면 매핑된 IP로 접속이 가능해집니다.
enviroment 환경변수 추가 : container의 sequence 번호를 golf- 다음에 추가해준다. 보통 1, 2, 3 으로 올라가는 count 숫자입니다.
scouter 세팅 정보 : javaagnet를 추가해줍니다. 이 때 OBJ_NAME과 JOB_NAME은 위 enviroment에 추가한 환경 변수고 docker에서는 시스템 환경변수와 구분하기 위해 $$로 선언한 환경변수와 구분한다.
관리 편의성을 위해 enviroment 환경변수 추가를 해준 것이기 때문에 꼭 추가해야하는지는 편의에 맡기겠습니다. 해당 설정까지 끝나면 APM 세팅까지 마무리되고 xlog 정보를 통해 API 모니터링이 가능해집니다.
마무리
이게 아마 마지막 내용일 것 같은데요 회사에서는 실제로 이러한 프로세스를 통해 성공적으로 docker cluster를 운영하고 있습니다. 많은 장점들이 있었는데 이를 여기 다 적기에는 양이 많아 5탄 회고로 말씀드리면 좋을 것 같습니다.
정말 다 해결 되었는가라고 하기엔 아직 개선할 점이 있어 내부적으로는 개인 시간을 할애하여 추가 R&D를 해보고 있는 상황입니다. 또한 APM 뿐만아니라 node 모니터링을 위한 prometheus & Grafana도 추가적으로 고민해볼 수 있습니다.
그리고 현재 scouter에 대한 setting은 따로 하나의 파일로 관리하기 위해 사설 registry를 구축하여 curl을 이용하여 이미지 빌드할 때 외부에서 가져오려고 개선을 하고 있습니다.
마침.
Reference.
https://selfhostedheaven.com/posts/20220206-manage-docker-with-portainer/
https://aws.amazon.com/ko/what-is/application-performance-monitoring/
https://docs.docker.com/engine/reference/commandline/config_create/
https://kubernetes.io/ko/docs/concepts/configuration/configmap/