본 글은 시작하세요! 도커/쿠버네티스(용찬호 저, 위키북스)를 기반으로 정리한 글입니다.
이전 포스팅에서 도커와 도커 사용법에 대해서 알아보았는데, 지금까지 알아본 도커 사용법은 하나의 호스트를 기준으로 한다.
그런데 만약 하나의 호스트 머신에서 도커 엔진을 구동하다가 CPU나 메모리, 디스크 용량과 같은 자원이 부족해진다면 이를 어떻게 해결할까? 서버를 하나 더 구매해서 컨테이너를 분산하는 방법이 있을 것이다.
그러나 서버를 추가하면 이러한 서버들을 하나의 자원 풀로 만들어야 하는데, 이는 쉬운 작업이 아니다.
예를 들어 새로운 서버나 컨테이너가 추가됐을 때 이를 발견(Service Discovery)하는 작업부터 어떤 서버에 컨테이너를 할당할 것인가에 대한 스케줄러와 로드밸런서 문제, 클러스터 내의 서버가 다운됐을 때 고가용성을 어떻게 보장할지 등이 문제로 남아 있게 된다.

하지만 다행히도 이러한 문제를 해결하는 여러 오픈소스들이 존재하고, 그 중 대표적인 것이 도커 스웜(Docker Swarm)이다.
도커 스웜
도커 스웜은 서비스 디스커버리, 스케줄링, 로드밸런싱 등을 수행하여 여러 대의 서버와 컨테이너를 쉽게 관리할 수 있도록 도와주는 오케스트레이션 툴이다.
이러한 도커 스웜은 도커 엔진 자체에 내장되어 있기 때문에 별도의 설치 과정이 필요하지 않다는 장점도 있다.
도커 스웜의 구조는 매니저 노드와 워커 노드로 구성되어 있다.

워커 노드는 실제로 컨테이너가 생성되고 관리되는 도커 서버이고, 매니저 노드는 워커 노드를 관리하기 위한 도커 서버이다. 그렇지만 매니저 노드에도 컨테이너가 생성될 수 있으며, 매니저 노드는 기본적으로 워커 노드의 역할을 포함하고 있다.
매니저 노드는 1개 이상이 있어야 하지만 워커 노드는 없을 수도 있다. 이는 매니저 노드가 워커 노드의 역할을 포함하고 있어 매니저 노드만으로도 스웜 클러스터를 구축할 수 있기 때문이다.
도커 스웜 클러스터 구축
도커 스웜 클러스터를 구축하고 기능을 제대로 테스트 해보기 위해서는 적어도 3대 이상의 서버가 필요하다. 예제에서 사용할 서버는 아래와 같다.
swarm-manager 192.168.0.100
swarm-worker1 192.168.0.101
swarm-worker2 192.169.0.102
스웜 클러스터를 구축하기 위해서는 먼저 도커 스웜에서 사용하는 포트들을 각 호스트 머신에서 열어두어야 한다.
스웜 매니저는 기본적으로 2377번 포트를 사용하며, 노드 사이의 통신에 7946/tcp, 7946/udp 포트를, 스웜이 사용하는 네트워크인 ingress 오버레이 네트워크에 4789/tcp, 4789/udp를 사용한다. 이러한 포트들을 각 호스트 머신에서 모두 열어준 뒤, 스웜 클러스터를 구축하도록 하자.
매니저 역할을 할 서버에서 docker swarm init 명령어를 입력해 스웜 클러스터를 시작한다. --advertise-addr에는 다른 도커 서버가 매니저 노드에 접근하기 위한 IP 주소를 입력한다.
root@swarm-manager:~# docker swarm init --advertise-addr 192.168.0.100
Swarm initialized: current node (ywniutzjm3ldrip3tv355lz9u) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-2llx29wnseic5wa66goy2ap8i28q3mhel9j287pqxencdqtpy7-akd27d9x2h5w54xbhnh0fc0bl 192.168.0.100:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
출력 결과에서 볼 수 있는 docker swarm join 명령어는 새로운 워커 노드를 스웜 클러스터에 추가할 때 사용된다.
이제 워커 노드로 사용할 서버에서 위 docker swarm join 명령어를 입력해 스웜 클러스터에 추가되도록 해야한다.
root@swarm-worker1:~# docker swarm join --token SWMTKN-1-2llx29wnseic5wa66goy2ap8i28q3mhel9j287pqxencdqtpy7-akd27d9x2h5w54xbhnh0fc0bl 192.168.0.100:2377
This node joined a swarm as a worker.
docker swarm join이 완료되면 워커 노드가 스웜 클러스터에 추가되었다는 문구가 나오는데, 제대로 추가되었는지 확인해보기 위해 매니저 노드에서 docker node ls 명령어를 입력해보도록 하자.
root@swarm-manager:~# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
ywniutzjm3ldrip3tv355lz9u * swarm-manager Ready Active Leader
vf5n9jw6bf3yfi1c1cim7lfyd swarm-worker1 Ready Active
ij2di98jr4lp6o1olournn51f swarm-worker2 Ready Active
이로써 매니저 노드 1개와 워커 노드 2개로 구성된 스웜 클러스터가 구축된 것을 알 수 있고, 이를 그림으로 표현하면 아래와 같다.

도커 스웜 서비스
이전까지는 도커 컨테이너를 제어해왔다면, 도커 스웜에서는 제어하는 단위가 컨테이너가 아니라 서비스이다.
서비스는 같은 이미지에서 생성된 컨테이너의 집합으로, 서비스 내 컨테이너들은 각 워커 노드와 매니저 노드에 할당된다.
참고로 서비스를 제어하는 도커 명령어는 전부 매니저 노드에서만 사용할 수 있다.
다음은 nginx 웹 서버 서비스를 생성하는 예제이다.
root@swarm-manager:~# docker service create --name myweb --replicas 2 -p 80:80 nginx
root@swarm-manager:~# docker service ps myweb
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ..
ywniutzjm3ld.. myweb.1 nginx swarm-manager Running Running 1 hours ago
vf5n9jw6bf3y.. myweb.2 nginx swarm-worker1 Running Running 1 hours ago
--replicas는 스웜 클러스터에 생성할 컨테이너의 개수를 지정하는 옵션이다.

도커 스웜 스케줄러는 서비스의 정의에 따라 컨테이너를 할당할 적합한 노드를 선정하고, 해당 노드에 컨테이너를 분산해서 할당하는데, 위 예제에서는 2개의 nginx 컨테이너가 swarm-manager와 swarm-worker1 노드에 생성된 것을 알 수 있다.
그렇다면 여기서 swarm-worker2 노드의 IP주소로 접근하면 nginx 웹 서버에 접근할 수 없는 것일까?
그렇지 않다. swarm-worker2 노드의 IP주소와 80번 포트로 접근해보면 nginx 웹 서버에 접근할 수 있음을 알 수 있다.
이는 도커 스웜이 자체적으로 지원하는 ingress 네트워크 덕분이다. ingress 네트워크는 스웜 클러스터를 생성하면 자동으로 등록되는 네트워크로, 스웜 클러스터에 등록된 노드라면 전부 ingress 네트워크가 생성된다.
이러한 ingress 네트워크는 어떤 노드에 접근하더라도 서비스 내의 컨테이너에 접근할 수 있게 설정하는 라우팅 메시를 구성하고, 서비스 내의 컨테이너에 대한 접근을 라운드 로빈 방식으로 분산하는 로드 밸런싱을 담당한다.
도커 스웜은 라운드 로빈 방식으로 서비스 내에 접근할 컨테이너를 결정하기 때문에 각 노드의 트래픽이나 자원 사용량 등을 고려해 로드 밸런싱을 해야 한다면 이 방식은 적합하지 않을 수 있다.
이를 그림으로 표현하면 아래와 같다.

이러한 ingress 네트워크 덕분에 swarm-worker2 노드의 IP주소로도 nginx 웹 서버에 접근할 수 있게 되는 것이다.
이를 조금 쉽게 정리하면, docker service create 명령어에서 -p 옵션으로 80:80을 입력함으로써 스웜 클러스터 자체에 포트를 개방했다고 생각하면 쉽게 이해할 수 있다.
추가적으로 만약 레플리카의 수를 5개로 늘리면 아래와 같이 표현할 수 있을 것이다.

서비스 장애 복구
만약 스웜 클러스터에서 컨테이너가 할당된 특정 노드가 다운된다면 어떻게 될까?
컨테이너가 할당된 노드가 다운되면 매니저는 사용 가능한 다른 노드에 같은 컨테이너를 생성한다. 노드가 다운되지 않더라도 서비스 내의 컨테이너 중 일부가 작동을 멈춰 정지한 상태로 있다면 이 또한 레플리카의 수를 충족하지 못하는 것으로 판단해 스웜 매니저는 새로운 컨테이너를 클러스터에 생성한다.
예를 들어 아래와 같이 스웜 클러스터에 3개의 컨테이너를 생성했다고 가정해보도록 하자.

여기서 만약 워커 노드1이 다운되면 아래와 같이 사용 가능한 다른 노드에 새로운 컨테이너가 생성되게 된다.

이처럼 도커 스웜은 서비스에 설정된 레플리카의 수만큼 컨테이너가 스웜 클러스에 존재하지 않으면 자동으로 새로운 컨테이너를 생성해 이를 복구하는 기능을 제공한다.
이 외에도 더욱 많은 기능들을 제공하는데 자세한 사항은 도커 스웜 공식문서를 참고하도록 하자.
지금까지 도커 스웜에 대해 알아보았다. 도커 스웜은 서버 클러스터에서 컨테이너를 어떻게 다루는지에 대한 기초적인 지식을 쌓기에 적합한 도구이다. 컨테이너를 더욱 세부적으로 관리할 수 있는 오케스트레이션 툴인 쿠버네티스를 학습하기 전에 서버 클러스터에서의 컨테이너 관리를 접해볼 수 있었던 좋은 경험이었던 것 같다.
'DevOps' 카테고리의 다른 글
Jenkins를 활용한 자동 배포 구축 (0) | 2022.05.13 |
---|---|
인덱스 컨디션 푸시다운(index_condition_pushdown) (0) | 2022.02.19 |
어댑티브 해시 인덱스(Adaptive Hash Index) (0) | 2022.02.02 |
Docker란 무엇인가 (0) | 2021.12.20 |