클라우드를 사용한 Docker 실행 환경 구축

15 minute read

Post에 앞서 이번 Post의 내용과 실습은subicura 블로그의 내용과 개념을 그대로 따라해본 것 입니다.

분산 환경에서의 컨테이너 운용 관리

이전 Post에서는 멀티호스트 환경과 클러스터링에 대해서 얘기하였다.
이제 더 나아가서 멀티호스트로 구성된 실제 환경을 클러스터 구성으로 가동시키려면 컨테이너의 시작 및 정지와 같은 조작뿐만 아니라 호스트 간의 네트워크 연결이나 스토리지 관리, 컨테이너를 어떤 호스트에서 가동할지와 같은 스케줄링, 컨테이너가 정상적으로 작동하고 있는지 아닌지를 감시할 장치도 필요하다.
이러한 기능을 갖추고 컨테이너를 통합 관리할 수 있는 툴을 컨테이너 오케스트레이션 툴 이라고 한다.

컨테이너 오케스트레이션 툴 종류

  1. Kubenetes: Google의 엔지니어를 중심으로 하는 커뮤니티에서 개발 진행
    제공하는 기능도 풍부하고 개발 속도도 빠르며, 대규모 시스템에서의 도입 실적도 풍부하다.
    컨테이너 오케스트레이션 툴의 실질적 스탠드라고 할 수 있다.
    (Kubernete에 관련되서는 따로 공부해서 하나의 Category로서 Post할 생각입니다.)
  2. Docker Engine(Swarm): Docker에서 클러스터링 기능을 제공하는 Swarm모드 이다.
    여러개의 컨테이너를 멀티호스트 환경에서 작동시키고, 그 컨테이너들을 모아서 하나의 명령으로 조작할 수 있다.
    (현재 Post에서는 Swarm을 오케스트레이션 툴로서 선정하고 실습한다.)
  3. Apache Mesos, Marathon: 여서 호스트의CPU나 메모리, 디스크를 추상화하여 하나의 리소스 풀로서 다룰 수 있는 것이 특징이다.
    단, Mesos를 사용하여 컨테이너 오케스트레이션을 가동시키려면 별도의 컨테이너 고나리용 프레임워크가 필요하다.
    이러한 대표적인 프레임워크로는 Marathon이 있고, 이름 그대로 장기간에 걸쳐 계속 작동하는 애플리케이션의 실행이나 모니터링이 가능하다.


참고사항: 용어 정리
컨테이너 오케스트레이션의 기능에 대해서 정확한 개념과 용어의 의미가 부족해서 찾아본 결과이다.

스케줄링: 컨테이너를 적당한 서버에 배포해 주는 작업입니다. 툴에 따라서 지원하는 전략이 조금씩 다른데 여러 대의 서버 중 가장 할일 없는 서버에 배포하거나 그냥 차례대로 배포 또는 아예 랜덤하게 배포할 수도 있습니다. 컨테이너 개수를 여러 개로 늘리면 적당히 나눠서 배포하고 서버가 죽으면 실행 중이던 컨테이너를 다른 서버에 띄워주기도 합니다.

클러스터링: 여러 개의 서버를 하나의 서버처럼 사용할 수 있습니다. 클러스터에 새로운 서버를 추가할 수도 있고 제거할 수도 있습니다. 작게는 몇 개 안 되는 서버부터 많게는 수천 대의 서버를 하나의 클러스터로 만들 수 있습니다. 여기저기 흩어져 있는 컨테이너도 가상 네트워크를 이용하여 마치 같은 서버에 있는 것처럼 쉽게 통신할 수 있습니다.

서비스 디스커버리: 말 그대로 서비스를 찾아주는 기능입니다. 클러스터 환경에서 컨테이너는 어느 서버에 생성될지 알 수 없고 다른 서버로 이동할 수도 있습니다. 따라서 컨테이너와 통신을 하기 위해서 어느 서버에서 실행중인지 알아야 하고 컨테이너가 생성되고 중지될 때 어딘가에 IP와 Port같은 정보를 업데이트해줘야 합니다. 키-벨류 스토리지에 정보를 저장할 수도 있고 내부 DNS 서버를 이용할 수도 있습니다.

로깅, 모니터링: 여러 대의 서버를 관리하는 경우 로그와 서버 상태를 한곳에서 관리하는게 편합니다. 툴에서 직접 지원하는 경우도 있고 따로 프로그램을 설치해야 하는 경우도 있습니다. ELK와 prometheus등 다양한 툴이 있습니다.


Docker Swarm 용어 정리

Docker Swarm에 들어가기 앞서 Docker Swarm에서 사용하는 용어에 대해 정리하고 실습을 하자.

용어 설명
스웜(Swarm) 군중이라는 의미로서 스웜 클러스터 자체를 스웜이라 한다.(스웜을 만들다 = 클러스터를 만들다, 스웜에 가입하다 = 클러스테어 가입하다.)
노드(Node) 스웜 클러스터에 속한 도커 서버의 단위이다. 보통 한 서버에 하나의 도커데몬만 실행하므로 서버가 곧 노드이다. 노드의 종류는 매니저 노드와 워커 노드가 있다.
매니저노드(Manage Node) 스웜 클러스터 상태를 관리하는 노드. 매니저 노드는 곧 워커노드가 될 수 있으나, 워커노드와의 차이점은 스웜 명령어는 매니저 노드에서만 실행된다.
워커노드(Worker Node) 매니저 노드의 명령을 받아 컨테이너를 생성하고 상태를 체크하는 노드
서비스(Service) 기본적인 배포 단위, 하나의 서비스는 하나의 이미지를 기반으로 생성하고 동일한 컨테이너를 한개 이상 실행할 수 있다.
테스크(Task) 컨테이너 배포 단위, 하나의 서비스는 여러개의 테스크를 실행할 수 있고 각각의 테스크가 컨테이너를 관리



Docker Swarm 기능 정리

위에서 컨테이너 오케스트레이션의 기능으로서 크게 스케줄링, 클러스터링, 서비스 디스커버리, 로깅, 모니터링 으로서 나누었다.
이러한 기능이 Docker Swarm에서는 어떻게 적용되는지 알아보고 추가적으로 다른 기능에 대해서도 알아보자.

스케줄링(Scheduling): 서비스를 만들면 컨테이너를 워커노드에 배포한다. 노드에 라벨을 지정하면 특정 노드에만 배포할 수 있고 모든 서버에 한 대씩 배포하는 기능도 제공한다. 서비스별로 CPU, Memory사용량을 미리 정의할 수 있다.

고가용성(High Available): 여러개의 매니저 노드를 운영할 수 있다. 만약 3대의 매니저 노드를 사용하면 1대가 죽어도 클러스터는 정상적으로 동작하며 매니저 노드를 지정하는 방법은 간단하므로 쉽게 관리할 수 있다.

멀티 호스트 네트워크(Multi Host Network): Overlay network로 불리는 SDN(Software Defined Network)를 지원하며 여러 노드에 분산된 컨테이너를 하나의 네트워크로 묶을 수 있다. 컨테이너마다 독립된 IP가 생기고 서로 다른 노드에 있어도 할당된 IP로 통신할 수 있다.

서비스 디스커버리(Service Discovery): 자체 DNS 서버를 가지고 컨테이너를 생성하면 서비스명과 동일한 도메인을 등록하고 컨테이너가 멈추면 도메인을 제거한다. 여러 노드에 분산된 컨테이너가 멀티호스트 네트워크로 묶이기 때문에 DNS를 가지고 바로 접근할 수 있다.

순차적 업데이트(Rolling Update): 서비스를 새로운 이미지로 업데이트 하는 경우 하나하나 차례대로 업데이트 한다. 동시에 업데이트하는 작업의 개수와 업데이트 간격 시간을 조정 가능하다.

상태체크(Health Check): 서비스가 정상적으로 실행되었는지 확인하기 위해 컨테이너 실행 여부 뿐 특정 쉘 스크립트가 정상적으로 실행됐는지 여부를 추가로 체크 가능. 컨테이너 실행 여부로만 체크한 경우 아직 서버가 실행 되지 않아 접속시 오류가 날 수 있는 미묘한 타이밍을 잡는데 효과적이다.

비밀값 저장(Secret Management): 비밀번호를 스웜 어딘가에 생성하고 컨테이너에서 읽을 수 있다. 비밀 값을 관리하기 위한 외부 서비스를 설치하지 않고 쉽게 이용 가능하다.

로깅(Logging): 같은 노드에서 실행 중인 컨테이너뿐 아니라 다른 노드에서 실행 중인 서비스의 로그를 한곳에서 볼 수 있다. 특정 서비스의 로그를 보려면 어느 노드에서 실행 중인지 알 필요도 없고 일일이 접속하지 않아도 된다.

모니터링(Monitoring): 리소스 모니터링 기능은 제공하지 않는다. 3rd party 서비스(prometheus, grafana)를 사용해야 한다



Docker Swarm 준비

현재 Linux기반의 Ubuntu(CLI)에서 실습 환경을 구축하였습니다.
1. VritualBox 설치

#VirtualBox 설치
apt-get install virtual box

#VirtualBox 설치 확인
vboxmanage --version

5.2.32_Ubuntur132056


2. Vagrant 설치
Vagrant 는 VirtualBox, VMWare, Parallels같은 가상머신을 쉽게 만들고 관리해주는 툴 이다.

#Vagrant 설치
wget -c https://releases.hashicorp.com/vagrant/2.2.4/vagrant_2.2.4_x86_64.deb
sudo dpkg -i vagrant_2.2.4_x86_64.deb

#Vagrant 설치 확인
vagrant -v

Vagrant 2.2.4


3. vargrant-hostsupdater 설치
vargrant-hostsupdater는 vargrant up할때 yml파일에 정의된 ip와 host명을 자동으로 hosts파일에 추가하고, vargrant halt하면 자동으로 삭제 해주는 플러그인 이다.

#vargrant-hostsupdater 설치
vagrant plugin install vagrant-hostsupdater

Installing the 'vagrant-hostsupdater' plugin. This can take a few minutes...
Fetching: vagrant-hostsupdater-1.1.1.160.gem (100%)


4. 데모 파일 다운로드
subicura Git에 접속하여 Docker swarm demo파일 다운로드

git clone https://github.com/subicura/docker-swarm-demo.git

cd docker-swarm-demo


5. 가상 Machine 생성
vargrant-hostsupdater로 인하여 DockerFile에 정의된 ip와 host명을 자동으로 할당하여 Dockerfile에 정의된 Machine을 만들게 된다.

#Dockerfile을 기반으로 Machine 생성
vagrant up
Bringing machine 'core-01' up with 'virtualbox' provider...
Bringing machine 'core-02' up with 'virtualbox' provider...
Bringing machine 'core-03' up with 'virtualbox' provider...
==> core-01: Box 'coreos-alpha' could not be found. Attempting to find and install...
    core-01: Box Provider: virtualbox
    core-01: Box Version: >= 0
    
...

#상태 확인
vagrant status

Current machine states:

core-01                   running (virtualbox)
core-02                   running (virtualbox)
core-03                   running (virtualbox)

This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.



Docker Swarm 클러스터

현재 core-01 ~ core-03까지의 3개의 가상머신이 생성되었다.
하나의 매니저 노드와 매니저 노드가 생성한 토큰을 가지고 워커 노드에서 매니저 노드로 접속하면 된다.

1. 매니저 노드 ip address알아오기
현재 core-01을 매니저 노드로 지정하기 위하여 ip address를 알아야 한다.
vagrant ssh core-01을 통하여 core-01에 접속한 뒤 ifconfig를 통하여 ip address를 알아온다.

core@core-01 ~ $ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255

...

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.8.101  netmask 255.255.255.0  broadcast 172.17.8.255

...



2. core-01 서버를 매니저 노드로 설정
swarm init명령어를 사용하여 core-01 서버를 매니저 노드로 설정

core@core-01 ~ $ docker swarm init --advertise-addr 172.17.8.101

Swarm initialized: current node (mgf0nk5ez63v5eltq08q0h1kr) is now a manager.

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

docker swarm join --token SWMTKN-1-11b1y84rzrw6ceaw0kwuq9r2aule3pge3jn1d60zsm8lul7bfl-cldzdrz4sjilc4uqsfkd3irum 172.17.8.101:2377

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



3. core-02,core-03 서버를 워크 노드로 설정
core-02, core-03에 ssh로 접속하여 docker swarm join --tocken [토큰] [IP Address]을 통하여 매니저 노드에 join한다. 이러한 join과정을 통하여 각각의 서버는 워크 노드가 된다.

#core-02접속 후 실행
core@core-02 ~ $ docker swarm join --token SWMTKN-1-11b1y84rzrw6ceaw0kwuq9r2aule3pge3jn1d60zsm8lul7bfl-cldzdrz4sjilc4uqsfkd3irum 172.17.8.101:2377

This node joined a swarm as a worker.

#core-03접속 후 실행
core@core-03 ~ $ docker swarm join --token SWMTKN-1-11b1y84rzrw6ceaw0kwuq9r2aule3pge3jn1d60zsm8lul7bfl-cldzdrz4sjilc4uqsfkd3irum 172.17.8.101:2377
This node joined a swarm as a worker.

This node joined a swarm as as worker.



4. 클러스터 상태 확인
docker node ls명령어를 토애 워커노드와 매니저 노드가 정상적으로 만들어 졌는지 확인 가능하다.

core@core-01 ~ $ docker node ls


ID HOSTNAME STATUS AVAILBILITY MANAGER STATUS ENGINE VERSION
mgf0nk5ez63v5eltq08q0h1kr * core-01 Ready Active Leader 18.06.3-ce
meq50fs2ab6vitw7xiaz7begu core-02 Ready Active 18.06.3-ce
kyjx0pfd5n62yoijec66ei6lm core-03 Ready Active 18.06.3-ce


참고사항
매니저 Node가 관리하는 config files는 /var/lib/docker/swarm에 저장된다.

위와 같은 구성이 끝나면 아래와 같은 사진으로서 표현할 수 있는 Cluster가 설정된 것 이다.
virtual machines 그림출처: subicura 블로그


기본 웹 애플리케이션

서비스 생성
간단한 웹 애플리케이션 서비스를 생성한다.
서비스를 생성하려면 docker service create로서 생성한다.

core@core-01 ~ $ docker service create --name whoami \
>   -p 4567:4567 \
>   subicura/whoami:1

l0ffrznqid7n58junwfmfzrtp
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged

subicurawhoami는 hostname을 출력하는 단순한 웹 애플리케이션 이다.
Port는 4567로서 Open하였다.

서비스 확인
docker service ls

core@core-01 ~ $ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
l0ffrznqid7n        whoami              replicated          1/1                 subicura/whoami:1   *:4567->4567/tcp



상세한 정보 확인
docker service pswhoami

core@core-01 ~ $ docker service ps whoami
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
ok5hp0p7yr0b        whoami.1            subicura/whoami:1   core-02             Running             Running 2 minutes ago  


core-01에서 실행하였지만 Cluster로 구성하여서 자동으로 core-02에서 서비스가 실행되는 것을 알 수 있다.

HTTP 요청으로 Test
curl 명령어를 통하여 HTTP요청을 보낸뒤 확인

#core-01에 요청
core@core-01 ~ $ curl core-01:4567

d3b0456933b3

#core-02에 요청
core@core-01 ~ $ curl core-02:4567

d3b0456933b3

#core-0d에 요청
core@core-01 ~ $ curl core-03:4567

d3b0456933b3


요청 결과를 확인하면 Service는 core-02에서 실행되고 있지만 core-01 ~ core-03까지 모든 노드에서 응답하는 것을 알 수 있다.


Ingress Network

도커 스웜은 서비스를 외부에서 쉽게 노출하기 위하여 모든 노드가 ingress라는 가상 네트워크에 속해 있다.
ingress는 routung mesh라는 서비스가 포트를 오픈할 경우 모든 노드에 포트가 오픈되고 어떤 노드에 요청을 보내도 실행 중인 컨테이너에 자동으로 전달해 준다.
그림출처: subicura 블로그

위의 예제에서 subicura/whoami라는 Service를 실행할 때 Port 4567을 Open하였기 때문에 어디에서 테스트를 하던간에 core-02노드에 실행된 컨테이너로 요청이 전달된다.
만약 컨테이너가 여러개라면 내부 로드밸런스를 이용하여 여러개의 컨테이너로 분산처리된다.


서비스 복제 replication

웹 애플리케이션에 부하가 발생했다고 가정하고 컨테이너를 5개로 늘린본다.
노드는 3개인데 컨테이너를 5개를 늘리면 2개의 서버에는 컨테이너2개, 1개의 서버에는 컨테이너1개가 생성된다.
각각의 컨테이너는 독립되어 있으므로 여러개를 생성해도 상관없고 ingress네트워크를 통해 요청을 분산 처리한다.
그림출처: subicura 블로그

서비스의 개수 증가
docker service scale [서비스 명]=[서비스 개수]

#서비스의 개수 5개로 증가
core@core-01 ~ $ docker service scale whoami=5

whoami scaled to 5
overall progress: 5 out of 5 tasks
1/5: running   [==================================================>]
2/5: running   [==================================================>]
3/5: running   [==================================================>]
4/5: running   [==================================================>]
5/5: running   [==================================================>]
verify: Service converged

#서비스 상태 확인
core@core-01 ~ $ docker service ps whoami


ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
ok5hp0p7yr0b cwhoami.1 subicura/whoami:1 core-02 Running Running about an hour ago
baztiqbws22p cwhoami.2 subicura/whoami:1 core-01 Running Running about a minute ago
kg9gm18xt2vn cwhoami.3 subicura/whoami:1 core-01 Running Running about a minute ago
ufn3g86114q8 cwhoami.4 subicura/whoami:1 core-01 Running Running about a minute ago
plhb8hi9x9tj cwhoami.5 subicura/whoami:1 core-01 Running Running about a minute ago


서비스 상태 확인

core@core-01 ~ $ curl core-01:4567
1dc273d198d2
core@core-01 ~ $ curl core-01:4567
fcc31bae1093
core@core-01 ~ $ curl core-01:4567
0b66ae7d26f3
core@core-01 ~ $ curl core-01:4567
2103d6c1434d
core@core-01 ~ $ curl core-01:4567
d3b0456933b3


5개의 컨테이너에게 요청이 분산된 것을 알 수 있다.
아무런 설정 없이 ingress 네트워크가 알아서 로드 밸런서 역할을 해주고 있다.

참고사항: 로드밸런서
Loab Balacer란여러 대의 Server에게 균등하게 Traffic을 분산시켜주는 역할을 하는 것 이다.



HEALTHCHECK

그림출처: subicura 블로그

Docker Swarm은 컨테이너가 실행되면 ingress에서 해당 컨테이너로 요청을 보내기 시작하는데 웹 서버가 부팅되는 동안 문제가 발생한다.
ingress는 컨테이너가 실행되면 요청을 보내기 때문에 문제가 없을 것이라고 판단하지만 컨테이너가 실행되고 웹 서버가 완전히 실행되기 전에 요청을 보내면 서버를 찾을 수 없다는 메세지를 볼 수 있고 이러한 문제를 해결하기 위해 좀 더 자세한 상태 체크 방식이 필요하다.

위에서 사용한 subicura/whoami:1과 subicura/whoami:2의 차이점은 HEALTHCHECK의 유무이다.
다음 subicura/whoami:2 Image를 Dockerfile로 정의한 내용이다.

FROM ruby:2.3-alpine
MAINTAINER subicura@subicura.com
COPY Gemfile* /usr/src/app/
WORKDIR /usr/src/app
RUN bundle install
COPY . /usr/src/app
EXPOSE 4567
HEALTHCHECK --interval=10s CMD wget -qO- localhost:4567
CMD bundle exec ruby app.rb -o 0.0.0.0


위의 과정을 Dockerfile로서 얻을 수 있는 정보는 10초마다 wget을 요청하여 정상적인 응답이 있을때마다 Update를 진행하게 된다.
즉, 하나의 서버씩 Update하는 Rolling Update가 이루워 진다.
이러한 방식은 단순하게 한 대씩 재시작한다.
다만, 코드 변경에 따른 side effect가 발생할 수 있다.
이러한 side effect를 해결하기 위해서는 블루 그린 배포를 사용한다.
(참고로 블루 그린 배포는 Kubernetes에서 지원한다.)
배포방식 자세한 내용
위와같은 Service의 업데이트는 docker service update를 통하여 이루워 질 수 있다.

core@core-01 ~ $ docker service update \
--image subicura/whoami:2 \
whoami


Update후 상태 확인

core@core-01 ~ $ docker service ps whoami

ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
ri4d8ujsid9r        whoami.1            subicura/whoami:2   core-02             Running             Running 6 minutes ago
ok5hp0p7yr0b         \_ whoami.1        subicura/whoami:1   core-02             Shutdown            Shutdown 6 minutes ago
6jjiv19istjr        whoami.2            subicura/whoami:2   core-01             Running             Running 7 minutes ago
baztiqbws22p         \_ whoami.2        subicura/whoami:1   core-01             Shutdown            Shutdown 7 minutes ago
9y2f2yqsjjea        whoami.3            subicura/whoami:2   core-01             Running             Running 7 minutes ago
kg9gm18xt2vn         \_ whoami.3        subicura/whoami:1   core-03             Shutdown            Shutdown 7 minutes ago
nsmbnffpdotv        whoami.4            subicura/whoami:2   core-03             Running             Running 5 minutes ago
ufn3g86114q8         \_ whoami.4        subicura/whoami:1   core-03             Shutdown            Shutdown 6 minutes ago
du5bpwago2k3        whoami.5            subicura/whoami:2   core-02             Running             Running 6 minutes ago
plhb8hi9x9tj         \_ whoami.5        subicura/whoami:1   core-02             Shutdown            Shutdown 6 minutes ago



방문자수 체크 웹 애플리케이션

redis와 함께 웹 애플리케이션을 실행하고 서버에 접속할 때마다 카운트 +1하는 서비스를 생성
먼저 웹 애플리케이션과 redis가 통신할 수 있는 오버레이 네트워크를 생성한다.
오버레이 네트워크를 사용하면 redis는 외부에 포트를 오픈하지 않아도 되고 웹 애플리케이션과 다른 노드에 있어도 같은 서버에 있는 것처럼 통신할 수 있다.
그림출처: subicura 블로그

네트워크 생성
docker network create를 통하여 오버레이 네트워크를 생성한다.

core@core-01 ~ $ docker network create --attachable \
  --driver overlay \
  backend
  
urjb325chpg1hr7lvcgu1kjex


네트워크 확인
docker network ls

core@core-01 ~ $ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
urjb325chpg1        backend             overlay             swarm
82fb3510c698        bridge              bridge              local
e6e2de224b77        docker_gwbridge     bridge              local
7ade34d33f04        host                host                local
ppymzsz9uejx        ingress             overlay             swarm
bf03ff81e303        none                null                local


기본적인 Network + 생성한 urjb325chpg1 overlay network를 살펴볼 수 있다.

redis 생성
그림출처: subicura 블로그

생성한 네트워크와 연결하는 redis Service를 생성한다.

core@core-01 ~ $ docker service create --name redis \
  --network=backend \
  redis
  
l0rak05zjtgesih4x76xmina5
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged


redis 확인
현재 redis의 네트워크는 외부 네트워크에서는 접속할 수 없고 backend 네트워크 상에서 원래 포트인 6379로 접속할 수 있다.

core@core-01 ~ $ docker run --rm -it \
  --network=backend \
  alpine \
  telnet redis 6379


참고사항
–rm은 일시적으로 컨테이너를 생성하는 방법이다.
-i은 interactive라는 뜻으로 컨테이너와 상호적으로 주고받고 하겠다는 뜻
-t은 tty를 사용하겠다는 의미이다.

애플리케이션 설정
그림출처: subicura 블로그

다음과 같은 명령어로서 Redis와 Counter라는 Service가 Backend Overlay Network를 통하여 통신하도록 설정

core@core-01 ~ $ docker service create --name counter \
  --network=backend \
  --replicas 3 \
  -e REDIS_HOST=redis \
  -p 4568:4567 \
  subicura/counter
  
ikl1t03e521i65ru2ap09bfff
overall progress: 3 out of 3 tasks
1/3: running   [==================================================>]
2/3: running   [==================================================>]
3/3: running   [==================================================>]


위의 명령어를 통하여 counter라는 Service를 --replicas 3을 통하여 3개를 설정하였다.
이러한 Service3개는 스웜에 의하여 각각의 Node에 한개의 Service를 자동 할당하였다.
외부의 포트 4568을 개방하였으며 Network는 이전에 정의한 backend를 사용한다.

테스트

core@core-01 ~ $ curl core-01:4568
abd752828052 > 1
core@core-01 ~ $ curl core-01:4568
abd752828052 > 1
4bc21a61f18c > 1
core@core-01 ~ $ curl core-01:4568
514ed14e7d5e > 1
abd752828052 > 1
4bc21a61f18c > 1
core@core-01 ~ $ curl core-01:4568
514ed14e7d5e > 1
abd752828052 > 2
4bc21a61f18c > 1
core@core-01 ~ $ curl core-01:4568
514ed14e7d5e > 1
abd752828052 > 2
4bc21a61f18c > 2
core@core-01 ~ $ curl core-01:4568
514ed14e7d5e > 2
abd752828052 > 2
4bc21a61f18c > 2


위의 결과로서 웹 애플리케이션 서버와 redis가 backend 오버레이 네트워크를 통해 연결되었고 ingress 네트워크가 3개의 웹 컨테이너에 작업을 분산하였다.

즉, 스웹은 서로 통신이 필요한 서비스를 같은 이름의 오버레이 네트워크로 묶고 네부 DNS서버를 이용하여 접근할 수 있다. 여러 개의 네트워크를 쉽게 만들 수 있고 하나의 서비스는 여러 개의 네트워크에 속할 수 있다. 모든 것은 스웜이 알아서 하고 관리자는 네트워크와 서비스만 잘 만들면 된다.



Docker의 기밀정보로 민감한 데이터 관리

Docker Swarm 서비스와 관련하여 암호, SSH 개인 키, SSL 인증서 또는 네트워크를 통해 전송되거나 Dockerfile이나 응용프로그램에 암호화되지 않은 다른 데이터 조각과 같은 데이터 묶음이다.
Docker 1.13이상에서는 Docker secret를 사용하여 이 데이터를 중앙에서 관리하고 엑세스 권한이 필요한 컨테이너에게만 안전하게 전송할 수 있다.

Docker secret예제
1. Docker에게 비밀키 생성: docker secret create명령은 파일을 나타내는 마지막 인수가 - 로 설정되어 있기 때문에 표준 입력을 읽는다.

core@core-01 ~ $ echo "this is my password!" | docker secret create my-password -

2d2lgydukbe0q93g0kfmmo9n8


위의 Code의 결과로 인하여 my-passward라는 이름의 비밀키에 this is my password!라는 내용을 저장하게 되었다.

2. secret 서비스 생성: 서비스를 생성하고 --secret옵션을 활용하여 비밀키에 대한 엑세스 권한 부여

core@core-01 ~ $ docker service create --name secret \
  --secret my-password \
  -p 4569:4567 \
  -e SECRET_PATH=/run/secrets/my-password \
  subicura/secret
  
p0ncqotfh3754jrmk5mj7dk2c
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged


--secret옵션을 활용하여 service를 생성하게 되면 run/secrest디렉토리 밑에 키 이름의 파일로 마운트 된다.

3. secret service 생성 확인: docker service ps를 통하여 생성된 secret service를 확인한다.

core@core-01 ~ $ docker service ps secret
ID                  NAME                IMAGE                    NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
zpurg7z73gza        secret.1            subicura/secret:latest   core-01             Running             Running 2 minutes ago


4. 실제 디렉토리 에서 내용 읽어오기

  • docker ps를 사용하여 container의 ID를 가져온다.
core@core-01 ~ $ docker ps --filter name=secret -q

a9889d17676c


  • docker exec를 사용하여 외부에서 컨테이너 안의 명령을 실행한다. 실제 /run/secrets디렉토리 안에 비밀키가 생성되었는지 확인한다.
core@core-01 ~ $ docker exec $(docker ps --filter name=secret -q) ls -l /run/secrets
total 4
-r--r--r--    1 root     root            21 Oct 16 06:58 my-password


  • docker exec를 사용하여 외부에서 컨테이너 안의 명령을 실행한다. 실제 /run/secrets디렉토리 안에 my-passward라는 파일의 내용을 읽어온다.
core@core-01 ~ $ docker exec $(docker ps --filter name=secret -q) cat /run/secrets/my-password

this is my password!


참고사항
현재 생성한 subicura/secret라는 Service는 외부 포트 4569를 통하여 위의 과정과 같은 결과를 알 수 있다.

core@core-01 ~ $ curl core-01:4569

this is my password!



5. 컨테이너의 변경 사항을 새로운 이미지로 저장뒤 비밀키에 접근: docker commit으로 새로운 이미지를 생성 후 /run/secrets/my-password에 접근하여 파일을 읽어 온다.

  • 새로운 이미지 생성
core@core-01 ~ $ docker commit $(docker ps --filter name=secret -q) committed_secret
sha256:f8fc38021d238f006d13f76b0af232f79be3a7c4efaaec417e5f52457ecb9445


  • 서비스 컨테이너 생성 후 /run/secrets/my-password에 접근하여 비밀 키 내용 읽어오기
#비밀 키 파일 확인
core@core-01 ~ $ docker run --rm -it committed_secret ls /run/secrets/

my-password

#비밀 키 내용 읽어오기
core@core-01 ~ $ docker run --rm -it committed_secret cat /run/secrets/my-password

#실행 결과 아무것도 안나오는 것을 알 수 있다.



6. 비밀 키 제거: 비밀 키 목록 확인 후 비밀키 제거

#비밀키 목록 확인
core@core-01 ~ $ docker secret ls

ID                          NAME                DRIVER              CREATED             UPDATED
2d2lgydukbe0q93g0kfmmo9n8   my-password                             44 minutes ago      44 minutes ago

#비밀키 제거
core@core-01 ~ $ docker secret rm my-password

Error response from daemon: rpc error: code = InvalidArgument desc = secret 'my-password' is in use by the following service: secret


현재 secret에서 my-password 비밀키를 사용중이므로 삭제할 수 없다.

7. Service에서 비밀 키 제거: my-password비밀키를 사용중인 Service에서 비밀키 사용 해제

#Service(Secret)에서 my-passward 비밀 키 삭제
core@core-01 ~ $ docker service update --secret-rm my-password secret

secret
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged

#삭제 확인
core@core-01 ~ $ docker exec $(docker ps --filter name=secret -q) ls /run/secrets/

my-password

core@core-01 ~ $ docker exec $(docker ps --filter name=secret -q) cat /run/secrets/my-password

#확인 결과 비밀키 파일은 존재하나 읽을 수 없는 것을 확인할 수 있다.



8. 비밀키 제거: 비밀키를 사용중인 Service와 비밀키의 관계를 없앴음으로 비밀키 제거 가능

#비밀키 제거
core@core-01 ~ $ docker secret rm my-password
my-password

#제거 확인
core@core-01 ~ $ docker secret ls
ID                  NAME                DRIVER              CREATED             UPDATED




참조: 완벽한 IT 인프라 구축을 위한 Docker
참조:subicura 블로그
참조:sauru 블로그
참조:code-examples
코드에 문제가 있거나 궁금한 점이 있으면 wjddyd66@naver.com으로 Mail을 남겨주세요.

Categories:

Updated:

Leave a comment