본문 바로가기

클라우드/도커

서비스와 스택

반응형

서비스

단일 도커 호스트에 대한 컨테이너 배포는 docker container run 명령으로 컨테이너를 일일히 실행하거나 컴포즈를 사용해 여러 컨테이너를 동시에 실행하는 방법이 있다.

어떤 특정한 문제를 해결하기 위해 만들어진 애플리케이션은 단일 컨테이너 혹은 여러 컨테이너로 구성될 수도 있으며 그것들이 복제된 집합으로 이루어졌을 수도 있다. 이렇게 애플리케이션을 구성하는 일부 컨테이너를 제어하기 위한 단위로 서비스라는 개념이 생겨났다.

$ docker container exec -it manager \
> docker service create --replicas 1 --publish 8000:8000 --name echo registry:5000/example/echo:latest
hbp13rv25bk0yo8em0kufpjpk
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged

 위와 같이 서비스는 manager 컨테이너에서 docker service create 명령으로 생성한다. 

서비스를 제어하는 레플리카를 늘려보자. docker service scale 명령으로 해당 서비스의 컨테이너 수를 늘리거나 줄일 수 있다. 여러 노드에 걸쳐 컨테이너 수를 조정할 수 있으므로 스케일 아웃을 적용할 때 유용하다. 

$ docker container exec -it manager docker service scale echo=6
echo scaled to 6
overall progress: 6 out of 6 tasks
1/6: running   [==================================================>]
2/6: running   [==================================================>]
3/6: running   [==================================================>]
4/6: running   [==================================================>]
5/6: running   [==================================================>]
6/6: running   [==================================================>]
verify: Service converged

스웜 클러스터 위에서 동작하는 컨테이너를 확인해 보았을 때, echo 컨테이너 6개가 실행 중이다. NODE 칼럼을 통해서 서비스가 스웜 클러스터의 노드를 분산 배치했음을 알 수 있다.

$ docker container exec -it manager docker service ps echo | grep Running
jk1uln3wxq1b        echo.1              registry:5000/example/echo:latest   760fa825ec6b        Running             Running 3 minutes ago
zsodk5p9pcie        echo.2              registry:5000/example/echo:latest   469231dcd4dc        Running             Running about a minute ago
z5e6wjel4bay        echo.3              registry:5000/example/echo:latest   ce8f7af60cff        Running             Running about a minute ago
nmxq3c0y0wtb        echo.4              registry:5000/example/echo:latest   ce8f7af60cff        Running             Running about a minute ago
yuvpkt3xt5v4        echo.5              registry:5000/example/echo:latest   760fa825ec6b        Running             Running about a minute ago
pqoysqluso4r        echo.6              registry:5000/example/echo:latest   7e4ff2b8f9d5        Running             Running about a minute ago

배포된 서비스는 docker service rm 서비스명 명령으로 삭제할 수 있다. 

$ docker container exec -it manager docker service rm echo
echo
$ docker container exec -it manager docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS

서비스가 레플리카 수를 늘리라고 지시하면 자동으로 컨테이너를 복제하고 이를 여러 노드에 배치한다.

 

스택

스택은 하나 이상의 서비스를 그룹으로 묶은 단위로, 애플리케이션 전체 구성을 정의한다. 여러 서비스를 사용하게 되면 여러 이미지를 다룰 수 있어서 다양한 애플리케이션을 구성할 수 있다. 스택은 말하자면 스웜에서 동작하는 스케일 인, 스케일 아웃, 제약 조건 부여가 가능한 컴포즈다. 

스택을 사용해 배포된 서비스 그룹은 overlay 네트워크에 속한다. 스택에서 overlay 네트워크를 설정하지 않으면 스택마다 서로 다른 overlay 네트워크를 생성하고 그 안에 서비스 그룹이 속하게 된다. 어떤 서비스가 다른 overloay 네트워크에 속한 다른 서비스를 발견할 수 없으므로 통신도 불가능하다.

*) overlay 네트워크: 여러 도커 호스트에 걸쳐 배포된 컨테이너 그룹을 같은 네트워크에 배치하기 위한 기술

클라이언트와 대상 서비스가 같은 overlay 네트워크에 있으면 통신이 가능하다. 다음과 같이 overlay 네트워크 ch03을 구성한 다음, 스택으로 만든 각 서비스를 소속시킨다. 스택 역시 스웜과 마찬가지로 manager 컨테이너에서 조작한다.

$ docker container exec -it manager docker network create --driver=overlay --attachable ch03

stack 디렉터리에 다음과 같이 ch03-webapi.yml 스택을 생성한다. 이 컨테이너는 환경 변수 BACKEND_HOST에 요청을 전송할 대상을 설정할 수 있는데, 스택으로 배포된 api 의 서비스명인 echo_api의 포트 8080을 설정한다. 스택 역시 서비스를 다루므로 replicas 값으로 레플리카 수를 조정할 수 있다. 또, placement 속성을 이용하면 컨테이너의 배치 전략을 설정할 수 있는데, 아래처럼 manager 이외의 노드에 컨테이너를 배치하도록 제약 부여가 가능하다.

version: "3"

services:
    nginx:
        image: gihyodocker/nginx-proxy:latest
        deploy:
            replicas: 3
            placement:
                constraints: [node.role != manager]
        environment:
            BACKEND_HOST: echo_api:8080
        depends_on:
            - api
        networks:
            - ch03
    api:
        image: registry:5000/example/echo:latest
        deploy:
            replicas: 3
            placement:
                constraints: [node.role != manager]
        networks:
            - ch03

networks:
    ch03:
        external: true

스택을 배포하려면 docker stack deploy 명령을 사용한다. 이 때 -c 옵션 값으로 스택 정의 파일 경로를 지정한다. stack 디렉터리는 manager 컨테이너의 /stack 디렉터리에 마운트 되므로 이 파일의 경로는 /stack/ch03-webapi.yml이 된다. 

docker container exec -it manager docker stack deploy -c /stack/ch03-webapi.yml echo

아래 명령으로 스택에 배포된 서비스 목록을 확인할 수 있다.

$ docker container exec -it manager docker stack services echo
ID                  NAME                MODE                REPLICAS            IMAGE                               PORTS
mgvpcmz8136v        echo_api            replicated          1/3                 registry:5000/example/echo:latest
w80wn8blawab        echo_nginx          replicated          1/3                 gihyodocker/nginx-proxy:latest

스택이 컨테이너 그룹을 어떻게 배포했는지 확인하려면 docker stack ps 명령을 사용한다. 

$ docker container exec -it manager docker stack ps echo
ID                  NAME                IMAGE                               NODE                DESIRED STATE       CURRENT STATE                ERROR                              PORTS
r3xdw6zvvt77        echo_api.1          registry:5000/example/echo:latest   8083e6f3db89        Running             Preparing 53 seconds ago
qy8n2serybqz         \_ echo_api.1      registry:5000/example/echo:latest   cf22a3cc4104        Shutdown            Rejected 53 seconds ago      "No such image: registry:5000/…"
fje81vzhpn3c        echo_nginx.1        gihyodocker/nginx-proxy:latest      cf22a3cc4104        Running             Running 43 seconds ago
y0uts8vvbsu7        echo_api.2          registry:5000/example/echo:latest   cf22a3cc4104        Running             Preparing 53 seconds ago
leq42s8pj4a2         \_ echo_api.2      registry:5000/example/echo:latest   8083e6f3db89        Shutdown            Rejected 53 seconds ago      "No such image: registry:5000/…"
jdds0qvl2luw        echo_nginx.2        gihyodocker/nginx-proxy:latest      8083e6f3db89        Running             Running 43 seconds ago
0r1fk3hns1qg        echo_api.3          registry:5000/example/echo:latest   c963d6dcae06        Running             Running about a minute ago
ofukw7lscl73        echo_nginx.3        gihyodocker/nginx-proxy:latest      c963d6dcae06        Running             Running about a minute ago

스웜 클러스터에 컨테이너 그룹이 어떤 노드에 배치됐는지 시각화해주는 visualizer라는 애플리케이션을 사용하여 컨테이너 배치 시각화를 할 수 있다.

아래 visualizer.yml파일을 stack 디렉토리 하위에 만든다.

version: "3"

services:
    app:
        image: dockersamples/visualizer
        ports:
            - "9000:8080"
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
        deploy:
            mode: global
            placement:
                constraints: [node.role == manager]

global 설정값은 특정 컨테이너를 클러스터 상의 모든 노드에 배치하라는 의미이다. constraints를 보면 manager노드에만 배치하도록 되어 있다.  manager 노드의 포트 9000을 visualizer 컨테이너의 포트 8080으로 포트 포워딩을 설정하였고, 호스트와 manager사이에는 9000:9000 포워딩이 설정돼 있으므로 로컬 머신에서 viaulizer에 접근하려면 http://localhost:9000으로 접근하면 된다. 이제 이 설정대로 스택을 배포한다.

docker container exec -it manager docker stack deploy -c /stack/visualizer.yml visualizer

 

스택 삭제하기

docker stack rm 명령에 대상 스택명을 지정하면 배포된 서비스를 스택째로 삭제할 수 있다.

$ docker container exec -it manager docker stack rm echo
Removing service echo_api
Removing service echo_nginx

스웜 클러스터 외부에서 서비스 사용하기

visualizer 스웜 클러스터 외부에서 접근할 수 있다. 이것은 contraints 설정에서 visualizer 컨테이너가 반드시 manager에 배치되도록 했기 때문이다. 그러나 echo_nginx 서비스는 여러 컨테이너가 여러 노드에 흩어져 배치돼 있기 때문에 이 방법을 사용할 수 없다. 호스트에서 이런 서비스에 접근하기 위해서는 서비스 클러스터 외부에서 오는 트래픽을 목적하는 서비스로 보내주는 프록시 서버가 있어야 한다.

HAProxy 를 이 프록시 서버로 사용해 스웜 클러스터 외부에서 echo_nginx 서비스에 접근할 수 있게 해보자. HAProxy 이미지는 dockercloud/haproxy 이미지를 사용한다. 이 이미지로 만든 컨테이너는 컨테이너 외부에서 서비스에 접근할 수 있게 해주는 다리 역할 외에도 서비스가 매치된 노드에 로드 밸런싱 기능을 제공한다. stack 디렉터리에 다음과 같은 ch03-ingress.yml 파일을 생성한다.

version: "3"

services:
    haproxy:
        image: dockercloud/haproxy
        networks:
            - ch03
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
        deploy:
            mode: global
            placement:
            	constraints:
                	- node.role == manager
        ports:
            - 80:80
            - 1936:1936 # for stats page(basic auth.stats:stats

networks:
    ch03:
        external: true

HAProxy를 거쳐 서비스에 접근이 되는지 확인하기 위해 ch03-webapi.yml을 다시 이용하여 ngnix 환경 변수에 SERVICE_PORTS를 추가한다. 

version: "3"

services:
    nginx:
        image: gihyodocker/nginx-proxy:latest
        deploy:
            replicas: 3
            placement:
                constraints: [node.role != manager]
        environment:
            SERVICE_PORTS: 80
            BACKEND_HOST: echo_api:8080
        depends_on:
            - api
        networks:
            - ch03
    api:
        image: registry:5000/example/echo:latest
        deploy:
            replicas: 3
            placement:
                constraints: [node.role != manager]
        networks:
            - ch03

networks:
    ch03:
        external: true

 

ch03-webapi.yml을 스택 echo로 다시 배포한다.

$ docker container exec -it manager docker stack deploy -c /stack/ch03-webapi.yml echo
Creating service echo_nginx
Creating service echo_api

그다음 ch03-ingress.yml을 스택 ingress로 배포한다.

$ docker container exec -it manager docker stack deploy -c /stack/ch03-ingress.yml ingress
Creating service ingress_haproxy

이 때 서비스 배치 현황은 다음과 같다. 

$ docker container exec -it manager docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                               PORTS
xgl7v8up1z2i        echo_api            replicated          3/3                 registry:5000/example/echo:latest
fsi5n81krpfs        echo_nginx          replicated          3/3                 gihyodocker/nginx-proxy:latest
l620yltq78y7        ingress_haproxy     global              1/1                 dockercloud/haproxy:latest          *:80->80/tcp, *:1936->1936/tcp
ce80u96xahsr        visualizer_app      global              1/1                 dockersamples/visualizer:latest     *:9000->8080/tcp

 

호스트의 8000은 manager 컨테이너의 포트 80, 다시 말해 ingress의 HAProxy로 포트 포워딩 되므로 localhost:8000이 echo_ngnix:80에 접근할 수 있게 된다. 

반응형