6 min read

docker swarm

docker swarm
Photo by jean wimmerlin / Unsplash

Introduction

docker가 개별 컨테이너의 실행과 제거, 관리를 담당한다면, swarm은 컨테이너의 분산 실행과 복제 실행, 가상 네트워크와 암호화를 통해 내결합성, 고가용성, 보안 기능을 제공한다.

한마디로 Google Kubernetes, Aphache Mesos 처럼 Docker에서 제공하는 Container Ochestration 기능이라고 보면 된다.

Architecture

docker swarm architecture

일반 docker 환경에서는 개별 container 단위로 실행했지만, swarm mode에서는 service를 정의하여 실행한다.

service는 해당 서비스를 어떻게 실행할 것인지, 즉 보안을 위해 어떤 포트를 열고 막을지, 고가용성을 위해 어떻게 스케줄링을 할 지를 정의한다.

from docs.docker.com

service 안에서 가장 작업 스케줄링 작업 단위를 task라고 한다. 그리고 task의 인스턴스를 container라고 한다.

node는 swarm 모드로 동작하는 docker engine을 말한다. 보통 물리적인 서버나 클라우드 서버에 node들을 분산 배포한다. worker와 manager node로 구분한다.

worker node는 task의 인스턴스인 container를 실행 관리하는 노드이다.

manager node는 service를 구성하는 task들의 실행을 스케줄링하며 worker node에 실행할 task를 전달한다. 그리고 docker cluster 리더 선출 등 cluster 관리를 위한 작업을 처리한다.

manager node 하나로만 docker swarm을 구성할 수 있지만, worker node만 사용해서 swawrm을 구성할 수 없다.

또한 swarm 내부에 DNS componet를 내장하고 있어서 service 명에 의한 접근도 할 수 있다.

docker swarm network

docker swarm 네트워크는 overlay 네트워크와 bridge 네트워크로 나뉜다. swarm 자체적으로는 overlay 타입의 ingress, bridge 타입의 docker_gwbridge 네트워크가 자동 생성된다.

overlay netwok는 swarm 내 docker daemon 및 service 간 통신을 위해 사용한다. overlay network driver로 생성한다.

ingress network는 overlay network의 하나로 service node 간에 load balancing을 담당하고, service가 외부로 노출할 port를 publish하여 연결활 수 있도록 처리한다. 모든 node가 노출된 port로 요청을 받으면, 해당 요청을 IPVS 모듈로 전달하고, IPVS는 service에 참여하는 IP를 모두 추적하며 그 중 하나를 선택해서 라우팅한다.

docker_gwbridge는 bridge 네트워크의 하나로, overlay, ingress 네트워크를 개별 docker daemon의 물리적 네트워크에 연결한다. 각 컨테이너는 로컬 docker daemon의 docker_gwbridge 네트워크에 연결한다.

Run

docker swarm init 명령으로 swarm을 생성한다. 192.168.6.47 상에서 실행하는 것이기 때문에 master node로 지정한다. 아래 실행한 모든 docker 명령은 root 권한에서 실행했기 때문에, sudo를 생략했다.

$ docker swarm init --advertise-addr 192.168.6.47
Swarm initialized: current node (sqcrpfry8lznp6pfbs3xzewhk) is now a manager.

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

    docker swarm join --token SWMTKN-1-4xzxyyz4qkdxtnd7hgxsyeqncgrv0gven52gn86vf9nsvitz1q-4gj05m36b0mixoceojrenc1gu 192.168.6.47:2377

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

worker node에서는 위 실행 결과 대로 swarm join 명령을 통해 master node에 연결할 수 있다. 여기서는 별도의 worker node 없이 master node 하나로만 사용한다.

overlay 네트워크 dvg_net을 추가한다.

$ docker network create --driver overlay dvg_net

여기에 새로운 service dbg_web를 추가한다. nginx를 써서 기본 http를 제공하는 서비스다. overlay 네트워크 dvg_net에 연결시킨다.

$ docker service create --name dvg_web --network dvg_net nginx:alpine
uzhfh7bau2w6ute7x6v75f9du
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged

service를 하나 더 추가하자. busybox로 기본 shell command를 수행하는 서비스다. 상시 동작하는 데몬 프로세스가 없어서 실행 즉시 컨테이너 실행이 종료되기 때문에, sleep 명령으로 원하는 시간만큼 실행될 수 있도록 한다. 마찬가지로 overlay 네트워크 dvg_net에 연결시킨다.

$ docker service create --name dvg_busy --network dvg_net busybox sleep 3600

service와 container 정보는 각각 다음과 같다. service dvg_busy, dvg_web의 container가 각각 dvg_busy1.0dt..., dvg_web.1.dng...로 실행된 것을 알 수 있다.

$ docker service ls
ID             NAME       MODE         REPLICAS   IMAGE            PORTS
lnef4peovzh8   dvg_busy   replicated   1/1        busybox:latest
4shd30s67euc   dvg_web    replicated   1/1        nginx:alpine
$ docker ps -a
CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS          PORTS     NAMES
7beabdf50f5e   busybox:latest   "sleep 3600"             15 seconds ago   Up 14 seconds             dvg_busy.1.0dt80akyy962n1nrie4vjky95
08874fc3c836   nginx:alpine     "/docker-entrypoint.…"   28 minutes ago   Up 28 minutes   80/tcp    dvg_web.1.dng5ygxvwy4x84bt4bpucynq8

dvg_busy.1 컨테이너에 접속한다.

$ docker exec -it 7beabdf50f5e /bin/sh

컨테이너 내에서 dvg_web에 http 접근을 시도해본다. 잘 이루어진다.

$ wget -O- dvg_web
Connecting to dvg_web (10.0.1.8:80)
writing to stdout
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</html>
-                    100% |**********************************************|   615  0:00:00 ETA
written to stdout

참고로 dvg_web은 docker swarm에서 제공해주는 DNS 서비스에서 IP 주소를 확인해준다. /etc/resolv.conf 파일에 DNS 서버가 127.0.0.11로 명시된 것을 확인할 수 있다.

이번엔 exitdvg_busy.1 컨테이너를 나와서, 외부에서 dvg_web 서비스로의 접근이 되는지 확인한다.

$ curl http://127.0.0.1
curl: (7) Failed connect to 127.0.0.1:80; Connection refused

접근이 막힌 것을 알 수 있다. 동일 overlay 네트워크에 연결된 service들끼리는 연결에 제한이 없지만, 외부로는 publish된 port가 없기 때문에 막힌 것이다. 기존 service에 tcp port 80을 추가하고 다시 테스트한다.

$ docker service update --publish-add published=80,target=80 dvg_web
dvg_web
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged
curl http://127.0.0.1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</html>

다시 docker service 리스트를 해보면, port가 추가된 것을 알 수 있다.

$ docker service ls
ID             NAME       MODE         REPLICAS   IMAGE            PORTS
lnef4peovzh8   dvg_busy   replicated   1/1        busybox:latest
4shd30s67euc   dvg_web    replicated   1/1        nginx:alpine     *:80->80/tcp

Reference

— END OF POST.