Docker Swarm dind 구성 및 수동 리밸런싱 테스트
이번 포스팅에서는 Docker Swarm dind 구성 및 수동 리밸런싱 테스트를 공유해보려고 합니다.
개요
시스템 메모리 초기화 등을 위해 정기 PM(유지보수) 작업 중, 서버를 하나씩 내렸다 올림
이를 위해, 도커 스웜 클러스터 또한 서버(노드)가 내려갔을 때, Task의 전환 및 노드 복구 후 Task의 재분배(리밸런싱)이 어떻게 이루어지는지 확인이 필요
- 자동 리밸런싱 제공 X
- 수동 리밸런싱 방법을 확인
1. Docker Swarm dind 구성
1.1 환경
단일 서버 환경에서의 dind 구성했으며, 매니저 노드 3대만 있을 경우로 가정하여 진행
docker/
├── 1.dind-swarm-cluster
│ ├── docker-compose.yml
│ ├── setup.sh
│ └── volume
1.2 클러스터 구성
docker-compose.yml
services:
registry:
container_name: registry
image: registry:2.8
ports:
- "5000:5000"
volumes:
- "./volume/registry-data:/var/lib/registry"
manager1:
container_name: manager1
image: docker:27.1.1-dind
privileged: true
tty: true
ports:
- "8000:80"
- "8085:8085" # visualizer 용
- "2377:2377" # Swarm 클러스터 관리 포트
- "7946:7946" # 노드 간 통신 포트
- "7946:7946/udp" # 노드 간 통신 포트 (UDP)
- "4789:4789" # 오버레이 네트워크 포트
command: ["dockerd-entrypoint.sh", "--experimental", "--host=tcp://0.0.0.0:2375", "--host=unix:///var/run/docker.sock", "--insecure-registry=registry:5000"]
volumes:
- "./volume/stack:/stack"
manager2:
container_name: manager2
image: docker:27.1.1-dind
privileged: true
tty: true
ports:
- "8001:80"
- "2378:2377" # Swarm 클러스터 관리 포트
- "7947:7946" # 노드 간 통신 포트
- "7947:7946/udp" # 노드 간 통신 포트 (UDP)
- "4790:4789" # 오버레이 네트워크 포트
command: ["dockerd-entrypoint.sh", "--experimental", "--host=tcp://0.0.0.0:2375", "--host=unix:///var/run/docker.sock", "--insecure-registry=registry:5000"]
volumes:
- "./volume/stack:/stack"
manager3:
container_name: manager3
image: docker:27.1.1-dind
privileged: true
tty: true
ports:
- "8086:8086"
- "8002:80"
- "2379:2377" # Swarm 클러스터 관리 포트
- "7948:7946" # 노드 간 통신 포트
- "7948:7946/udp" # 노드 간 통신 포트 (UDP)
- "4791:4789" # 오버레이 네트워크 포트
command: ["dockerd-entrypoint.sh", "--experimental", "--host=tcp://0.0.0.0:2375", "--host=unix:///var/run/docker.sock", "--insecure-registry=registry:5000"]
volumes:
- "./volume/stack:/stack"
worker01:
container_name: worker01
image: docker:27.1.1-dind
privileged: true
tty: true
ports:
- "8087:8087"
expose:
- "7946" # 노드 간 통신 포트
- "7946/udp" # 노드 간 통신 포트 (UDP)
- "4789/udp" # 오버레이 네트워크 포트
command: ["dockerd-entrypoint.sh", "--experimental", "--host=tcp://0.0.0.0:2375", "--host=unix:///var/run/docker.sock", "--insecure-registry=registry:5000"]
depends_on:
- manager1
- manager2
- manager3
- registry
worker02:
container_name: worker02
image: docker:27.1.1-dind
privileged: true
tty: true
expose:
- "7946" # 노드 간 통신 포트
- "7946/udp" # 노드 간 통신 포트 (UDP)
- "4789/udp" # 오버레이 네트워크 포트
command: ["dockerd-entrypoint.sh", "--experimental", "--host=tcp://0.0.0.0:2375", "--host=unix:///var/run/docker.sock", "--insecure-registry=registry:5000"]
depends_on:
- manager1
- manager2
- manager3
- registry
스크립트(setup.sh)를 통해 도커 스웜 클러스터 구축
#!/bin/bash
# 1.
docker-compose up -d
# 2.
docker exec -it manager1 hostname manager1
docker exec -it manager2 hostname manager2
docker exec -it manager3 hostname manager3
docker exec -it worker01 hostname worker01
docker exec -it worker02 hostname worker02
echo "All containers are up and hostnames are set."
sleep 10
# 3.
MANAGER1_IP=$(docker exec -it manager1 hostname -i | tr -d '\r')
docker exec -it manager1 docker swarm init --advertise-addr $MANAGER1_IP
echo "Docker Swarm initialized with manager1 IP: $MANAGER1_IP"
# 4.
MANAGER_JOIN_TOKEN=$(docker exec -it manager1 docker swarm join-token manager -q | tr -d '\r')
docker exec -it manager2 docker swarm join --token $MANAGER_JOIN_TOKEN $MANAGER1_IP:2377
docker exec -it manager3 docker swarm join --token $MANAGER_JOIN_TOKEN $MANAGER1_IP:2377
echo "manager2 and manager3 have joined the swarm as managers."
# 5.
WORKER_JOIN_TOKEN=$(docker exec -it manager1 docker swarm join-token worker -q | tr -d '\r')
docker exec -it worker01 docker swarm join --token $WORKER_JOIN_TOKEN $MANAGER1_IP:2377
docker exec -it worker02 docker swarm join --token $WORKER_JOIN_TOKEN $MANAGER1_IP:2377
echo "worker01 and worker02 have joined the swarm as workers."
1.3 Registry 설정 및 UI 생성
-- (내부가 아닌, 서버에서 수행) tag 붙이기
$ docker tag registry:2.8 localhost:5000/registry:2.8
$ docker push localhost:5000/registry:2.8
‘’‘
registry 2.8 cfb4d9904335 10 months ago 25.4MB
localhost:5000/registry 2.8 cfb4d9904335 10 months ago 25.4MB
‘’‘
$ curl -X GET http://localhost:5000/v2/_catalog
-- worker 또는 manager 컨테이너 안에서 실행
$ docker pull localhost:5000/registry:2.8 (에러)
$ docker pull registry:5000/registry:2.8 (이름 혹은 IP)
-- registry 컨테이너 설정
$ docker exec -it registry sh
/ # vi etc/docker/registry/config.yml
‘’‘
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
Access-Control-Allow-Origin: ["http://localhost:8086"]
Access-Control-Allow-Methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
Access-Control-Allow-Headers: ["Authorization", "Content-Type"]
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
‘’‘
-- 서버
$ docker-compose stop registry
# docker-compose restart registry
-- 매니저 /stack/docker/3.registry-ui
/ # vi docker-compose.yml
‘’‘
services:
rgst-ui:
image: joxit/docker-registry-ui:latest
ports:
- "8086:80"
environment:
- REGISTRY_URL=http://localhost:5000
deploy:
replicas: 1
placement:
constraints:
- node.labels.role == test-role
‘’‘
2. 서비스 실행
테스트용
-- 자신의 hostname을 출력하는 웹 어플리케이션 (서비스 실행 = 3개의 Task 실행)
$ docker service create --name testApp -p 4567:4567 --replicas 3 subicura/whoami:1
-- 도커 스웜 visualizer, Global Mode로 실행 (서비스 실행 = 3개의 Task 실행)
$ docker stack deploy -c docker-compose.yml test
services:
visualizer:
image: dockersamples/visualizer
ports:
- "80:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
mode: global
placement:
constraints: [node.role == manager]
--5초마다 카운트 증가하는 어플리케이션 (서비스 실행 = 1개의 Task 실행)
$ docker stack deploy -c docker-compose.yml test
#!/bin/bash
count=0
while true; do
echo "Hello, World! Count: $count"
count=$((count + 1))
sleep 5
done
실행중인 서비스와 Task 확인
3. 수동 리밸런싱 테스트
3.1 Leader 노드의 서버 중지
노드가 죽었을 떄, Task가 다른 노드로 전환되는지 (승격 여부 포함)
- 매니저1에 있던 Task(app_helloworld, testApp)가 다른 노드로 전환되어 실행됨
- Leader의 역할 또한, 승격됨을 확인 (매니저1 -> 매니저3)
$ docker-compose stop manager1
Task의 전환 (상세 확인)
- 다른 노드에 새로 Task가 실행되어 서비스의 연속성을 유지함
3.3 서버 복구 시, Task 이동 확인 (Task 재분배)
클러스터가 자동으로 컨테이너를 해당 노드(복구된)로 재배치시키는 가
- 실행 중이던 Task들은 원래 위치로 이동하지 않음 (재배치 수행 X)
$ docker-compose start manager1
도커 스웜은 클러스터가 자동으로 재배치하지않기에 수동으로 실행해야 함
3.3 수동으로 재배치 (1/2)
수동 방법 1. 서비스를 강제로 업데이트하여 컨테이너 재배포
$ docker service update --force app_helloworld
3.3 수동으로 재배치 (2/2)
수동 방법 2. 복제 수를 조정하여 재배치 유도
$ docker service scale app_helloworld=0
$ docker service scale app_helloworld=3
결론
도커 스웜에서는 자동으로 리밸런싱되지 않음
- 자동으로 task를 리밸런싱하면 불필요한 컨테이너 재시작이 발생할 수 있기에, 이는 이미 실행중인 애플리케이션에 영향을 미칠 수 있음 (안정성 우선시)
- 수동으로 리밸런싱하면, 시기를 정할 수 있으며 효율적 활용 가능
참고