• yundream
  • 2019-07-19 06:22:56
  • 2017-06-27 13:26:17
  • 80379

Contents

Docker swarm

도커를 다룬지 3년이 넘어가는 것 같지만 스웜(Swarm)을 사용하지 않았다. MesOS나 Rancher 같은 녀석을 사용하거나 직접 만들어서 사용하다 보니, 필요성을 느끼지 못했다. 뒤늦게? 스웜을 써보려는 이유는 스웜위에 Spark를 올리기 위해서다. MesoS위에서도 올릴 수 있겠지만 Spark 스터디 용도로 설치하려는데, 너무 나가는 것 같아서 간단하다는 스웜을 선택했다. Hadoop yarn도 마찬가지의 (복잡하다는)이유로 선택하지 않았다.

도커(docker)는 1.12.0 버전 부터 swarm모드를 지원한다. 1.12 이전의 도커는 호스트 레벨에서만 작동을 했으며, 클러스터를 구성하기 위해서는 MesOS와 같은 툴을 사용해야 했다. 이제 스웜(Swarm)을 이용해서 기본적인 클러스터의 관리가 가능하다.

테스트 환경

VirtualBox를 이용해서 테스트 환경을 만들었다.

 테스트 환경
  • 호스트 운영체제 : 우분투 리눅스 17.04
  • 가상환경 : VirtualBox
  • 게스트 운영체제 : 우분투 서버 리눅스 16.04
  • 도커 설치 : docks.docker.com 참고
도커 버전은 다음과 같다.
# docker version
Client:
 Version:      17.03.1-ce
 API version:  1.27
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Mon Mar 27 17:14:09 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.03.1-ce
 API version:  1.27 (minimum version 1.12)
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Mon Mar 27 17:14:09 2017
 OS/Arch:      linux/amd64
 Experimental: false

스웜 구성요소

도커 스웜의 구성요소들이다.
  • 스웜 : 군중이라는 뜻처럼, 분산된 노드에서 여러 개의 컨테이너를 실행 할 수 있다. 분산된 컨테이너를 실행 할 수 있는 클러스터를 스웜 클러스터라고 부른다.
  • 노드 : 스웜 클러스터를 구성하는 도커 서버
  • 매니저 노드 : 스웜 클러스터를 관리하는 노드다. 스웜 명령어는 매니저 노드에서만 실행한다.
  • 워커 노드 : 매니저 노드의 명령을 받아서 컨테이너가 만들어지는 노드.
  • 서비스 : 기본 배포단위다. 예를 들어 NginX로 로드밸런서를 구축한다면, NginX로 구성된 컨테이너들이 서비스가 된다.
  • 테스크 : 서비스의 구성단위다. 워드프레스 서비스는, 워드 프레스 애플리케이션, Mysql 테스크로 구성될 것이다.

스웜 생성

새로운 스웜(스웜 클러스터)를 만들어보자. 먼저 스웜 클러스터를 관리할 매니저 노드를 설정해야 한다. swarm01 노드를 매니저 노드로 등록하자.
$ docker swarm init --advertise-addr 192.168.56.10
Swarm initialized: current node (kndz5fsmeg5229t96tvv37g47) is now a manager.

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

   docker swarm join \
   --token SWMTKN-1-5fbm1eqi2ako9cc1n50iqm5mi70kwvlqwsxx1tgptgysiqd4de-3fp0vx104o2ct68riqebtyuf0 \
   192.168.56.10:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
이제 워커 노드들은 token에 있는 문자열을 이용해서, 스웜 클러스터에 합류 할 수 있다.

docker info 명령으로 도커 상태를 확인해보자.
$ docker info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 0
Server Version: 17.03.1-ce
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 0
 Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins: 
 Volume: local
 Network: bridge host macvlan null overlay
Swarm: active
 NodeID: kndz5fsmeg5229t96tvv37g47
 Is Manager: true
 ClusterID: bbn1xhq68e1gd2fjxp8077prm
 Managers: 1
 Nodes: 1
스웜 클러스터가 active 인 것을 확인 할 수 있다.

docker node ls로 스웜 클러스터를 구성하고 있는 노드들을 확인 할 수 있다.
$ docker node ls
ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
kndz5fsmeg5229t96tvv37g47 *  swarm01   Ready   Active        Leader

스웜에 노드 추가하기

지금 스웜 클러스터는 manager node하나만 등록되 있다. 이제 워커 노드를 만들어보자. swarm02, swarm03 노드를 워커노드로 등록한다. swarm-02, swarm-03 노드에서 아래 명령을 실행하자.
$ docker swarm join --token SWMTKN-1-5fbm1eqi2ako9cc1n50iqm5mi70kwvlqwsxx1tgptgysiqd4de-3fp0vx104o2ct68riqebtyuf0 192.168.56.10:2377
This node joined a swarm as a worker.
docker node ls 명령을 실행해보자. swarm02, swarm03 노드가 클러스터에 포함된 걸 확인 할 수 있을 것이다.
yundream@swarm01:~$ docker node ls
ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
kndz5fsmeg5229t96tvv37g47 *  swarm01   Ready   Active        Leader
rniubrtixywbqb20mvsucpist    swarm02   Ready   Active        
t26yi2c5ent1eaxelrdwgf81a    swarm03   Ready   Active        

스웜에 서비스 전개하기

스웜은 전개하기 원하는 서비스의 상태를 정의해서 실행한다. 아래와 같은 정보들을 정의할 수 있다.
  • 서비스 컨테이너의 이름과 태그
  • 얼마나 많은 컨테이너가 실행될지
  • 어떤 포트를 외부에 노출 할지
  • 도커시작시 서비스를 자동으로 실행 할지.
  • 서비스가 다시 시작될 때 발생하는 동작 설정.
  • 서비스가 실핼될 조건들

서비스 만들기

하나의 컨테이너로 실행되는 서비스는 설정 없이 실행 할 수 있다. 단지 이미지의 이름만 설정하면 된다. 아래는 nginx 서비스를 실행하는 예제다.
$ docker service create nginx
axgvnpk2sq5mu1d5wgrt7e9vd
docker service ls로 서비스 목록을 확인 할 수 있다. 랜덤이름으로 실행됐다.
$ docker service ls
ID            NAME          MODE        REPLICAS  IMAGE
o3aj11ae8wwe  tender_kirch  replicated  1/1       nginx:latest
alpine 이미지로 부터 helloworld 이름을 가지는 서비스를 만들었다. 컨테이너는 실행하면서 ping docker.com 명령을 실행 한다.
$ docker service create --name helloworld alpine ping docker.com

서비스 업데이트

docker service update명령으로 서비스의 정보를 변경 할 수 있다. 서비스를 업데이트하면, 도커는 컨테이너를 stop 한 다음에 새로운 설정으로 재시작 한다. 테스트를 위해서 my_web 이라는 이름의 nginx 서비스를 만들었다.
$ docker service create --name my_web nginx
zoki6hj8pn4kcnwp90dixpdej
호스트의 8080을 컨테이너의 80으로 포워딩 설정했다.
$ docker service update --publish-add 8080:80 my_web
이제 스웜 노드의 8080포트로 nginx 웹 서버에 접근 할 수 있다.
$ curl -I swarm01:8080
HTTP/1.1 200 OK
Server: nginx/1.13.1
Date: Wed, 28 Jun 2017 14:54:06 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 30 May 2017 13:03:46 GMT
Connection: keep-alive
ETag: "592d6db2-264"
Accept-Ranges: bytes

$ curl -I swarm02:8080
HTTP/1.1 200 OK
Server: nginx/1.13.1
Date: Wed, 28 Jun 2017 14:54:06 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 30 May 2017 13:03:46 GMT
Connection: keep-alive
ETag: "592d6db2-264"
Accept-Ranges: bytes
서비스 컨테이너는 스웜 노드들 중 하나에 뜨지만, 다른 모든 스웜노드로 서비스에 접근 할 수 있다.

스웜은 호스트의 포트를 routing meshport directly on the warm node 두 가지 방식으로 외부에 노출 할 수 있다. 스웜은 별도의 설정이 없을 때 routing mesh모드로 포트를 노출하는데, 스웜의 모든 노드에서 포트에 접근 할 수 있게 해준다.

아래 그림은 routing mesh를 묘사하고 있다.

 Mesh routing

서비스 삭제

사용하지 않는 서비스는 docker service remove로 삭제 할 수 있다.
$ docker service remove my_web

서비스 스케일링

원하는 갯수만큼 서비스를 실행 할 수 있다. my_web 컨테이너를 3개로 늘렸다.
$ docker service scale my_web=3
docker service ls로 서비스 상태를 확인해 보자.
yundream@swarm01:~$ docker service ls
ID            NAME                MODE        REPLICAS  IMAGE
fgsdcjuhdsf5  jolly_khorana       replicated  0/1       my_web
i8h2zeq6ig4n  affectionate_yalow  replicated  0/1       my_web
nxc5sq41eemr  wizardly_brown      replicated  0/1       my_web
pe3140dqrneb  my_web              replicated  3/3       nginx:latest
원본까지 해서 총 4개의 컨테이너가 실행됐다.

Rolling Update

앞서 my_web 애플리케이션을 스케일링 해서 4개의 컨테이너가 실행했다. my_web 애플리케이션의 버전이 올라갈 경우 이들을 모두 새로 실행해야 한다. 이 과정은 무중단으로 진행해야 한다. 실 환경에서 서비스 관리자는 서비스 프로세스를 하나씩 죽였다 살리는 식으로 주의깊게 작업을 진행한다. 프로세스가 그리 많지 않다면, 수작업을 해도 상관없겠으나 수십개가 넘는다면 대략 난감할 것이다.

스웜의 rolling update 기능을 이용해서 이 과정을 자동으로 진행할 수 있다.
$ docker service create \
  --replicas 3 \
  --name my_web \
  --update-delay 10s \
  my_web:4.0
--update-delay를 이용해서 업데이터의 시간 간격을 10s로 설정했다.

노드 추가하기

스웜을 구성하는 노드는 워커 노드관리자 노드 두 개의 타입이 있다. 워커노드는 관리자 노드의 명령을 받아서 컨테이너를 실행하는 일만 한다. 반면 관리자 노드는 스웜 클러스터를 관리하는 일을 한다.

서비스를 실행할 자원이 부족 하다면 워커 노드를 추가해서 자원을 늘려주면 된다. 관리자 노드는 클러스터의 안정성과 가용성을 확보하기 위한 목적으로 사용한다. 스웜 클러스터에 두 개 이상의 관리자 노드를 추가하면, 하나의 관리자 노드에 문제가 생기더라도 서비스를 계속 할 수 있다. 보통은 최소 3개 정도의 관리자 노드를 구성한다. 관리자 노드들 중 하나가 리더로 선출되며, 이 리더가 클러스터를 관리한다. 만약 리더가 죽는다면, 작동중인 관리자 노드들 중 하나가 리더로 선출되서 클러스터를 계속 관리한다.

관리노드에서 join-token명령으로 토큰을 만들어서 배포하면 된다. 워커 노드를 위한 토큰을 만들어보자.
$ docker swarm join-token worker
To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-5fbm1eqi2ako9cc1n50......qebtyuf0 \
    192.168.56.10:2377
이제 추가할 노드(swarm04)에서 위의 명령을 실행하면 된다.
$ docker swarm join \
>--token SWMTKN-1-5fbm1eqi2ako9cc1n50iqm5mi70kwvlqwsxx1tgptgysiqd4de-3fp0vx104o2ct68riqebtyuf0 \
>192.168.56.10:2377
This node joined a swarm as a worker.
swarm04가 추가된 걸 확인 할 수 있다.
$ docker node ls
ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
kndz5fsmeg5229t96tvv37g47 *  swarm01   Ready   Active        Leader
rbmzjtshc3cveo8a18d2qohsg    swarm04   Ready   Active        
rniubrtixywbqb20mvsucpist    swarm02   Ready   Active        
t26yi2c5ent1eaxelrdwgf81a    swarm03   Ready   Active        

매너지 노드를 추가해보자. join-token worker 대신 join-token manager를 호출하면 된다.
$ docker swarm join-token manager
To add a manager to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-5fbm1eqi2ako9cc1n50iqm5mi70kwvlqwsxx1tgptgysiqd4de-ba14im77qflw7xpc7h3c8yiac \
    192.168.56.10:2377

스웜 서비스 네트워크 관리

스웜은 두 개의 트래픽 타입을 지원한다.
  • 제어및 관리 트래픽 : 스웜에 노드를 추가하는 등의 관리 트래픽이다. 항상 암호화 된다.
  • 애플리케이션 트래픽 : 응용 프로그램을 위한 데이터 트래픽으로 컨테이너에서 발생하는 트래픽과 외부 클라이언트와의 트래픽이 포함된다.
여기에서는 애플리케이션 서비스를 위한 트래픽을 제어하는 방법에 대해서 살펴보려 한다. 스웜 네트워크 모델을 완전히 이해하고 싶다면Docker networking reference architecture문서가 도움이 될 것이다.

스웜 서비스는 아래의 네트워크 모델을 지원한다.
  • 오버레이 네트워크(Overlay Network) : 오버레이 네트워크는 스웜에 참여하는 도커 데몬간의 통신을 관리한다.
  • ingress 네트워크는 서비스 노드들간의 로드 밸런싱을 관리하는 목적으로 사용하는 특수한 오버레이 네트워크다. 스웜 서비스 포트에 대한 요청을 받으면 이 요청은 IPVS라는 모듈로 전달한다. IPVS는 서비스에 참여하는 모든 IP 주소를 추적하여, 그 중 하나를 선택하고 트래픽을 해당 경로로 라우팅 한다. ingress 네트워크는 스웜을 초기화 하거나 새로운 노드가 가입할 때 자동으로 만들어진다. 일반적인 경우에 사용자가 정의 할 필요는 없지만, 원한다면 도커 17.05 이상 버전에서 정의 할 수도 있다.
  • docker_gwbridge는 오버레이 네트워크를 개별 도커 데몬으로 연결하기 위한 브릿지 네트워크다. 서비스가 실행 중인 각 컨테이너는 로컬 호스트의 docker_gwbridge 네트워크에 연결된다. docker_gwbridge 네트워크는 스웜을 초기화 하거나 노드가 가입 할 때 자동으로 만들어진다. 일반적으로 사용자가 정의 할 필요는 없지만, 원한다면 사용자가 정의해서 사용 할 수도 있다.

방화벽 정책

도커 데몬은 서로 통신을 하기 위해서 두 개 포트를 사용한다. 아래 포트에 대한 방화적 정책을 허용해야 한다.
  • TCP/UDP 7946 포트 : 컨테이너 네트워크 discovery를 위해서 사용한다.
  • UDP 4789 포트 : 컨테이너 오버레이 네트워크를 구성하기 위해서 사용한다.

오버레이 네트워크의 구성

.... 계속