[docker-swarm] docker swarm 시작하기 (2)
카테고리: docker
태그: docker
🎯목차
- 서비스에 롤링 업데이트 적용
- 노드 Drain
- Swarm Mode 라우팅 메시 사용
서비스에 롤링 업데이트 적용
시나리오
Redis 3.0.6 컨테이너를 기반으로 서비스를 배포한 후 롤링 업데이트를 통해 Redis 3.0.7 컨테이너 이미지를 사용하도록 서비스를 업데이트 합니다.
# TODO 1. 관리자 노드에서 Redis 3.0.6 태그를 가진 이미지를 기반으로 서비스를 생성합니다.
docker service create \
--replicas 3 \
--name redis \
--update-delay 10s \
redis:3.0.6
0u6a4s31ybk7yw2wyvtikmu50
: << "END"
'--update-delay': 서비스 task에 대한 업데이트 사이의 시간 간격을 의미합니다. Th, Tm, Ts 로 표기할 수 있습니다.
'--update-parallelism': 기본적으로 스케줄러는 한 번에 하나의 task를 업데이트합니다. 해당 플래그를 사용하면 스케줄러가 최대로 동시에 업데이트하는
task 수를 지정할 수 있습니다.
'--update-failure-action;': 기본적으로 개별 task에 대한 업데이트 상태가 'RUNNING'을 반환하는 경우 스케줄러는
업데이트할 다른 task를 예약합니다.
반면 'FALIED' 상태를 반환하는 경우 스케줄러는 업데이트를 일시 중지합니다. 이때 해당 플래그를 사용하여 'FAILED' 시 동작 방식을 제어할 수 있습니다.
위 세 개의 플래그는 'docker service create', 'docker service update' 명령 수행 시 활용할 수 있습니다.
END
# TODO 2. 관리자 노드에서 Redis 서비스를 검사합니다.
docker service inspect --pretty redis
ID: 0u6a4s31ybk7yw2wyvtikmu50
Name: redis
Service Mode: Replicated
Replicas: 3
Placement:
Strategy: Spread
UpdateConfig:
Parallelism: 1
Delay: 10s
ContainerSpec:
Image: redis:3.0.6
Resources:
Endpoint Mode: vip
# TODO 3. 관리자 노드에서 Swarm 관리자는 UpdateConfig 정책에 따라 redis 컨테이너 이미지를 업데이트 합니다.
docker service update --image redis:3.0.7 redis
redis
: << "END"
스케줄러는 기본적으로 다음의 절차에 따라 롤링 업데이트를 적용합니다.
1. 첫 번째 task 중지
2. 중지된 task에 대한 업데이트를 예약
3. 업데이트된 task에 대한 컨테이너를 시작합니다.
4. task 업데이트가 RUNNING 상태를 반환하면 지정된 지연 시간 동안 기다린 후 다음 작업을 시작합니다.
5. 업데이트 중 FAILED 상태를 반환하면 업데이트를 일시 중지합니다.
END
# TDOO 4. 관리자 노드에서 'docker service inpsect --pretty redis' 명령을 통해 컨테이너 이미지를 확인합니다.
docker service inspect --pretty redis
ID: 0u6a4s31ybk7yw2wyvtikmu50
Name: redis
Service Mode: Replicated
Replicas: 3
Placement:
Strategy: Spread
UpdateConfig:
Parallelism: 1
Delay: 10s
ContainerSpec:
Image: redis:3.0.7
Resources:
Endpoint Mode: vip
: << "END"
- 업데이트가 실패한 경우 `docker service inspect --pretty redis` 명령의 결과는 다음과 같습니다.
docker service inspect --pretty redis
ID: 0u6a4s31ybk7yw2wyvtikmu50
Name: redis
...snip...
Update status:
State: paused
Started: 11 seconds ago
Message: update paused due to failure or early termination of task 9p7ith557h8ndf0ui9s0q951b
...snip...
- 일시 중지된 업데이트 실행을 다시 시작하려면 `docker service update <SERVICE-ID>` 명령을 실행합니다.
docker service update redis
END
# TODO 5. 롤링 업데이트를 보려면 'docker service ps <SERVICE-ID>를 실행합니다.
docker service ps redis
NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
redis.1.dos1zffgeofhagnve8w864fco redis:3.0.7 worker1 Running Running 37 seconds
\_ redis.1.88rdo6pa52ki8oqx6dogf04fh redis:3.0.6 worker2 Shutdown Shutdown 56 seconds ago
redis.2.9l3i4j85517skba5o7tn5m8g0 redis:3.0.7 worker2 Running Running About a minute
\_ redis.2.66k185wilg8ele7ntu8f6nj6i redis:3.0.6 worker1 Shutdown Shutdown 2 minutes ago
redis.3.egiuiqpzrdbxks3wxgn8qib1g redis:3.0.7 worker1 Running Running 48 seconds
\_ redis.3.ctzktfddb2tepkr45qcmqln04 redis:3.0.6 mmanager1 Shutdown Shutdown 2 minutes ago
스웜에서 노드 Drain
Drain?
- AVAILABILITY가
Drain으로 설정된 경우 Swarm 관리자로부터 새 task를 할당받지 않습니다. - 또한 관리자는
Drain노드에서 실행 중인 task를 중지시키고 복제본을 ACTIVE AVAILABILITY 인 노드에 실행합니다.
# TODO 1. 관리자 노드에서 모든 노드가 활성 상태인지 확인합니다.
docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
1bcef6utixb0l0ca7gxuivsj0 worker2 Ready Active
38ciaotwjuritcdtn9npbnkuz worker1 Ready Active
e216jshn25ckzbvmwlnh5jr3g * manager1 Ready Active Leader
# TODO 2. redis:3.0.6 이미지를 기반으로 하는 서비스를 생성합니다.
docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6
c5uo6kdmzpon37mgj9mwglcfw
# TODO 3. 'docker service ps redis' 명령을 통해 Swarm 관리자가 다른 노드에 작업을 할당한 방법을 확인합니다.
docker service ps redis
NAME IMAGE NODE DESIRED STATE CURRENT STATE
redis.1.7q92v0nr1hcgts2amcjyqg3pq redis:3.0.6 manager1 Running Running 26 seconds
redis.2.7h2l8h3q3wqy5f66hlv9ddmi6 redis:3.0.6 worker1 Running Running 26 seconds
redis.3.9bg7cezvedmkgg6c8yzvbhwsd redis:3.0.6 worker2 Running Running 26 seconds
# 이 경우 Swarm 관리자는 각 노드에 하나의 작업을 배포했습니다.
# TODO 4. 'docker node update --availability drain <NODE-ID>' 명령을 통해 노드를 Drain 합니다.
docker node update --availability drain worker1
worker1
# TODO 5. 노드의 가용성을 확인합니다.
docker node inspect --pretty worker1
ID: 38ciaotwjuritcdtn9npbnkuz
Hostname: worker1
Status:
State: Ready
Availability: Drain
...snip...
# Availability: Drain 으로 표시됩니다.
# TODO 6. 'docker service ps redis' 명령을 통해 Swarm 관리자가 redis 서비스의 task를 어떻게 할당했는지 확인합니다.
docker service ps redis
NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
redis.1.7q92v0nr1hcgts2amcjyqg3pq redis:3.0.6 manager1 Running Running 4 minutes
redis.2.b4hovzed7id8irg1to42egue8 redis:3.0.6 worker2 Running Running About a minute
\_ redis.2.7h2l8h3q3wqy5f66hlv9ddmi6 redis:3.0.6 worker1 Shutdown Shutdown 2 minutes ago
redis.3.9bg7cezvedmkgg6c8yzvbhwsd redis:3.0.6 worker2 Running Running 4 minutes
# Swarm 관리자는 Drain된 노드에서 task를 종료하고 ACTIVE 상태의 노드에 새 task를 생성하여 원하는 상태를 유지합니다.
# TODO 7. 'docker node update --availability active <NODE-ID>' 명령을 통해 Drain된 노드를 ACTIVE 상태로 되돌립니다.
docker node update --availability active worker1
worker1
# TODO 8. 노드를 검사하여 업데이트된 상태를 확인합니다.
docker node inspect --pretty worker1
ID: 38ciaotwjuritcdtn9npbnkuz
Hostname: worker1
Status:
State: Ready
Availability: Active
...snip...
# 노드를 다시 ACTIVE 상태로 설정하면 새 task를 할당받을 수 있습니다. 하지만 Drain 상태로 설정되면서 중지된 task가 다시 실행되진 않습니다. (Rebalancing X)
스웜에서 라우팅 메시 사용
- 라우팅 메시를 사용하면 Swarm의 각 노드에서 실행 중인 task가 없더라도 Swarm에서 실행 중인 모든 서비스에 대해 게시된 포트의 연결을 만들 수 있습닏나.
- 라우팅 메시는 사용 가능한 노드의 게시된 포트로 들어오는 모든 요청을 활성 task로 라우팅합니다.
- Swarm에서 인그레스 네트워크를 사용하려면 Swarm 모드를 활성화하기 전에 Swarm 노드 간에 다음 포트를 열어야 합니다.
- 컨테이너 네트워크 검색을 위한 포트:
TCP/UDP 7946 - 컨테이너 인그레스 네트워크용 포트 :
UDP 4789
- 컨테이너 네트워크 검색을 위한 포트:
- 특정 서비스에 대한 라우팅 메시를 우회할 수도 있습니다.
서비스용 포트 게시
--publish 플래그를 사용하여 서비스를 생성할 때 포트를 게시합니다. target은 컨테이너 내부의 포트를 지정하고 published는 라우팅 메시에 바인딩할 포트를 지정합니다.
docker service create \
--name <SERVICE-NAME> \
--publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
<IMAGE>
<PUBLISHED-PORT>: SWARM이 제공하는 포트입니다. 생략하면 임의의 높은 번호의 포트가 바인딩됩니다.<CONTAINER-PORT>: 컨테이너가 수신 대기하는 포트입니다. 이 매개변수는 필수입니다.
예를 들어 다음 명령은 nginx 컨테이너의 포트 80을 swarm의 모든 노드에 대해 포트 8080에 게시합니다.
docker service create \
--name my-web \
--publish published=8080,target=80 \
--replicas 2 \
nginx
라우팅 메시는 게시된 포트에 대해 노드에 할당된 모든 IP 주소에서 수신 대기하고 임의 노드의 8080번 포트로 들어온 요청을 활성 컨테이너로 라우팅합니다.

# 1. 다음 명령을 사용하여 기존 서비스에 대한 포트를 게시할 수 있습니다.
docker service update \
--publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
<SERVICE>
# 2. 'docker service inpsect <SERVICE>' 명령을 통해 서비스에 게시된 포트를 확인할 수 있습니다.
docker service inspect --format="" my-web
[{"Protocol":"tcp","TargetPort":80,"PublishedPort":8080}]
TCP 또는 UDP 전용 포트 게시
기본적으로 포트를 게시하면 TCP 포트입니다. --published , -p 플래그에 protocol 키를 TCP 또는 UDP로 지정하면 TCP/UDP/TCP+UDP 포트를 게시할 수 있습니다.
# 1.1 긴 구문 TCP
docker service create --name dns-cache \
--publish published=53,target=53 \
dns-cache
# 1.2 짧은 구문 TCP
docker service create --name dns-cache \
-p 53:53 \
dns-cache
# 2.1 긴 구문 TCP와 UDP
docker service create --name dns-cache \
--publish published=53,target=53 \
--publish published=53,target=53,protocol=udp \
dns-cache
# 2.2 짧은 구문 TCP와 UDP
docker service create --name dns-cache \
-p 53:53 \
-p 53:53/udp \
dns-cache
# 3.1 긴 구문 UDP
docker service create --name dns-cache \
--publish published=53,target=53,protocol=udp \
dns-cache
# 3.2 짧은 구문 UDP
docker service create --name dns-cache \
-p 53:53/udp \
dns-cache
라우팅 메시 우회
라우팅 메시를 우회하면 지정된 노드의 바인딩된 포트에 접속할 때 항상 해당 노드(일반적으로 라우팅 메시로 들어온 요청은 스웜 클러스터로 등록된 모든 노드의 활성 서비스로 라우팅되는 점을 상기하라.)에서 실행 중인 서비스 인스턴스에 엑세스하도록 합니다. 이것을 host 모드라고 합니다. 몇가지 명심할 사항으로 다음을 참고하세요.
- 서비스 task가 실행되지 않는 노드에 엑세스하면 아무런 task도 수신 대기 중이지 않으므로 요청을 처리할 수 없다.
- 동일한 노드에서 같은 task를 실행하는경우 Docker host Port를 임의로 지정할 수 없다.
- 이런 경우 Docker가 임의의 높은 번호의 포트를 할당하도록
published하거나 글로벌 서비스로 사용하거나 배치 제약조건을 사용하여 지정된 노드에서 단일 task만 실행되도록 구성해야한다.
라우팅 메시를 우회하려면 긴 구문의 --publish 플래그를 사용해야 하고 이떄 mode는 host로 설정해야합니다.(mode를 생략하는 경우 ingress로 사용됩니다.) 다음 명령은 라우팅 메시를 우회하는 글로벌 서비스를 생성합니다.
docker service create --name dns-cache \
--publish published=53,target=53,protocol=udp,mode=host \
--mode global \
dns-cache
외부 로드 밸런서 구성
- 라우팅 메시와 함께 사용
- 라우팅 메시 없이 사용
라우팅 메시와 함께 사용
Swarm 서비스로 요청을 라우팅하도록 외부 로드 밸런서를 구성할 수 있습니다. 예를 들어 포트 8080에 게시된 nginx 서비스에 대한 요청을 부하분산을 하도록 HAProxy를 구성할 수 있습니다.

이 경우 로드밸런서에서 Swarm 노드의 8080 포트에 연결할 수 있어야 하고 Swarm 노드는 로드밸런서에 엑세스할 수 있지만 Public 환경에 구성하지 않고 Private 환경에 구성할 수 있습니다.
다음은 HAProxy(L7 로드밸런서) 80번 포트로 들어온 요청을 Swarm의 각 노드 8080번 포트에 전달하는 HAProxy 구성 (/etc/haproxy/haproxy.cfg) 입니다.
global
log /dev/log local0
log /dev/log local1 notice
...snip...
# Configure HAProxy to listen on port 80
frontend http_front
bind *:80
stats uri /haproxy?stats
default_backend http_back
# Configure HAProxy to route requests to swarm nodes on port 8080
backend http_back
balance roundrobin
server node1 192.168.99.100:8080 check
server node2 192.168.99.101:8080 check
server node3 192.168.99.102:8080 check
로드밸런서에 의해 분산된 요청은 Swarm의 노드로 들어오고 라우팅 메시는 요청을 활성 task로 라우팅합니다.
라우팅 메시 없이 사용
- 라우팅 메시 없이 외부 로드 밸런서를 사용하려면
--endpoint-mode의 기본 값인vip(Docker 내부 DNS는 서비스 이름을 VIP로 반환합니다.)대신dnsrr로 설정해야합니다. - 이 경우 VIP가 없고 Docker는 서비스 이름에 대한 DNS 쿼리가 task의 IP 주소 목록을 반환하도록 DNS 레코드를 설정합니다.
Docker Engine DNS Server Architecture

📌출처
👍 개인 공부 기록용 블로그입니다. 오류나 조언이 있으시면 언제든지 댓글 혹은 메일로 남겨주시면 감사하겠습니다! 😄
댓글남기기