[docker-swarm] docker swarm 시작하기 (2)

업데이트:     Updated:

카테고리:

태그:

🎯목차

  • 서비스에 롤링 업데이트 적용
  • 노드 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번 포트로 들어온 요청을 활성 컨테이너로 라우팅합니다.

image

# 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 플래그를 사용해야 하고 이떄 modehost로 설정해야합니다.(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를 구성할 수 있습니다.

image

이 경우 로드밸런서에서 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

image

📌출처

Docker Docs


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

맨 위로 이동하기

docker 카테고리 내 다른 글 보러가기

댓글남기기