Profile picture

[Docker Swarm] 도커 스웜 클러스터 구축하기

JaehyoJJAng2024년 04월 02일

▶︎ 스웜 클러스터 구축하기

이번 실습에서는 VMware Workstaion으로 Ubuntu 22.04가 설치된 VM을 3개 띄워서 3개의 노드로 구성된 클러스터를 구축해볼 것이다.

VM 서버 구축 및 도커 설치 과정은 생략하겠다.


‣ 사전 준비

클러스터에 포함시킬 각 호스트에는 도커 엔진(Docker Engine) 1.12 버전 이상이 설치되어 있어야 한다.
또한 아래의 포트들이 사용 가능한 상태여야 한다.

  • 2377/tcp: 클러스터 관리에 사용되는 포트
  • 7946/tcp, 7946/udp: 노드 간 통신에 사용
  • 4789/udp: 클러스터에서 사용되는 Ingress 오버레이 네트워크 트래픽에 사용

각 호스트에 아래 명령어 실행

sudo hostnamectl set-hostname <노드명>

‣ 스웜 모드 활성화

도커 엔진 자체에 도커 스웜이 통합되어 있다. 도커가 설치되어 있다면, 아래의 한 줄 명령으로 스웜 모드(Swarm Mode)를 바로 시작할 수 있다.

docker swarm init

이렇게 되면 현재 접속 중인 호스트로 단일 노드 클러스터가 새로 구축된다.
만약 특정 IP 주소를 기준으로 클러스터를 시작하려면 아래와 같이 입력하면 된다.

docker swarm init --advertise-addr <매니저 노드 IP주소>

도커 스웜에서 노드는 매니저 노드(Manager Node), 워커 노드(Worker Node) 로 구분된다. 위의 명령문은 --advertise-addr 플래그로 지정된 주소의 호스트를 새로운 클러스터의 매니저 노드로 지정하여 활성화시킨다.


스웜 모드 활성화가 완료되면 아래와 같은 안내문이 출력된다.

Swarm initialized: current node (m1ozlf3hzt9z8vx727d34hzyt) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-5muz63yi56xjsmunoi8ilcmz9v2rgoycpvdert6cb7x3cel5ux-5alk23mrjgi7fl9mx0mx5h2jd 192.168.219.162:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

도커 스웜이 정상적으로 활성화 되었는지 궁금하다면 docker info 명령어를 입력해보자.
아래 스크린샷과 같이, Server.Swarm 값이 active로 바뀐 것을 볼 수 있을 것이다.

docker info | grep -A5 'Swarm'

image


‣ 클러스터 생성

• 단일 노드 클러스터

이제 노드 목록을 확인해보자. 방금 전에 활성화 시킨 매니저 노드 하나만 존재하는 단일 노드 클러스터가 구성된 것을 볼 수 있다.

ubuntu@master:~$ docker node ls

ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
m1ozlf3hzt9z8vx727d34hzyt *   master     Ready     Active         Leader           24.0.7

✏️ Tips

도커 데스크탑에서도 위와 같은 방법으로 단일 노드 구성을 빠르게 진행할 수 있다.
단, 맥(mac) 또는 윈도우(windows)에서 도커 데스크탑을 사용할 때에는 여러 개의 노드로 구성된 다중 클러스터를 생성할 수 없다.


• 다중 노드 클러스터

도커 스웜(Docker Swarm)에서는 토큰(token)이 포함된 docker swarm join 명령을 이용하여 노드를 추가한다. 이때 삽입할 토큰 값은 추가할 노드의 종류에 따라 달라진다. 참고로 첫 번째로 init을 실행한 노드 외의 나머지 노드에서는 별도로 docker swarm init을 할 필요가 없다.


앞서 첫 번째로 docker swarm init을 실행 완료한 노드에 출력된 안내문의 일부를 다시 살펴보자.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-5muz63yi56xjsmunoi8ilcmz9v2rgoycpvdert6cb7x3cel5ux-5alk23mrjgi7fl9mx0mx5h2jd 192.168.219.162:2377

위 안내문을 살펴보면 워커 노드 추가를 위한 명령어가 포함되어 있다. 워커 노드로 추가할 호스트에 접속해서 도커 엔진 설치와 필요 포트 개방을 마친 후, 위의 명령어를 실행시키면 This node joined a swarm as a worker.란 메시지와 함께 클러스터에 추가된다.

ubuntu@node-01:~$ docker swarm join --token SWMTKN-1-5muz63yi56xjsmunoi8ilcmz9v2rgoycpvdert6cb7x3cel5ux-5alk23mrjgi7fl9mx0mx5h2jd 192.168.219.162:2377

image


만약 매니저 노드를 추가하고 싶다면, 우선 매니저 노드로 돌아와 docker swarm join-token manager를 실행한다.

그러면 아래와 같이 별도의 토큰이 생성되는데, 이것을 가지고 새 노드에서 docker swarm join 명령을 수행하면 된다.

# 매니저 노드 join용 토큰을 요청한다.
ubuntu@master:~$ docker swarm join-token manager

To add a manager to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-3va9gxqumnvfax1tivnhheu785lypaepxw7mr3p9rsvifnogn1-0zsoazv4prylgfxqsbsbahi99 172.31.14.44:2377

# 매니저 노드로 추가할 호스트에 접속해서 위의 명령문을 실행한다.
ubuntu@node-02:~$ docker swarm join --token SWMTKN-1-3va9gxqumnvfax1tivnhheu785lypaepxw7mr3p9rsvifnogn1-0zsoazv4prylgfxqsbsbahi99 172.31.14.44:2377

# 노드 추가가 완료되면 아래 메시지가 출력된다.
This node joined a swarm as a manager.

만약 워커 또는 매니저 노드 추가에 필요한 토큰 값만 얻고 싶다면 docker swarm join-token 명령에 --quiet 플래그를 추가해주면 된다.

ubuntu@master:~$ docker swarm join-token --quiet worker
SWMTKN-1-3h415tip2x8wh4xyv9g3uel3sp6ldrgsayusfvf4ebb8b36gn1-e5pshwokqu9u1o05wzh3t3rde # token 값

매니저 노드가 관리하는 정보는 /var/lib/docker/swarm에 저장됩니다.


‣ 노드 정보 조회

• 노드 상세 정보 출력

원하는 특정 노드에 대한 상세 정보를 확인하려면 docker node inspect <노드ID 또는 호스트네임> 명령을 사용한다.
다만 이렇게만 명령문을 실행할 경우 기나긴 JSON 포맷의 텍스트를 출력 결과로 받아보게 된다.

ubuntu@master:~$ docker node inspect node1

image


읽어보기 편한 포맷으로 가공된 출력물을 보고싶다면 --pretty 플래그를 함께 붙여주자.

# 현재 접속한 노드 자기 자신의 정보를 출력할 때엔 노드ID 대신 'self'를 붙인다.
ubuntu@master:~$ docker node inspect self --pretty

image


• 노드 목록 조회

다시 매니저 노드(master)로 돌아와 클러스터 노드 목록을 조회해보자.

ubuntu@master:~$ docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
m1ozlf3hzt9z8vx727d34hzyt *   master     Ready     Active         Leader           24.0.7
ocxg7p9un8vnlbx3k3t9wat52     node1      Ready     Active

docker node ls 명령어는 현재 클러스터에 구성된 노드들의 각 ID 값과 HOSTNAME, STATUS, AVAILABILITY, 그리고 MANAGER STATUS를 보여준다.

노드 ID 값 옆에 붙은 * 표시는 위의 조회 명령을 수행한 현재 노드를 의미한다.


ID는 클러스터 차원에서 각 노드에 부여된 고유의 값이다.

**HOSTNAME은 해당 노드가 가진 호스트네임(hostname)**이다. 이 둘의 차이를 잘 구분해야 한다.

도커 스웜의 클러스터에서는 HOSTNAME은 중복이 가능하다. 같은 호스트네임을 가진 서로 다른 서버가 같은 클러스터에 속할 수 있는 것이다.

반대로 동일한 호스트가 클러스터를 떠났다가(leave) 다시 합류(join)한 경우에는 이전과 다른 새로운 ID 값이 부여된다.

이처럼 클러스터에서 서로 다른 노드를 구분하는 가장 중요한 단서는 HOSTNAME이 아닌 ID이라는 점에 유의하자.


다음으로는 AVAILABILITY를 살펴보자.

먼저 AVAILABILITY 이 값은 노드의 현재 상태를 나타낸다.

  • Active: 정상적으로 태스크(Task)를 할당받을 수 있는 상태를 의미
  • Pause: 이 상태의 노드에는 스케줄러(Scheduler)가 새로운 태스크(Task)를 할당하지 않음.
    • 그러나 해당 노드에서 돌아가는 태스크(Task)는 구동 상태를 그대로 유지한다.
  • Drain: 이 상태의 노드에는 스케줄러(Scheduler)가 새로운 태스크(Task)를 할당하지 않음.
    • 해당 노드에서 돌아가던 태스크(Task)들은 모두 종료되며 가용 상태(Active)인 다른 노드로 다시 스케줄링 된다.

다음으로는 MANAGER_STATUS를 살펴보자.

이 상태 값은 매니저 노드만이 가질 수 있다. 실제로 위의 예시를 보면 맨 처음 매니저 노드의 MANAGER STATUS 값이 Leader로 지정되어 있다.

MANAGER_STATUS에서 매니저 노드가 가질 수 있는 상태값은 다음과 같다.

  • Leader: 스웜 클러스터의 관리와 오케스트레이션을 관리하는 노드다.
  • Reachable: 매니저 노드로서 다른 매니저 노드들과 정상적으로 통신 가능한 상태다. 만약 Leader 노드에 장애가 발생하면, 이 상태값을 가진 매니저 노드는 새로운 Leader 노드로 선출 가능한 후보군이 된다.
  • Unavailable: 매니저 노드로서 Leader를 포함한 다른 매니저 노드들과 통신이 불가능한 상태다. 이런 경우엔 노드를 다시 복구하거나, 다른 워커 노드를 매니저 노드로 변경하거나, 새 매니저 노드를 추가하는 작업이 필요하다.

도커 스웜에서 클러스터는 1개 이상의 매니저 노드를 가질 수 있는데, 이 경우에는 리더(Leader)로 선별된 매니저 노드가 전체 클러스터를 실질적으로 관리하는 역할을 맡는다.

클러스터의 모든 변경 사항은 리더 노드를 통해 전파되며, 나머지 노드들은 리더 노드와 동기화 된 상태를 유지한다

이는 여러 개의 노드로 구성된 클러스터에서 일부 노드에 장애가 발생하더라도 나머지 노드들을 이용하여 서비스를 정상적으로 유지할 수 있는 고가용성(High Availability)을 위해 고안된 것이다.


‣ 노드 관리하기

• 노드 유형 변경

도커 스웜의 노드 관리 명령어(docker node)에서는 promotedemote처럼 특정 노드를 매니저 노드나 워커 노드로 바꿀 수 있는 간편한 명령어를 제공한다.

현재 시점에서는 master가 매니저 노드로 지정되어 있다. 아직 워커 노드로 남아있는 node1 노드를 매니저 노드로 바꿔보자.

ubuntu@master:~$ docker node promote node1

image


이로써 2개의 노드가 모두 매니저 노드로 변경되었다. 이번에는 master만 매니저 노드로 두고, 나머지 1개를 워커 노드로 다시 변경해보도록 하자. promote, demote 명령을 이용하면 여러 노드의 상태를 한 번에 변경할 수 있다.

ubuntu@master:~$ docker node demote node1

# node1이 워커 노드로 변경됨.
Manager node1 demoted in the swarm.

image


promote, demote 명령은 아래와 같이 update --role 형태로 바꿔쓸 수도 있다. 단, update --role 명령으로는 한 번에 하나의 노드만 바꿀 수 있다는 점에 주의하자.

# docker node promote node1
ubuntu@master:~$ docker node update --role manager node1

# docker node demote node1
ubuntu@master:~$ docker node update --role worker node1

또한 클러스터에 남은 마지막 매니저 모드는 demote 또는 제거가 불가능하다.

ubuntu@master:~$ docker node demote master

# FailedPrecondition 관련하여 에러 메시지가 출력된다.
Error response from daemon: rpc error: code = FailedPrecondition desc = attempting to demote the last manager of the swarm

💥 demote 관련 에러

매우 드물게, 여러 노드를 한 번에 demote 하다 보면 다음과 같은 에러가 발생하기도 한다.

ubuntu@master:~$ docker node demote node1 node2

# 01번 노드는 정상적으로 워커 노드가 되었다.
Manager node1 demoted in the swarm.

# 그런데 02번 노드 처리 과정에서 아래와 같은 에러 메시지가 발생했다.
Error response from daemon: rpc error: code = FailedPrecondition desc = can't remove member from the raft: this would result in a loss of quorum

이 경우에는 node2 노드를 워커 노드로 다시 변경해주도록 하자.

# 다시 02번 노드를 워커 노드로 변경 처리한다.
ubuntu@master:~$ docker node demote node2

# 이번에는 02번 노드도 정상적으로 워커 노드로 변경되었다.
Manager node2 demoted in the swarm.

• 노드 상태 변경

때로는 노드에 태스크가 더 이상 할당되지 않도록 막거나, 돌아가고 있던 태스크들을 종료하고 다른 노드로 옮겨줘야 할 상황도 생긴다.

이를테면 호스트에 대한 정기적인 점검이나 업그레이드를 수행해야 하는 경우를 생각해볼 수 있다.

이런 경우에는 docker node update 명령에 --availability 플래그를 더하여 원하는 노드의 상태를 변경할 수 있다.

docker node update --availability <상태> <노드>

--availability 플래그 뒤에 원하는 <상태>와 대상이 될 <노드(노드ID 또는 호스트네임)>를 지정한다.

<상태>에는 앞서 "노드 목록 조회" 파트에서 소개했던 active, pause, drain 중 하나를 입력한다.

ubuntu@master:~$ docker node update --availability drain node1

# 정상적으로 처리되었다면, 해당되는 노드의 호스트네임이 출력된다.
node1

# 이 시점에서 다시 노드 목록을 조회하면 01번 노드가 Drain 처리된 걸 확인할 수 있다.
ubuntu@master:~$ docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
m1ozlf3hzt9z8vx727d34hzyt *   master     Ready     Active         Leader           24.0.7
ocxg7p9un8vnlbx3k3t9wat52     node1      Ready     Drain                          25.0.1

도커 스웜(Docker Swarm)에서 매니저 노드는 기본적으로 워커 노드와 똑같이 태스크를 할당 받아 실행할 수 있다. 그러나 drain 상태의 매니저 노드는 새로운 태스크 할당을 받지 않고, 기존에 할당 받았던 태스크도 다른 노드로 옮긴다. 결국 해당 노드는 클러스터 관리 기능만을 수행하게 된다. 쿠버네티스에서 master:NoSchedule 테인트(Taint)가 설정된 마스터 노드와 동일한 상태가 되는 셈이다.

단, 서비스(Service)로 구성하지 않고 docker run 또는 docker compose up 명령으로 직접 구동시킨 컨테이너들은 Drain 상태에서도 종료되지 않고 그대로 남는다. 이들은 스웜 모드(Swarm Mode)에서 관리되지 않으며 해당 호스트에 개별적으로 남아있게 된다는 점에 유의하자.


• 노드 라벨링

각 노드에는 필요에 따라 라벨(Label)을 지정할 수 있다. 라벨은 키=값(key=value) 또는 키(key) 형태로 부여한다. 이후에 컨테이너 기반 애플리케이션 구동을 위해 서비스(Service)를 클러스터에 배포할 때, 노드에 부여된 라벨 정보를 이용하여 스케줄링 조건을 지정할 수 있다. 예를 들어 redis 서비스(Service)를 배포한다고 가정한다면, type=redis라는 라벨이 붙은 노드에만 해당 컨테이너가 돌아가도록 규칙을 만들 수 있을 것이다.

노드에 라벨을 추가할 때에는 docker node update 명령에 --label-add 플래그를 이용한다. 추가하려는 라벨 하나당 플래그를 하나씩 앞에 붙여줘야 정상적으로 실행된다.

# node1 노드에 'foo'라는 key와 `type=redis'라는 key=value를 라벨로 추가한다.
ubuntu@master:~$ docker node update --label-add foo --label-add type=redis node1

# 노드 정보에서 추가된 라벨 내용을 확인한다.
ubuntu@master:~$ docker node inspect node1 --pretty | grep -i labels: -A 2

# 입력된 라벨이 잘 추가된 것을 확인할 수 있다.
Labels:
 - foo
 - type=redis

불필요한 라벨은 --label-rm 플래그로 삭제

# node1 노드에서 'foo'라는 라벨을 제거한다.
ubuntu@master:~$ docker node update --label-rm foo node1

도커 스웜(Docker Swarm)에선 노드를 먼저 클러스터에 추가시킨 다음부터 라벨링 작업이 가능하다. docker swarm join 또는 init 시점에서 바로 라벨링을 진행할 수는 없는 것으로 보인다.


‣ 노드 제거

• 워커노드 제거

매니저 노드가 현재 구동 중인 다른 노드를 클러스터에서 바로 제거할 수는 없다. 클러스터에서 노드를 제거하기 위한 일반적인 절차는 다음과 같다.

  • 삭제할 노드를 drain 시킨 뒤, 해당 노드에 있던 태스크들이 다른 노드로 잘 옮겨졌는지 확인
  • 삭제할 노드에서 docker swarm leave 명령을 실행하여 해당 노드와 클러스터의 연결을 끊음
  • 매니저 노드에서 docker swarm rm <삭제할노드>를 실행

docker swarm leave 명령 자체가 drain 기능을 포함하고 있으므로 1번 절차는 선택사항에 가깝다. 그러나 가급적 먼저 해주는 걸 권장한다. 삭제될 노드 외엔 가용한 노드가 남아있지 않아서 기존에 돌아가던 태스크들이 PENDING 상태로 멈추게 될 가능성을 미리 체크하기 위해서다.

2번 절차가 끝난 후에도 클러스터 노드 목록에는 해당 노드가 여전히 남아있다는 점에 유의하자. 클러스터를 관리하는 매니저 노드 입장에선, 2번 절차까지 완료 된 노드도 '연결이 끊어져 Down 상태로 인식하게 된 노드'일 뿐이다. 클러스터에서의 노드 제거는 3번 절차까지 진행해주어야 완전히 마무리된다.

위의 절차를 차근차근 따라가보자. 여기서는 워커 노드인 node1 노드를 예제로 사용했다. 먼저 매니저 노드(master)에 접속한 상태로 node1 노드를 drain 상태로 바꿔준다.

ubuntu@master:~$ docker node update --availability drain node1

다음으로는 node1 노드에 할당되어 있던 태스크(Task)들이 다른 노드로 잘 옮겨졌는지 확인할 차례다. 도커 스웜(Docker Swarm)은 모든 애플리케이션이 서비스(Service) 단위로 배포되며, 서비스(Service)에 정의된 이미지 기반 컨테이너가 각 노드에 태스크로서 할당되어 돌아가는 체계를 갖추고 있다. 특정 서비스에 속하는 각각의 태스크가 어느 노드에 할당되어 있는지는 docker service ps 명령으로 확인할 수 있다.

# 여기서는 예시로 3개의 레플리카(replica)를 포함한 nginx 서비스를 배포한 상태로 가정한다.

# node1번 노드를 drain 처리 완료시킨 후,
# 현재 구동(running) 중인 nginx 서비스의 태스크들이 어느 노드에 있는지 확인한다.
# 아래와 같이 -f, --format을 조합하면 내게 필요한 정보만 골라서 출력시킬 수 있다.

ubuntu@master:~$ docker service ps -f "desired-state=running" --format "{{.Name}}: {{.Node}}" nginx

# nginx 태스크들이 01, 02번 노드로 적절히 옮겨져 정상 구동 중인 것을 확인할 수 있다.
nginx.1: master
nginx.2: master
nginx.3: master

이제 node1 노드에 접속하여 docker swarm leave 명령을 실행한다. 그러면 해당 노드에선 스웜 모드(Swarm Mode)가 해제되며, 스케줄러는 해당 노드로 더 이상 태스크를 할당하지 않는다. 기존에 돌아가고 있던 태스크들이 있다면, 이들은 클러스터 안의 가용한 다른 노드들로 옮겨진다. 만약 가용한 노드가 없다면 이들은 어느 노드에도 할당되지 않은 채 PENDING 상태로 대기하게 된다.

ubuntu@node1:~$ docker swarm leave

# 해당 노드가 스웜(swarm)을 떠났다는 메시지가 출력된다.
Node left the swarm.

이 시점에서 매니저 노드(master)로 돌아와 노드 목록을 조회하면 다음과 같이 출력된다.

ubuntu@master:~$ docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
m1ozlf3hzt9z8vx727d34hzyt *   master     Ready     Active         Leader           24.0.7
ocxg7p9un8vnlbx3k3t9wat52     node1      Down      Active                          25.0.1

앞서 leave 처리한 node1이 여전히 목록에 남아있는 것을 볼 수 있다. 다만 STATUS가 Down으로 변경되었다. 즉, 해당 노드는 클러스터와의 연결이 끊어진 독자적인 도커 서버로 바뀌었기에 Down 상태로 표기되는 것이다.


이 상태에서 docker node rm <노드명>을 실행하면 최종적으로 노드 제거가 완료된다.

ubuntu@master:~$ docker node rm node1
node1

ubuntu@master:~$ docker node ls

ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
m1ozlf3hzt9z8vx727d34hzyt *   master     Ready     Active         Leader           24.0.7

만약 제거하려는 워커 노드에 접속이 불가능하거나 기타 이유로 강제 제거가 필요한 상황이라면, docker node rm 명령에 --force 플래그를 조합하여 바로 제거할 수 있다.

ubuntu@master:~$ docker node rm --force node1
node1

• 매니저 노드 제거

매니저 노드를 제거할 때엔 demote 절차를 사전에 반드시 실행해 주어야 한다. 이후로는 워커 노드 제거 방법과 동일하다. 단, 제거 후에도 최소한 하나 이상의 매니저 노드가 클러스터에 존재해야 한다는 제약이 있다. 마지막 남은 매니저 노드는 demote 또는 제거가 불가능하다.

  • 삭제할 노드를 워커 노드로 demote 시킨다.
  • 삭제할 노드를 drain 시킨 뒤, 해당 노드에 있던 태스크들이 다른 노드로 잘 옮겨졌는지 확인한다.
  • 삭제할 노드에서 docker swarm leave 명령을 실행하여 해당 노드와 클러스터의 연결을 끊는다.
  • 매니저 노드에서 docker swarm rm <삭제할노드>를 실행한다.

만약 demote 작업 없이 바로 docker swarm leave 명령을 실행하면 아래와 같은 에러 메시지를 만나게 된다. 클러스터에 남은 매니저 노드의 수에 따라 메시지가 조금씩 바뀌지만, 내용은 비슷하다

ubuntu@node2:~$ docker swarm leave
Error response from daemon: You are attempting to leave the swarm on a node that is participating as a manager. The only way to restore a swarm that has lost consensus is to reinitialize it with `--force-new-cluster`. Use `--force` to suppress this message.

물론 에러 메시지에 안내된 대로 docker swarm leave 명령에 --force 플래그를 붙이면 매니저 노드도 클러스터에서 바로 떼어 놓을 수 있다. 그러나 이것은 절대로 추천하지 않는 방법이다. 왜 그럴까? 한 번 실험해보자.


💥 매니저 노드를 강제로 제거할 시 벌어지는 일

먼저 3개의 노드가 모두 매니저 노드인 경우를 가정하자. 워커 노드 상태의 node2에서 docker swarm leave 명령 실행 결과는 바로 위에서 살펴보았으니, 이번엔 --force 플래그를 붙여 강제로 실행해보자.

ubuntu@node2:~$ docker swarm leave --force
Node left the swarm.

이 상태에서 다른 매니저 노드로 돌아와 전체 노드 목록을 조회하면 다음과 같이 나타난다.

ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
m1ozlf3hzt9z8vx727d34hzyt *   master     Ready     Active         Leader           24.0.7
ocxg7p9un8vnlbx3k3t9wat52     node1      Ready     Active         Reachable        25.0.1
fdowweoor3oosaasllgfo23lo     node2      Down      Active         Unreachable      25.0.1

3개의 매니저 노드 중 1개(node2)가 Down 되었다. 그러나 나머지 두 노드는 여전히 잘 동작한다. 클러스터 관리 기능도 정상적으로 돌아간다. 새 서비스를 클러스터에 배포하더라도 별다른 문제 없이 스케줄링되어 구동되는 것을 확인할 수 있다.


그러면 문제가 없는게 아닌가?

그렇다면 이번엔 3개의 노드 중 2개(master, node2)만 매니저 노드인 경우를 가정하자. 이 상태로 node2에서 docker swarm leave를 실행한 결과는 다음과 같다.

ubuntu@node2:~$ docker swarm leave

Error response from daemon: You are attempting to leave the swarm on a node that is participating as a manager. Removing this node leaves 1 managers out of 2. Without a Raft quorum your swarm will be inaccessible. The only way to restore a swarm that has lost consensus is to reinitialize it with `--force-new-cluster`. Use `--force` to suppress this message.

매니저 노드가 2개에서 1개로 줄어들면 이 정족수가 채워지지 않으면서 클러스터가 정상적으로 기능할 수 없으며, 이를 복구할 수 있는 유일한 방법은 클러스터 자체를 강제로 초기화하는 것뿐이라고 한다.

만약 이 상태에서 매니저 노드 제거를 강행하면 어떻게 될까? node2 노드에서 docker swarm leave --force를 실행하면 예와 마찬가지로 Node left the swarm.이라는 메시지가 출력된다. 잠시 시간을 보낸 후 master 노드로 자리를 옮겨 노드 목록을 조회해보자. 기대와는 다른 결과가 나타난다.

ubuntu@master:~$ docker node ls

# 클러스터 관리 명령이 듣지 않는다. 정보 조회, 변경, 스케줄링 기능이 모두 멈춰버렸다.
Error response from daemon: rpc error: code = Unknown desc = The swarm does not have a leader. It's possible that too few managers are online. Make sure more than half of the managers are online.

3개 노드로 구성된 클러스터에서, 2개의 매니저 노드 중 하나만 없어진 상태인데 클러스터 관리 기능이 완전히 멈춰버렸다. 온전히 동작하는 매니저 노드가 아직 남아있는데도 말이다.


Loading script...