회사 기술블로그에 작성한 내용입니다.
Author. chhanz
안녕하세요? 오픈소스컨설팅 한철희 과장입니다.
이전 " Docker 이해하기 " 를 포스팅에 이어, " Docker Swarm 을 이용한 Container Orchestration 환경 만들기 " 라는 포스팅을 작성하게 되었습니다.
(Review - Docker 이해하기 )
이전 포스팅에서 Docker 를 직접 사용하면서 여러 장점을 확인했습니다.
하지만 과연 실무에 적용하면 안정적으로 서비스를 유지하고 운영할 수 있을지에 대해서는 의문을 가지고 있었습니다.
이러한 의문은 Container 들을 자동으로 관리하게 해주는 Container Orchestration Tool 을 활용함으로써 해결을 하게 되었습니다.
Container Orchestration
컨테이너 오케스트레이션 이란? 다중 컨테이너 패키지 어플리케이션을 배포하는 동안 사용되는 컨테이너, 리소스의 자동화, 정렬, 조정 및 관리를 하는 것을 말합니다.
위와 같이 많은 오케스트레이션 도구들이 있습니다. 이번 포스팅에서는 쉽게 구성이 가능한 Docker Swarm 을 통해 컨테이너 오케스트레이션을 맛보려고 합니다.
Docker Swarm
Docker Swarm 이란?
수많은 컨테이너 오케스트레이션 도구 중의 하나로, 여러 대의 Docker 호스트들을 마치 하나인 것처럼 만들어주는 Orchestration 도구입니다.
Docker v1.12 이후부터 Docker Swarm Mode 로 별개의 Docker Swarm 엔진에서 Docker 엔진으로 통합되면서 좀 더 간편한 설치가 가능해졌습니다.
쉬워진 Docker Swarm 직접 설치 해보도록 하겠습니다.
Docker Swarm 설치
(Docker Document, How nodes work - https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/)
위와 같이 기본적으로 Docker Swarm 은 Master 노드와 Worker 노드로 시스템을 구성합니다.
Master 노드에서는 클러스터 관리 작업을 하고 클러스터 상태 유지, 스케줄링 서비스, Swarm HTTP API Endpoint 를 제공합니다.
Worker 노드는 컨테이너를 실행하는 역할만 합니다.
이번 Master 노드를 Three-Manager 구성으로 하여 컨테이너 오케스트레이션 및 Docker Swarm 안정성에 대해 확인해보도록 하겠습니다.
OS : CentOS Linux release 7.6.1810 (Core)
Docker Version : docker-1.13.1-88.git07f3374.el7.centos.x86_64
위와 같이 시스템 환경으로 Three-Manager 구성을 하도록 하겠습니다.
Docker Swarm 이 Docker 엔진과 통합되면서 설치는 일반적인 Docker 설치와 동일해졌습니다.
설치는 아래와 같습니다.
# yum -y install docker
[root@manager1 ~]# yum -y install docker <중략> Installed: docker.x86_64 2:1.13.1-88.git07f3374.el7.centos Dependency Installed: PyYAML.x86_64 0:3.10-11.el7 atomic-registries.x86_64 1:1.22.1-26.gitb507039.el7.centos audit-libs-python.x86_64 0:2.8.4-4.el7 checkpolicy.x86_64 0:2.5-8.el7 container-selinux.noarch 2:2.74-1.el7 container-storage-setup.noarch 0:0.11.0-2.git5eaf76c.el7 containers-common.x86_64 1:0.1.31-7.gitb0b750d.el7.centos docker-client.x86_64 2:1.13.1-88.git07f3374.el7.centos docker-common.x86_64 2:1.13.1-88.git07f3374.el7.centos libcgroup.x86_64 0:0.41-20.el7 libseccomp.x86_64 0:2.3.1-3.el7 libsemanage-python.x86_64 0:2.5-14.el7 libyaml.x86_64 0:0.1.4-11.el7_0 oci-register-machine.x86_64 1:0-6.git2b44233.el7 oci-systemd-hook.x86_64 1:0.1.18-2.git3efe246.el7 oci-umount.x86_64 2:2.3.4-2.git87f9237.el7 policycoreutils-python.x86_64 0:2.5-29.el7_6.1 python-IPy.noarch 0:0.75-6.el7 python-backports.x86_64 0:1.0-8.el7 python-backports-ssl_match_hostname.noarch 0:3.5.0.1-1.el7 python-ipaddress.noarch 0:1.0.16-2.el7 python-pytoml.noarch 0:0.1.14-1.git7dea353.el7 python-setuptools.noarch 0:0.9.8-7.el7 setools-libs.x86_64 0:3.3.8-4.el7 subscription-manager-rhsm-certificates.x86_64 0:1.21.10-3.el7.centos yajl.x86_64 0:2.0.4-4.el7 Dependency Updated: policycoreutils.x86_64 0:2.5-29.el7_6.1 Complete! [root@manager1 ~]# systemctl enable docker Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service. [root@manager1 ~]# systemctl start docker
위와 같이 모든 Master 노드에 동일하게 설치를 합니다.
[root@manager1 ~]# systemctl enable docker Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service. [root@manager1 ~]# systemctl start docker
# systemctl enable docker
# systemctl start docker
각 노드 별로 Docker 서비스를 시작합니다.
[root@manager1 ~]# systemctl status docker ● docker.service - Docker Application Container Engine Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled) Active: active (running) since 월 2019-02-11 14:14:37 KST; 2min 54s ago Docs: http://docs.docker.com Main PID: 14694 (dockerd-current) CGroup: /system.slice/docker.service ├─14694 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-cu... └─14701 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc --runtime-args --systemd-c...
# systemctl status docker
설치가 완료되면 Docker 서비스를 시작하고 위와 같이 정상적으로 시작되었는지 확인합니다.
Docker Swarm init
Docker Swarm 를 구성하기 위해 아래와 같이 명령 수행을 합니다.
# docker swarm init --advertise-addr [Manager Node IP]
[root@manager1 ~]# docker swarm init --advertise-addr 192.168.13.176 Swarm initialized: current node (y8ul9r3jq0rgt9k3vbvrayeyg) is now a manager. To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-2m3tqsm8ly45vpd5i80p4bkor5zaohfmultu4cdnvfpg8yxmuk-bv8adgschaygmg9icehekb9wg \ 192.168.13.176:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
위와 같이 초기화를 진행하면 Worker 노드를 추가하는 token 값으로 명령어가 자동 생성됩니다.
해당 명령을 Worker 노드에 입력하면 해당 노드는 Worker 노드가 됩니다.
Master 노드(Manager 노드)를 추가하기 위해서는
# docker swarm 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-2m3tqsm8ly45vpd5i80p4bkor5zaohfmultu4cdnvfpg8yxmuk-9ghru6puwdvqms3bn7zqtiyvt \ 192.168.13.176:2377
Manager 연결을 위해 생성된 명령을 나머지 Manager 노드에 아래와 같이 입력합니다.
[root@manager2 ~]# docker swarm join \ > --token SWMTKN-1-2m3tqsm8ly45vpd5i80p4bkor5zaohfmultu4cdnvfpg8yxmuk-9ghru6puwdvqms3bn7zqtiyvt \ > 192.168.13.176:2377 This node joined a swarm as a manager. [root@manager3 ~]# docker swarm join \ > --token SWMTKN-1-2m3tqsm8ly45vpd5i80p4bkor5zaohfmultu4cdnvfpg8yxmuk-9ghru6puwdvqms3bn7zqtiyvt \ > 192.168.13.176:2377 This node joined a swarm as a manager.
Docker Swarm 구성 확인
[root@manager1 ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS lrt89xwkugty162qk8c2av5ek manager2.example.com Ready Active Reachable y8ul9r3jq0rgt9k3vbvrayeyg * manager1.example.com Ready Active Leader yqerq5ujds38t0izzlp03dbhd manager3.example.com Ready Active Reachable
# docker node ls
위와 같이 manager 로 노드들이 연결된 것을 확인 할 수 있습니다.
Docker Swarm 기본 사용법
Docker Swarm 에서 사용되는 기본적인 명령을 간단한 Apache 서비스를 기동하면서 확인 해보겠습니다.
Docker Swarm Service 생성
Docker Swarm 명령어는 기존의 docker 명령어와 크게 다른 점은 없습니다.
기본적으로 docker run 에서 사용되는 옵션을 그대로 사용 할 수 있습니다.
아래 명령을 통해 Docker Swarm Mode 로 컨테이너를 실행 할 수 있습니다.
Usage: docker service create [OPTIONS] IMAGE [COMMAND] [ARG...]
[root@manager1 ~]# docker service create --name web httpd xocc6zwdulliijqpypwby764d
Docker Swarm Service 확인
생성된 서비스가 정상적으로 실행이 되었는지는 아래 명령으로 확인이 가능합니다.
Usage: docker service ls
[root@manager1 ~]# docker service ls ID NAME MODE REPLICAS IMAGE xocc6zwdulli web replicated 0/1 httpd:latest [root@manager1 ~]# docker service ls ID NAME MODE REPLICAS IMAGE xocc6zwdulli web replicated 1/1 httpd:latest
처음 REPLICAS 필드가 0/1 로 시작해서 1/1 로 변경이 되면 컨테이너가 정상적으로 실행이 된 것으로 확인 할 수 있습니다.
해당 필드를 통해 컨테이너가 문제가 생겼는지 정상 작동 중인지 확인이 가능합니다.
또한 각 서비스 별로 자세한 정보를 확인하는 명령은 아래와 같습니다.
Usage: docker service ps [SERVICE]
[root@manager1 ~]# docker service ps web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 9x3qvcl5seif web.1 httpd:latest manager2.example.com Running Running 2 minutes ago
Docker Swarm Service Scale-out
생성된 서비스를 복제하여 분산 서비스를 할 수 있도록 합니다.(Scale-out)
Usage: docker service scale SERVICE=REPLICAS [SERVICE=REPLICAS...]
[root@manager1 ~]# docker service scale web=3 web scaled to 3 [root@manager1 ~]# docker service ls ID NAME MODE REPLICAS IMAGE xocc6zwdulli web replicated 1/3 httpd:latest [root@manager1 ~]# docker service ls ID NAME MODE REPLICAS IMAGE xocc6zwdulli web replicated 3/3 httpd:latest [root@manager1 ~]# for i in $(cat /etc/hosts | grep manager| awk '{print $1}') > do > ssh root@$i "docker ps -a" > done CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e517f6af9ebd httpd@sha256:d12c036427f436978f2d4397ad2bd6b5b8f7b03003b7a1da084eb228ef25b7d2 "httpd-foreground" 5 minutes ago Up 5 minutes 80/tcp web.2.57p0vzbkqymvak5t5rw6g42k9 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 91dddedf7374 httpd@sha256:d12c036427f436978f2d4397ad2bd6b5b8f7b03003b7a1da084eb228ef25b7d2 "httpd-foreground" 9 minutes ago Up 9 minutes 80/tcp web.1.9x3qvcl5seifoidt5jy4fm3oa CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2a3ade0887f9 httpd@sha256:d12c036427f436978f2d4397ad2bd6b5b8f7b03003b7a1da084eb228ef25b7d2 "httpd-foreground" 5 minutes ago Up 5 minutes 80/tcp web.3.aqlqfena08g9c50tdl5vgb4ju [root@manager1 ~]# docker service ps web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 9x3qvcl5seif web.1 httpd:latest manager2.example.com Running Running 9 minutes ago 57p0vzbkqymv web.2 httpd:latest manager1.example.com Running Running 6 minutes ago aqlqfena08g9 web.3 httpd:latest manager3.example.com Running Running 6 minutes ago
Docker Swarm Service 제거
생성한 서비스의 제거 및 종료는 아래 명령을 통해 가능합니다.
Usage: docker service rm SERVICE [SERVICE...]
[root@manager1 ~]# docker service rm web web [root@manager1 ~]# docker service ls ID NAME MODE REPLICAS IMAGE [root@manager1 ~]# docker service ps web Error: No such service: web
지금까지 Docker Swarm 에서 많이 사용되는 명령어들을 보면서 간단한 웹 서비스를 구성하였습니다.
이제부터는 Build 된 PHP Docker Image를 이용해서 Docker Swarm 을 어떻게 실무에 적용 할 수 있는지 확인해 보도록 하겠습니다.
PHP Demo
Docker Image 관리를 위한 사설 Registry 생성
각 Docker Host 노드에 같은 이미지를 배포 하기 위해서는 두가지 방법이 있습니다.
그 방법은 DockerHub 를 활용하는 방법 및 사설 Registry 를 만들어서 사용하는 방법입니다.
어떤 방법을 사용하는 것이 좋을지는 운영 환경에 맞게 선택을 하는 것이 좋습니다.
이번 PHP Demo 에서는 사설 Registry 를 생성하여 Docker Image 를 관리하도록 하겠습니다.
먼저 Docker Registry 를 생성하기 전에 insecure-registries 옵션을 설정하여 인증되지 않은 Registry를 사용 할 수 있도록 해야됩니다.
이미지를 사용해야되는 모든 노드를 아래와 같이 수정을 합니다. 이후 docker 서비스를 재시작합니다.
# vi /etc/docker/daemon.json { "insecure-registries" : ["manager1.example.com:5000"] } # systemctl restart docker
위와 같이 manager1.example.com 만 선택을 하였는데 Load Balancer 가 있다면 해당 IP 혹은 Domain 명을 추가해도 됩니다.
사설 Registry 를 생성하기 위해서는 아래와 같이 진행합니다.
# docker service create --name registry -p 5000:5000 registry
# docker service create --name registry -p 5000:5000 registry z3gl3pie7xm9vjfyetot9zi3q [root@manager1 ~]# docker service ls ID NAME MODE REPLICAS IMAGE z3gl3pie7xm9 registry replicated 1/1 registry:latest [root@manager1 dockerfile]# docker service ps registry ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS ct6zhchfla8s registry.1 registry:latest manager3.example.com Running Running 6 minutes ago
위와 같이 현재 manager3.example.com Docker Host 에 컨테이너가 실행중인 것을 확인 할 수 있습니다.
Build The Docker Image
아래와 같이 Dockerfile을 생성하여 PHP 서비스가 가능한 Docker Image 를 Build 합니다.
> 참고로 아래 사용된 예제 파일은 github 에서 Clone 할 수 있습니다.
> https://github.com/chhanz/docker-swarm-demo
PHP Demo 에 사용되는 파일 구성 및 내용은 아래와 같습니다.
[root@manager1 docker-swarm-demo]# tree . ├── Dockerfile ├── README.md └── htdocs └── index.php 1 directory, 3 files # vi Dockerfile FROM php:7.2-apache MAINTAINER chhanz <chhan@osci.kr> ADD htdocs/index.php /var/www/html/index.php EXPOSE 80 [root@manager1 docker-swarm-demo]# cat htdocs/index.php <html> <body> <center> <b> <?php $host=gethostname(); echo "Container Name : "; echo $host; ?> <p> Image Version : orignal</p> </b> </center> </body> </html>
제가 포스팅한 내용을 보신 분이라면 Docker Build는 어렵지 않습니다. ㅎㅎ
Image 를 Build 합니다.
# docker build -t phpdemo:v1 .
[root@manager1 docker-swarm-demo]# docker build -t phpdemo:v1 . Sending build context to Docker daemon 4.608 kB Step 1/4 : FROM php:7.2-apache ---> 2424d6c5e6b9 Step 2/4 : MAINTAINER chhanz <chhan@osci.kr> ---> Running in 1257b21144c7 ---> 2beeadfdb912 Removing intermediate container 1257b21144c7 Step 3/4 : ADD htdocs/index.php /var/www/html/index.php ---> 62a4d63e0c2f Removing intermediate container 06a5fe09c5c5 Step 4/4 : EXPOSE 80 ---> Running in 310137303fa5 ---> c62e0ad19807 Removing intermediate container 310137303fa5 Successfully built c62e0ad19807 [root@manager1 docker-swarm-demo]#
Build 가 완료된 Image 를 사설 Registry 에 Push 합니다.
// Docker Image Tag 변경
# docker tag phpdemo:v1 manager1.example.com:5000/phpdemo:v1
// Docker Image Push
# docker push manager1.example.com:5000/phpdemo:v1
[root@manager1 docker-swarm-demo]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE phpdemo v1 c62e0ad19807 18 seconds ago 378 MB docker.io/php 7.2-apache 2424d6c5e6b9 3 days ago 378 MB docker.io/registry <none> d0eed8dad114 12 days ago 25.8 MB [root@manager1 docker-swarm-demo]# docker tag phpdemo:v1 manager1.example.com:5000/phpdemo:v1 [root@manager1 docker-swarm-demo]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE manager1.example.com:5000/phpdemo v1 c62e0ad19807 30 seconds ago 378 MB phpdemo v1 c62e0ad19807 30 seconds ago 378 MB docker.io/php 7.2-apache 2424d6c5e6b9 3 days ago 378 MB docker.io/registry <none> d0eed8dad114 12 days ago 25.8 MB [root@manager1 docker-swarm-demo]# docker push manager1.example.com:5000/phpdemo:v1 The push refers to a repository [manager1.example.com:5000/phpdemo] a0df0b1bee34: Pushed 29f6f251b4d2: Pushed 28255a6692d8: Pushed d9b14cb17d8b: Pushed 725c91d33681: Pushed 005a87a63ac9: Pushed 66fd43b3ea3b: Pushed 20d941ba3638: Pushed eb3e3e0ec224: Pushed 3843f6b0eab9: Pushed 63fc1837f67c: Pushed c68025fbc229: Pushed ec6f4f0a90dc: Pushed 0a07e81f5da3: Pushed v1: digest: sha256:58b33a5f39d60a3f0ba860a1bcbc98f5f767d934c9b1c057cee4b8c1a192fd06 size: 3242 [root@manager1 docker-swarm-demo]#
서비스 배포!
생성된 따끈한 Image 를 이용해서 Docker Swarm Mode 로 서비스를 배포하도록 하겠습니다.
# docker service create --name phpdemo -p 80:80 manager1.example.com:5000/phpdemo:v1
[root@manager1 docker-swarm-demo]# docker service create --name phpdemo -p 80:80 manager1.example.com:5000/phpdemo:v1 mcz67fbul4gmxtjtwc4dvf4n2 // 서비스 시작 중 [root@manager1 docker-swarm-demo]# docker service ls ID NAME MODE REPLICAS IMAGE mcz67fbul4gm phpdemo replicated 0/1 manager1.example.com:5000/phpdemo:v1 z3gl3pie7xm9 registry replicated 1/1 registry:latest [root@manager1 docker-swarm-demo]# docker service ps phpdemo ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS m82bq5rgmk7z phpdemo.1 manager1.example.com:5000/phpdemo:v1 manager2.example.com Running Preparing 7 seconds ago // 서비스 시작 완료 [root@manager1 docker-swarm-demo]# docker service ls ID NAME MODE REPLICAS IMAGE mcz67fbul4gm phpdemo replicated 1/1 manager1.example.com:5000/phpdemo:v1 z3gl3pie7xm9 registry replicated 1/1 registry:latest [root@manager1 docker-swarm-demo]# docker service ps phpdemo ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS m82bq5rgmk7z phpdemo.1 manager1.example.com:5000/phpdemo:v1 manager2.example.com Running Running 2 seconds ago
직접 웹브라우져를 통해 접속해보니 서비스가 정상적으로 작동 되는 것을 확인 할 수 있었습니다.
서비스 복제!
컨터이너 한개로 서비스를 하기에는 안정성이 너무나도 떨어지고 성능 향상을 위해 컨테이너를 복제합니다.
# docker service scale phpdemo=3
[root@manager1 docker-swarm-demo]# docker service ls ID NAME MODE REPLICAS IMAGE mcz67fbul4gm phpdemo replicated 1/1 manager1.example.com:5000/phpdemo:v1 z3gl3pie7xm9 registry replicated 1/1 registry:latest // 서비스 복제 [root@manager1 docker-swarm-demo]# docker service scale phpdemo=3 phpdemo scaled to 3 [root@manager1 docker-swarm-demo]# docker service ls ID NAME MODE REPLICAS IMAGE mcz67fbul4gm phpdemo replicated 3/3 manager1.example.com:5000/phpdemo:v1 z3gl3pie7xm9 registry replicated 1/1 registry:latest [root@manager1 docker-swarm-demo]# [root@manager1 docker-swarm-demo]# docker service ps phpdemo ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS m82bq5rgmk7z phpdemo.1 manager1.example.com:5000/phpdemo:v1 manager2.example.com Running Running 2 minutes ago 09p9qrtxidnw phpdemo.2 manager1.example.com:5000/phpdemo:v1 manager3.example.com Running Running less than a second ago 8x0pcftmzbzw phpdemo.3 manager1.example.com:5000/phpdemo:v1 manager1.example.com Running Running 11 seconds ago [root@manager1 docker-swarm-demo]#
위와 같이 서비스가 복제가 된 것을 확인 할 수 있습니다.
그럼 실제로 어떻게 서비스가 운영되는지 확인해보겠습니다.
3 Replica 서비스
(상기 GIF 파일은 용량이 커서, 출력이 느릴수도 있습니다.)
보시는 것과 같이 각기 다른 컨테이너로 Load Balancing 되는 것을 확인 할 수 있습니다.
위와 같이 Docker Swarm 이 각기 다른 Docker Host를 Load Balancing 를 하는 이유는 아래와 같습니다.
무언가 엄청 복잡해 보이지만 결국은 Ingress Network 를 통해 지정된 포트의 통신은 해당 컨테이너로 자동으로 전달이 될 것입니다.
자세한 Network Architecture 는 아래 Docker Document 를 확인하는 것이 좋습니다.
( https://success.docker.com/article/networking )
서비스 Rolling Update
서비스를 운영하다보면 업데이트가 필요로한 시기가 있습니다.
하지만 운영중에 서비스를 중지하고 업데이트를 하는 것은 서비스 DownTime 이 발생하게 되고 그만큼 운영에 힘들게 됩니다.
우리 Docker Swarm 과 함께라면 운영중에 서비스를 업데이트가 가능합니다!!!
먼저 기존에 만들어진 Docker Image 를 업데이트하도록 하겠습니다.
[root@manager1 docker-swarm-demo]# cat htdocs/index.php <html> <body> <center> <b> <?php $host=gethostname(); echo "Container Name : "; echo $host; ?> <p> Image Version : Update Version v2</p> </b> </center> </body> </html>
핵심 파일인 Index.php 를 수정을 합니다.
[root@manager1 docker-swarm-demo]# docker build -t phpdemo:v2 . Sending build context to Docker daemon 4.608 kB Step 1/4 : FROM php:7.2-apache ---> 2424d6c5e6b9 Step 2/4 : MAINTAINER chhanz <chhan@osci.kr> ---> Using cache ---> 2beeadfdb912 Step 3/4 : ADD htdocs/index.php /var/www/html/index.php ---> 723bb4020994 Removing intermediate container ef8133b39a77 Step 4/4 : EXPOSE 80 ---> Running in 14a08f850b38 ---> 99574ad1473c Removing intermediate container 14a08f850b38 Successfully built 99574ad1473c [root@manager1 docker-swarm-demo]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE phpdemo v2 99574ad1473c 5 seconds ago 378 MB manager1.example.com:5000/phpdemo v1 c62e0ad19807 16 minutes ago 378 MB phpdemo v1 c62e0ad19807 16 minutes ago 378 MB docker.io/php 7.2-apache 2424d6c5e6b9 3 days ago 378 MB docker.io/registry <none> d0eed8dad114 12 days ago 25.8 MB [root@manager1 docker-swarm-demo]#
phpdemo:v2 로 Tag 를 지정하고 신규로 생성된 Image 를 Push 합니다.
[root@manager1 docker-swarm-demo]# docker tag phpdemo:v2 manager1.example.com:5000/phpdemo:v2 [root@manager1 docker-swarm-demo]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE manager1.example.com:5000/phpdemo v2 99574ad1473c About a minute ago 378 MB phpdemo v1 c62e0ad19807 17 minutes ago 378 MB phpdemo v2 99574ad1473c About a minute ago 378 MB manager1.example.com:5000/phpdemo v1 c62e0ad19807 18 minutes ago 378 MB docker.io/php 7.2-apache 2424d6c5e6b9 3 days ago 378 MB docker.io/registry <none> d0eed8dad114 12 days ago 25.8 MB [root@manager1 docker-swarm-demo]# [root@manager1 docker-swarm-demo]# docker push manager1.example.com:5000/phpdemo:v2 The push refers to a repository [manager1.example.com:5000/phpdemo] b246f39fc10a: Pushed 29f6f251b4d2: Layer already exists 28255a6692d8: Layer already exists d9b14cb17d8b: Layer already exists 725c91d33681: Layer already exists 005a87a63ac9: Layer already exists 66fd43b3ea3b: Layer already exists 20d941ba3638: Layer already exists eb3e3e0ec224: Layer already exists 3843f6b0eab9: Layer already exists 63fc1837f67c: Layer already exists c68025fbc229: Layer already exists ec6f4f0a90dc: Layer already exists 0a07e81f5da3: Layer already exists v2: digest: sha256:1542620ce99456e9cc6b8e55998f08707e68d0f7aa8c84a17457e20fd5623caa size: 3242 [root@manager1 docker-swarm-demo]#
그럼 본격적으로 서비스를 운영하면서 변경된 Image 로 서비스 Rolling Update 를 하겠습니다.
방법은 아래와 같습니다.
# docker service update --update-parallelism 1 --image manager1.example.com:5000/phpdemo:v2 phpdemo
--update-parallelism 옵션은 컨테이너 이미지가 한번에 얼마나 변경될지 결정합니다. 0일 경우, 한번에 변경합니다.
[root@manager1 docker-swarm-demo]# docker service update --update-parallelism 1 --image manager1.example.com:5000/phpdemo:v2 phpdemo phpdemo [root@manager1 docker-swarm-demo]# docker service ps phpdemo ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS qo0dxm16hly5 phpdemo.1 manager1.example.com:5000/phpdemo:v2 manager2.example.com Running Running about a minute ago m82bq5rgmk7z \_ phpdemo.1 manager1.example.com:5000/phpdemo:v1 manager2.example.com Shutdown Shutdown about a minute ago z7782l71gnum phpdemo.2 manager1.example.com:5000/phpdemo:v2 manager3.example.com Running Running about a minute ago msiyu6y2gjxn \_ phpdemo.2 manager1.example.com:5000/phpdemo:v1 manager3.example.com Shutdown Shutdown about a minute ago sxp3cs1vmn96 phpdemo.3 manager1.example.com:5000/phpdemo:v2 manager1.example.com Running Running about a minute ago 8x0pcftmzbzw \_ phpdemo.3 manager1.example.com:5000/phpdemo:v1 manager1.example.com Shutdown Shutdown about a minute ago
# docker service ps 명령으로 보면 각 노드에 phpdemo:v2 로 이미지들이 교체가 된 것을 확인 할 수 있습니다.
실제로 아래 그림을 보시면 이해에 도움이 됩니다.
하나씩 신규로 이미지를 교체하면서 서비스를 운영하면서 신규 이미지로 배포가 되는 것을 볼 수 있습니다.
(상기 GIF 파일은 용량이 커서, 출력이 느릴수도 있습니다.)
서비스 Rollback
서비스 Rolling Update 를 진행하였는데 문제가 발생되어 원복을 해야되는 상황이 발생 할 수 있습니다.
Docker Swarm 은 Rollback 기능도 지원하고 있습니다.
Rollback 은 아래와 같이 수행 합니다.
# docker service update --rollback phpdemo
[root@manager1 docker-swarm-demo]# docker service update --rollback phpdemo phpdemo [root@manager1 docker-swarm-demo]# docker service ps phpdemo ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS u1w5rry6wvog phpdemo.1 manager1.example.com:5000/phpdemo:v1 manager1.example.com Running Running 24 seconds ago so0h6oyfdy65 \_ phpdemo.1 manager1.example.com:5000/phpdemo:v2 manager1.example.com Shutdown Shutdown 26 seconds ago yzfysbktouw9 phpdemo.2 manager1.example.com:5000/phpdemo:v1 manager2.example.com Running Running 23 seconds ago i3lqa52jspx4 \_ phpdemo.2 manager1.example.com:5000/phpdemo:v2 manager2.example.com Shutdown Shutdown 24 seconds ago whoukoq2hwor \_ phpdemo.2 manager1.example.com:5000/phpdemo:v1 manager2.example.com Shutdown Shutdown 2 minutes ago z7782l71gnum \_ phpdemo.2 manager1.example.com:5000/phpdemo:v2 manager3.example.com Shutdown Shutdown 3 minutes ago msiyu6y2gjxn \_ phpdemo.2 manager1.example.com:5000/phpdemo:v1 manager3.example.com Shutdown Shutdown 7 minutes ago 9ju17obshxlp phpdemo.3 manager1.example.com:5000/phpdemo:v1 manager3.example.com Running Running 25 seconds ago 26s3p5fthc0f \_ phpdemo.3 manager1.example.com:5000/phpdemo:v2 manager3.example.com Shutdown Shutdown 26 seconds ago 92g40nhfm15n \_ phpdemo.3 manager1.example.com:5000/phpdemo:v1 manager3.example.com Shutdown Shutdown 3 minutes ago sxp3cs1vmn96 \_ phpdemo.3 manager1.example.com:5000/phpdemo:v2 manager1.example.com Shutdown Shutdown 3 minutes ago 8x0pcftmzbzw \_ phpdemo.3 manager1.example.com:5000/phpdemo:v1 manager1.example.com Shutdown Shutdown 7 minutes ago [root@manager1 docker-swarm-demo]#
# docker service ps 명령을 통해 확인해보면 Rollback 된 것을 자세히 확인 할 수 있습니다.
실제로 서비스는 어떻게 Rollback 되는지는 아래 그림을 보면 됩니다.
컨테이너 하나씩 기존 이미지로 Rollback 을 진행 하는 것을 확인 할 수 있습니다.
(상기 GIF 파일은 용량이 커서, 출력이 느릴수도 있습니다.)
Docker Host 장애 발생으로 인한 복구 시나리오
서비스를 운영하다보면 어떠한 이유로 시스템에 장애가 발생되어 서비스가 중단되는 경우가 발생합니다.
Docker Swarm 을 이용하면 서비스 장애에 대해 감지하고 장애가 발생된 노드의 컨테이너를 다른 노드로 이관하여 장애 복구를 진행합니다.
인위적으로 manager2.example.com 의 시스템을 강제로 중지시켜 장애를 발생시키고 어떻게 Docker Swarm 에서 복구하는지 확인 해보겠습니다.
[root@manager1 docker-swarm-demo]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS lrt89xwkugty162qk8c2av5ek manager2.example.com Ready Active Leader y8ul9r3jq0rgt9k3vbvrayeyg * manager1.example.com Ready Active Reachable yqerq5ujds38t0izzlp03dbhd manager3.example.com Ready Active Reachable [root@manager1 docker-swarm-demo]# docker service ps phpdemo ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS a50p5gs82hop phpdemo.1 manager1.example.com:5000/phpdemo:v2 manager2.example.com Running Running about a minute ago 4vwicf8zt7j4 phpdemo.2 manager1.example.com:5000/phpdemo:v2 manager3.example.com Running Running 46 seconds ago 7ik901zrb0ob phpdemo.3 manager1.example.com:5000/phpdemo:v2 manager1.example.com Running Running 51 seconds ago // 노드 2번 시스템 인위적인 장애 발생 [root@manager1 docker-swarm-demo]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS lrt89xwkugty162qk8c2av5ek manager2.example.com Down Active Unreachable y8ul9r3jq0rgt9k3vbvrayeyg * manager1.example.com Ready Active Leader yqerq5ujds38t0izzlp03dbhd manager3.example.com Ready Active Reachable [root@manager1 docker-swarm-demo]# [root@manager1 docker-swarm-demo]# docker service ps phpdemo ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS o32y0ozm5wpz phpdemo.1 manager1.example.com:5000/phpdemo:v2 manager1.example.com Running Running about a minute ago a50p5gs82hop \_ phpdemo.1 manager1.example.com:5000/phpdemo:v2 manager2.example.com Shutdown Running 5 minutes ago 4vwicf8zt7j4 phpdemo.2 manager1.example.com:5000/phpdemo:v2 manager3.example.com Running Running about a minute ago 7ik901zrb0ob phpdemo.3 manager1.example.com:5000/phpdemo:v2 manager1.example.com Running Running about a minute ago [root@manager1 docker-swarm-demo]#
(상기 GIF 파일은 용량이 커서, 출력이 느릴수도 있습니다.)
위 그림을 보시면 장애 감지 및 장애 복구까지 소요된 시간이 약 40~50초 정도가 걸렸습니다.
manager2.example.com 시스템에 장애가 감지되고 해당 시스템에서 실행 중이던 컨테이너는 manager1.example.com 시스템에서 복구가 되는 것을 볼 수 있습니다.
마치며
컨테이너 오케스트레이션 도구 중에 하나인 Docker Swarm 에 대해서 알아보는 시간이 였습니다.
구성이 간단하고 기존에 Docker 를 잘 사용하셨다면 쉽게 운영에 적용 할 수 있을 것 같습니다!!
또한 컨테이너 하나만으로는 부족한 느낌이 많이 없어진 것 같습니다. ^ㅡ^
언제나 쉽게 오픈소스를 사용할 수 있도록 노력하겠습니다.
감사합니다.
참고 자료
- https://docs.docker.com/engine/swarm/
- https://docs.docker.com/engine/reference/commandline/service_update/
- https://www.xenonstack.com/blog/top-trends-ci-cd-devops-tools/
- https://success.docker.com/article/networking
- https://tech.osci.kr/2019/02/13/59736201/
- https://chhanz.github.io/docker/2018/09/10/45749387/