Docker Swarm, 제대로 이해하기 - Swarm & Service

2023. 10. 30. 00:00BACKEND/Docker & Kubernetes

본 포스팅은 Docker Swarm 과 Service의 개념을 익히고 실제 사용할 수 있도록 데모를 실행해보는 것을 목표합니다.

 

 

📌  Docker Series

Docker Engine, 제대로 이해하기 (1) -  docker engine deep dive

Docker Engine, 제대로 이해하기 (2) - namespace, cgroup

Docker Network, 제대로 이해하기 (1) - libnetwork

Docker Network, 제대로 이해하기 (2) - bridge, host, none drivers

Docker, 제대로 사용하기 - Commands

> Docker Swarm, 제대로 이해하기 - Swarm & Service

 

 

 

 

Docker Swarm

: 여러 도커 호스트를 클러스터로 묶어 주는 컨테이너 오케스트레이션 도구의 한 종류

 

Swarm으로 클러스터의 앞 쪽에서 하나 이상의 도커 노드를 그룹화하여 클러스터로 관리할 수 있습니다.

 

도커 호스트 여러 대를 사용할 때, 컨테이너 오케스트레이션 도구 없이는 확장성있는 애플리케이션을 만들기가 매우 어렵습니다.

어느 도커 호스트에 어떤 컨테이너를 배치해야 할지,
서로 다른 호스트에 위치한 컨테이너간의 통신은 어떻게 제어하는지 등의 조율을 오케스트레이션 도구없이 하기에는 무리가 있습니다.

 

오케스트레이션 도구를 도입하면 이러한 조율에 수고를 줄여 줄 뿐만아니라,
호스트가 여러대로 나뉘어 있다는 점을 신경 쓰지 않고,

클러스터를 투명하게 다룰 수 있다는 이점도 있습니다.

 

컨테이너 그룹을 오케스트레이션하기 위해서 알아볼 키워드를 정리하자면, 아래와 같습니다.

 

이름 역할 대응하는 명령어
Compose 여러 컨테이너로 구성된 도커 애플리케이션을 관리 (주로 단일 호스트) docker-compose
Swarm 클러스터 구축 및 관리(주로 멀티 호스트) docker swarm
Service 스웜에서 클러스터 안의 서비스(컨테이너 하나 이상의 집합)를 관리 docker service
Stack 스웜에서 여러개의 서비스를 합한 전체 애플리케이션을 관리 docker stack

 

Swarm 은 아래의 두 가지 용도로 사용할 수 있습니다.

 

✔️ 상용 도커 호스트의 보안 클러스터

An enterprise-grade secure cluster of Docker hosts

✔️ 마이크로서비스 앱의 오케스트레이터

An orchestrator of microservices apps

 

 

📌 Benefits

Swarm은 따로 설치나 설정 없이도 바로 사용할 수 있는 Out-of-the-box 서비스로 아래와 같은 기능을 제공합니다.

 

- 암호화된 분산 클러스터 스토어 Encrypted distributed cluster store

- 암호화된 네트워크 Encrypted networks

- Mutual TLS

- 보안을 위한 클러스터 조인 토큰 Secure cluster join tokens

- 인증서 관리 및 재발급을 쉽게 해주는 PKI

 

 

또, 노드를 중단 없이 non-disruptively 추가 및 제거할 수도 있습니다.

오케스트레이션 앞 쪽에서, 스웜으로 복잡한 마이크로서비스 앱을 쉽게 배포하고 관리할 수 있습니다.

앱을 정의하는 파일을 제작한 후, 네이티브 도커 명령으로 스웜에 배포할 수 있습니다.

뿐만 아니라, 도커가 기본으로 제공하는 간단한 명령으로 롤링 업데이트, 롤백, 스케일링 작업까지 수행할 수 있습니다.

 

Swarm은 쿠버네티스 Kubernetes 와 비슷하게 컨테이너화된 애플리케이션을 오케스트레이션합니다.

쿠버네티스는 훨씬 더 많은 탄력성과 더 활발한 커뮤니티 및 생태계를 가지고 있지만,

Swarm은 쉽게 사용할 수 있고, 많은 중소기업과 애플리케이션 배포 시 채택되고 있습니다.

 

혹은, 쿠버네티스를 학습하기 위해 Swarm을 먼저 알아두면 큰 도움이 될 수 있습니다.

 

 

 

Commands

데모를 생성하기 전에, 사용할 모든 명령어들을 먼저 훑어 보겠습니다.

 

 

✔️ docker swarm init : 새로운 swarm 생성

해당 명령어를 실행하는 노드가 첫 번째 관리자가 되어, swarm mode로 실행되도록 전환됩니다.

 

✔️ docker swarm join-token : worker와 manager를 swarm에 포함시키기 위해 필요한 명령과 토큰 발급

새로운 manager를 가입시키기 위해서 docker swarm join-token manager 명령을 사용합니다. 

새로운 worker를 가입시키기 위해서 docker swarm join-token worker 명령을 사용합니다.

토큰은 반드시 안전하게 보관합니다.

 

✔️ docker node ls : swarm 내의 모든 노드를 나열

어떤 게 manager인지 또 어떤 게 leader 인지를 포함한 모든 노드를 확인할 수 있습니다.

 

✔️ docker service create : 새로운 서비스를 만드는 명령어

 

✔️ docker service ls: 실행 중인 서비스를 나열

실행 중인 서비스를 확인할 수 있어, 서비스 상태 및 실행 중인 replicas에 대한 기본 정보를 확인할 수 있습니다.

 

✔️ docker service ps <service> : 특정 서비스 replicas에 대한 보다 자세한 정보 제공

 

✔️ docker service inspect : 서비스에 대한 매우 상세한 정보 제공

가장 중요한 정보만을 확인하려면 위해 --pretty 플래그를 입력할 수 있습니다.

 

✔️ docker service scale : 서비스의 복제본 수를 확장하거나 수축

 

✔️ docker service update : 실행 중인 서비스의 많은 속성을 업데이트

 

✔️ docker service logs : 서비스의 로그 확인

 

✔️ docker service rm : swarm에서 서비스를 삭제

확인을 요구하지 않고 모든 서비스 복제본을 삭제하므로 주의하여 사용해야 합니다.

 

 

 

 

Swarm Hands-on

실제 swarm을 제작해보겠습니다.

 

 

Single engine mode vs Swarm mode

swarm에 포함되지 않은 도커 노드는 single-engine mode라고 합니다.

swarm에 추가되면 자동으로 swarm mode로 전환됩니다.

 

single-engine mode로 도커 호스트에서 docker swarm init 을 실행하면,

해당 노드가 swarm mode로 전환되고, 새로운 swarm을 생성하며 노드가 스웜의 첫 번째 관리자가 됩니다.

 

그러면 추가 노드를 worker 또는 manager로 포함될 수 있으며,

이 때 자동으로 swarm mode로 전환됩니다.

 

 

 

Overview

실제 진행할 데모에 대해 알아보겠습니다.

먼저, Manager 2대, Worker 3대의 컨테이너를 생성합니다.

 

스웜을 구축하는 과정을 스웜 초기화라고 하며, 크게 아래의 과정으로 진행됩니다.

 

1. Manager 초기화 및 등록 Initialize the first manager

2. Workers 등록 Join workers

 

 

✔️ manager

Control plane 관리. Cluster의 상태 관리나 worker에게 task를 보내는 것과 같은 swarm 전체를 제어하는 역할

 

✔️ worker

manager로부터 작업을 수락하고 실행

 

 

Manager 1 에서 새로운 swarm을 생성하기 위해 초기화 명령어를 입력합니다.
그런 다음 Worker 1, Worker 2 및 Worker 3를 워커 노드로 합류시키는데,

이 과정에서 해당 컨테이너들은 자동으로 swarm mode로 전환됩니다.
마지막으로 Manager 2 를 추가 관리자로 등록하는데, 이 때도 동일하게 자동으로 swarm mode로 전환됩니다.
모든 과정이 끝나면 5개 노드 모두 swarm mode임을 확인할 수 있으며, 동일한 swarm로써 작동하게 됩니다.

 

 

📌 여러 대의 도커 호스트로 스웜 클러스터 구성하기

Docker Machines
여러 대의 도커 호스트를 만들 수 있으며, 도커 머신즈를 사용하려면 macos 에서는 virtualbox 드라이버, 윈도우에서는 hyperv 드라이버가 각각 필요합니다.

Virtual Box
같은 가상화 소프트웨어를 사용하면 물리 호스트 1대에 여러 대의 도커 호스트를 실행할 수 있음 도커 공식 참조 문서에서도 이 방법을 소개하고 있습니다.

Docker in Docker
= dind. 도커 호스트 역할을 할 도커 컨테이너를 여러 개 실행하는 방법이며, 도커 컨테이너 안에서 도커 호스트를 실행할 수 있습니다.

 

 

 

1. docker-compose 작성

먼저, swarm이라는 디렉토리 하나를 생성해서 docker-compose를 구성합니다.

 

❯ mkdir swarm
❯ cd swarm
❯ vi docker-compose.yml

 

더보기

 

version: "3" 
services:
  registry:
    container_name: registry
    image: registry:2.6
    ports:
      - 5000:5000
    volumes:
      - "./registry-data:/var/lib/registry"

  manager:
    container_name: manager
    image: docker:dind
    privileged: true
    tty: true
    ports:
      - 8000:80
      - 9000:9000
    depends_on:
      - registry
    expose:
      - 3375
    command: "--insecure-registry registry:5000"
    volumes:
      - "./stack:/stack"

  worker01:
    container_name: worker01
    image: docker:dind
    privileged: true
    tty: true
    depends_on:
      - manager
      - registry
    expose:
      - 7946
      - 7946/udp
      - 4789/udp
    command: "--insecure-registry registry:5000"

  worker02:
    container_name: worker02
    image: docker:dind
    privileged: true
    tty: true
    depends_on:
      - manager
      - registry
    expose:
      - 7946
      - 7946/udp
      - 4789/udp
    command: "--insecure-registry registry:5000"

  worker03:
    container_name: worker03
    image: docker:dind
    privileged: true
    tty: true
    depends_on: 
      - manager
      - registry
    expose:
      - 7946
      - 7946/udp
      - 4789/udp
    command: "--insecure-registry registry:5000"

 

 

 

 

2. docker-compose 실행

이제 docker-compose.yml 실행합니다.

 

❯ docker-compose up -d
[+] Running 6/6
 ✔ Network swarm_default  Created                                                                                                                                                                              0.0s 
 ✔ Container manager02    Started                                                                                                                                                                              0.8s 
 ✔ Container manager01    Started                                                                                                                                                                              0.6s 
 ✔ Container worker02     Started                                                                                                                                                                              1.8s 
 ✔ Container worker01     Started                                                                                                                                                                              1.7s 
 ✔ Container worker03     Started

 

더보기

💣 오류 발생
Your kernel does not support cgroup memory limit

🔮 해결
: Apple M2 Chip에서 발생한 오류로, docker-image 변경함

Before
image: docker:18.05.0-ce-dind

After
image: docker:dind

 

 

 

 

3. 새로운 swarm 초기화

docker swarm init 명령어로 도커를 manager로 지정합니다.

 

❯ docker container exec -it manager01 docker swarm init
Swarm initialized: current node (2kgbjysdan5582hetvrlz0a66) is now a manager.

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

    docker swarm join --token SWMTKN-1-1dke3... 172.21.0.2:2377

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

 

위의 명령어와 같이 swarm init 명령 성공하게 되면, 해당 도커 호스트는 manager로 마킹되면서

swarm mode가 활성화됩니다.

 

종료 후 출력된 join 토큰을 확인할 수 있습니다.

해당 토큰을 통해 worker docker 를 해당 manager가 관리하게끔 만듭니다.

 

 

Token

토큰은 위처럼 생성 시 확인할 수도 있고, join-token 명령어를 통해 확인할 수 있습니다.

Worker를 등록하고자 토큰을 발급하고 싶다면, 아래와 같이 worker 를 입력합니다.

 

❯ docker container exec -it manager01 docker swarm join-token worker
To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-543ojw1... 172.23.0.2:2377

 

또 다른 manager를 등록하고자 한다면, manager를 입력하여 발급받습니다.

 

❯ docker container exec -it manager01 docker swarm join-token manager
To add a manager to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-543ojw1... 172.23.0.2:2377

 

 

4. Swarm에 Worker 등록

worker 컨테이너에서 manager 컨테이너를 식별하도록 manager:2377 로 join 토큰 전달합니다.

 

❯ docker container exec -it worker01 docker swarm join --token SWMTKN-1-1dke3... manager01:2377
This node joined a swarm as a worker.

 

나머지도 등록해줍니다.

 

❯ docker container exec -it worker02 docker swarm join --token SWMTKN-1-1dke3... manager01:2377
This node joined a swarm as a worker.
❯ docker container exec -it worker03 docker swarm join --token SWMTKN-1-1dke3... manager01:2377
This node joined a swarm as a worker.

 

 

 

5. Swarm에 추가 Worker 등록

추가 manager를 등록합니다.

위에서 살펴본 join-token 명령어에 manager를 입력하여 발급받습니다.

 

❯ docker container exec -it manager01 docker swarm join-token manager
To add a manager to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-1dke3... 172.21.0.2:2377

 

발급받은 토큰을 이용해 manager로 등록해줍니다.

 

❯ docker container exec -it manager02 docker swarm join --token SWMTKN-1-1dke3js... manager01:2377
This node joined a swarm as a manager.

 

 

 

6. Swarm cluster 상태 확인

그럼 이후 manager에 등록된 노드들을 확인할 수 있습니다.

 

❯ docker container exec -it manager01 docker node ls
ID                            HOSTNAME       STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
ifc8dg8cdl0rwvw66lfd8yhha     0bfa1e8e38bc   Ready     Active         Reachable        24.0.6
fynomalhu2fryrut2hh2e75dx     055ede599440   Ready     Active                          24.0.6
cslu1q9tv2vqcgch8ji9rjff5     77539678ba45   Ready     Active                          24.0.6
xqsafi0huh7azu1sg2dyfk5r3 *   ac9c5449faa0   Ready     Active         Leader           24.0.6
r5umbj98vrl6huftnhwrqou1k     cbcf19990e5e   Ready     Active                          24.0.6

 

 

 

 

 

Swarm Lock

이전 manager를 다시 시작하거나, 이전 백업을 복원하면 클러스터에 충돌이 발생할 수 있습니다.

 

이전 manager가 다시 조인하면 암호를 해독하여 Raft log time-series database에 액세스할 수 있고,

현재의 Swarm configuration을 오염시키거나 삭제할 수도 있습니다.


이러한 상황을 방지하기 위해 도커는 Autolock 기능으로 스웜을 잠글 수 있습니다.
이는 클러스터에 다시 들어가기 전에 관리자가 키를 제시하도록 강제합니다.

초기화 과정에서 --autolock 플래그를 docker swarm init 명령에 전달하여 스웜을 잠글 수 있지만, 

이미 Swarm을 구축했기 때문에 docker swarm update 명령을 사용하여 Swarm을 잠가야 합니다.

Swarm의 manager에게 다음 명령을 실행합니다.

 

$ docker swarm update --autolock=true
Swarm updated.
To unlock a swarm manager after it restarts, run the `docker swarm unlock` command and 
provide the following key:

   SWMKEY-1-XDeU3XC75Ku7rvGXixJ0V7evhDJGvIAvq0D8VuEAEaw

Please remember to store this key in a password manager, since without it you will not be able
to restart the manager.

 

잠금 해제 키는 안전한 장소에 보관해야 합니다. 

docker swarm unlock-key 명령으로 항상 현재 스웜 잠금 해제 키를 확인할 수 있습니다.

관리자 노드 중 하나를 재시작하여 클러스터에 자동으로 재가입되는지 확인합니다.

명령어 앞에 sudo를 붙여야 할 수도 있습니다.

 

$ service docker restart

# Try and list the nodes in the swarm.
$ docker node ls
Error response from daemon: Swarm is encrypted and needs to be unlocked before it can be used.

 

Docker service가 관리자에서 다시 시작되었지만 Swarm에 다시 조인하는 것은 허용되지 않았습니다.
다른 관리자 노드에서 docker node ls 명령을 실행해서 확인할 수 있습니다.
다시 시작된 manager는 downunreachable 로 표시됩니다.

docker swarm unlock 명령을 실행하여, 재시작된 관리자에 대한 docker swarm unlock 명령을 실행합니다.

재시작된 manager에 대해 이 명령을 실행하고, 이 때 unlock 키를 함께 제공해야 합니다.

 

$ docker swarm unlock
Please enter unlock key: <enter your key>


노드는 swarm에 다시 가입할 수 있으며, 만약 docker node ls 명령을 하게 되면 readyreachable로 표시 됩니다.
운영 환경에서는 스웜을 잠그고 unlock 키를 보호하는 것이 좋습니다.

 

 

 

 

 

Docker Service

위에서 생성한 Swarm을 배포하기 위해 Service를 생성하여 한 번에 배포합니다.

 

단일 도커 컨테이너 배포는 docker container run 명령으로 컨테이너를 하나씩 실행하거나,

compose 를 통해 여러 컨테이너 동시 실행하곤 합니다.

 

Swarm 은 아래와 같이 넓은 범위를 아우르게 구성될 수 있기 때문에,

애플리케이션을 구성하는 일부 컨테이너를 제어하기 위한 단위로 서비스라는 개념을 가집니다.

 

이번에는 생성한 Swarm을 배포해보겠습니다.

 

 

1. Service 생성

먼저, leader manager에 접속해서 서비스를 하나 생성합니다.

 

❯ docker container exec -it manager01 docker service create --replicas 1 --publish 8000:8000 --name echo gngsn/echo:latest
overall progress: 0 out of 1 tasks
1/1: preparing [=================================>                 ]

 

 

2. Service 확인

다음, 서비스가 제대로 생성되었는지 확인합니다.

 

❯ docker container exec -it manager docker service ls
ID             NAME      MODE         REPLICAS   IMAGE               PORTS
6royaikec2pg   echo      replicated   1/1        gngsn/echo:latest   *:8000->8000/tcp

 

 

3. Service Scaling

만약, 서비스 내에서 동일한 컨테이너 수를 늘리고 싶을 땐 어떻게 해야 할까요?

각각의 컨테이너 수만큼 docker container run명령을 반복해야겠지만, 현실적이지 않습니다.

 

docker service scales레플리카 수 조절

 

위 명령어는 자동으로 컨테이너를 복제하고 여러 노드에 배치합니다.

이를 통해 애플리케이션을 쉽게 스케일 아웃할 수 있습니다.

 

❯ docker container exec -it manager docker service scale echo=6

 

늘어난 REPLICAS 확인해보면, 6 개로 늘어난 것을 확인할 수 있습니다.

 

❯ docker container exec -it manager docker service ls
ID             NAME      MODE         REPLICAS   IMAGE                             PORTS
js126i5zxbe0   echo      replicated   6/6        registry:5000/gngsn/echo:latest   *:8000->8000/tcp

 

 

 

4. Service 삭제

생성한 서비스는 아래와 같이 제거할 수 있습니다.

❯ docker container exec -it manager docker service rm echo
echo

 

제거한 서비스를 확인해봅니다.

 

❯ docker container exec -it manager docker service ls
ID        NAME      MODE      REPLICAS   IMAGE     PORTS

 

 

 

FYI.

✔️ 서비스는 레플리카 수(컨테이너 수)를 조절해 컨테이너를 쉽게 복제할 수 있으며, 여러 노드에 레플리카를 배치할 수 있기 때문에 스케일 아웃에 유리

✔️ 서비스로 관리되는 (여러 개의) 레플리카는 서비스명으로 name resolution 되므로 서비스에 대한 트래픽이 각 레플리카로 분산됨

✔️ 스웜 클러스터 외부에서 스웜에 배포된 서비스를 이용하려면 서비스에 트래픽을 분산시키기 위한 프록시를 갖춰야 함