pre-requisite
docker
,docker-compose
,docker-machine
이 세가지 프로그램이 설치되어야 한다.Docker Store(링크) 에서 설치 가능하다. 자신의 OS 에 맞는 Docker 를 설치하자.
그동안 docker
를 사용하여 웹 서버 개발을 하고 있었지만, Docker 공식 문서를 오랜만에 들어가보니 그곳에서 추구하는 개발-배포 flow 는 나의 그것과 사뭇 달랐다.
나의 방식보다 훨씬 깔끔하고 스마트했다. 그래서 한번 제대로 익혀놓고, 앞으로 이렇게 개발-배포 하자 라고 마음먹으며 이 글을 쓴다.
“Docker 에서 제시하는 개발-배포 Flow 는 AWS 나 Azure 에서 자사 제품들을 이용하여 제시하는 개발-배포 Flow 의 대체가 될 수 있을 것 같다.”
새로운 개발 배포 flow를 익히면서 중점적인 이슈로 둔 부분은 아래와 같다.
1. 초기구축 : 초기 서비스 그룹(DB, WAS, Web Server 등) 구축이 쉬운가
2. 스케일 조정 : Load Balancing 설정이 쉽고, Scale 조정이 쉬운가
3. 코드 배포 : 추후 앱의 로직 코드 변경시 배포가 편리한가
클라우드를 제공하는 AWS 나 AZURE 는 자신들이 만들어놓은 여러 제품들을 이용하면 위 세가지를 편리하게 실현할 수 있게 하였다. (AWS 의 ELB-elastic load balancer 를 이용하면 로드밸런싱이 쉽게 가능한 것 처럼 …)
과연 Docker 를 이용한 서버 개발-배포 flow 도 위의 세가지가 가능할까? Docker 공식 문서를 읽고 난 후 나의 생각은 ‘yes’ 이다.
초기 구축이란, 코드가 배포될 클라우드의 인프라를 구축하는 일을 말한다.
Docker를 이용한 개발-배포 Flow 에서, 초기 구축은 두 단계로 나뉜다.
docker-compose.yml
로 Stack 구성하고 실행한다.Swarm 이란 여러 Docker Macine들이 마치 하나의 Docker 실행환경처럼 작동하는 Virtual Macine Cluster 를 말한다.
아래 그림처럼 Swarm 이 클라우드 서버 상의 두대의 Docker Machine 으로 구성되어 있다면, 우리가 제공하고자 하는 앱에 필요한 컨테이너들이 두 가상머신에 적절한 수로 배치된다.
Swarm 의 각 Docker Machine 들은 Node 라고 부르며, 하나의 Manager Node와 다수의 Worker Node 로 이루어져있다. 오직 Manager node 만이 다른 node 에 접근하고 제어할 수 있다. 우리는 이 모든 노드에 접속해 일일히 동작을 제어할 필요 없이, Manager Node 의 Shell 에 접속해서 마치 swarm 이 하나의 Docker 실행환경이라고 생각하고 docker 명령어를 실행하면 된다.
우선 접속 가능한 docker machine 리스트를 확인한다.
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
myvm1 - virtualbox Running tcp://192.168.99.100:2376 v17.06.2-ce
myvm2 - virtualbox Running tcp://192.168.99.101:2376 v17.06.2-ce
이 중 manager 로 삼을 docker machine 을 골라 아래와 같이 수행한다.
$ docker-machine ssh myvm1 "docker swarm init --advertise-addr <myvm1 ip>"
Swarm initialized: current node <node ID> is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \
--token <token> \
<myvm ip>:<port>
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
위를 완료했다면 worker 로 삼을 docker machine 에서 아래와 같이 수행한다.
$ docker-machine ssh myvm2 "docker swarm join \
--token <token> \
<ip>:2377"
This node joined a swarm as a worker.
이때 주의 할 점은 반드시 2377 포트를 이용해 swarm 통신을 해야한다는 것이다. 2376 이 절대 아니다.
이제 Manager Node 에서 모든 docker 명령을 수행하면 되는데, 첫번째 docker 명령으로 docker node ls
으로 모든 클러스터 노드들을 확인해보자.
$ docker-machine ssh myvm1 "docker node ls"
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
brtu9urxwfd5j0zrmkubhpkbd myvm2 Ready Active
rihwohkh3ph38fhillhhb84sk * myvm1 Ready Active Leader
이렇게 Swarm 구축은 끝났고, 이 swarm 의 노드들을 Azure 나 Aws 의 클라우드 가상 머신으로 설정만 한다면 클라우드 서버 인프라 구축의 시작점이 되는 것이다.
참고 1: Azure 에서 Docker Machine 만드는 법
참고 2: AWS 에서 Docker Machine 만드는 법
참고 3: Docker machine 에서 지원하는 가상머신 드라이버들
참고 4: driver 란? Microsoft
docker-compose.yml
로 Stack 구성하고 실행Docker-Compose 는 컨테이너를 Stack-Service-Task 라는 세가지 가상 계층으로 구분해 관리한다.
결국 우리가 만들고자 하는 것은 하나의 Stack 이고, docker-compose.yml
은 Stack 을 정의할 수 있는 파일이다.
docker-compose.yml
작성 예시아래는 docker-compose.yml
의 예시이다.
web
, visualizer
,redis
라는 세개의 Service 가 이 Stack 을 이루고, web
Service 는 5개의 Task(Container) 로 이루어져있다.
5개의 Task 로 이루어진 web
서비스의 주소 80 port 로 접속이 들어오면, docker 는 round-robin 방식으로 load balancing 을 수행한다.
version: "3"
services:
web:
# replace username/repo:tag with your name and image details
image: username/repo:tag
ports:
- "80:80"
deploy:
replicas: 5
restart_policy:
condition: on-failure
resources:
limits:
cpus: "0.1"
memory: 50M
networks:
- webnet
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
networks:
- webnet
redis:
image: redis
ports:
- "6379:6379"
# ports 대신 expose:-"6379" 을 사용하면 docker network 상에서만 접근 가능하고, 실제 외부 포트로 연결은 되지 않는다.
volumes:
- "redis-data-vol:/data"
deploy:
placement:
constraints: [node.role == manager]
command: redis-server --appendonly yes
networks:
- webnet
networks:
webnet:
volumes:
redis-data-vol:
대략 하나의 서비스를 기술 할 때,
image
ports
/expose
volumes
networks
command
deploy
등이 필수적인 설정값인듯 하다.
참고로 docker swarm 을 이용해 개발-배포 한다면 network driver 의 기본 설정값은 overlay
이다. overlay
는 여러대의 docker-machine 에 나누어진 container들이 마치 하나의 network 상에 존재하는 것처럼 접속 가능하게 해준다.
참고 1 : networks
top-level key 설정 관하여
참고 2 : volumes
top-level key 설정 관하여
참고 3 : deploy
service-level key 설정 관하여
참고 4 : Docker 의 overlay network 에 대하여
docker-compose.yml
로 하나의 Stack 을 정의했으니, 이제 이 docker-compose.yml
파일을 Manager Node 에 업로드하고
docker-machine scp /local/docker-compose.yml myvm1:/path/to/docker-compose.yml
Manager Node 에서 Stack 을 실행한다. 이때 stack 정의에 참고할 Compose file 도 -c
옵션으로 적어준다.
docker stack deploy -c ./docker-compose.yml
Docker Compose 가 하는 역할
- Stack-Service-Task 계층 구조를 확립시키고, 컨테이너를 효율적으로 관리하고 연결시킨다.
- 원본 Image 가 변경되어서 컨테이너가 recreate 될 때에도, 이전 컨테이너 내용을 복사해서 붙여넣어주므로 데이터 연속성과 유지력을 보완시켜준다. (기본적으로 컨테이너가 recreate 되면 read-write 계층 파일은 모두 사라진다. ) (참고블로그링크)
- 불필요한 container recreate 를 줄여준다. 이미지의 변경이 없을 시 컨테이너를 그대로 유지한다.
- Docker Swarm 의 로드밸런싱 규칙을 설정한다.
Docker Machine 이 하는 역할
docker 실행 환경이 조성된 가상 머신을 생성하고 관리한다. Docker Swarm 을 구축하고 관리할 때 필수적이다.
위의 초기 구축 단계를 따라오다보면 두가지 로드밸런싱의 패러다임을 발견할 수 있다.
replicas : 5
)를 늘림으로써 부하분산을 취하는 방식두가지 방식 모두 유용하다. 스케일 조정 참 쉽다.
Swarm 의 각 노드 Machine 주소로 접속한다면?
결국 각 노드에 존재하는 swarm loadbalancer 가 하나의 docker 실행환경처럼 작동해서 필요한 적절한 컨테이너로 연결해준다.
하지만 어떠한 가상머신(node)이 서비스를 제공하는지 숨기고 싶은 경우, 통상적인 방식대로 Swarm 앞에 로드밸런서를 하나 더 두어야한다. Load Balancing 을 수행하는 Proxy 서버로 Nginx 를 Swarm 앞에 사용하는 tutorial 관련 게시글 을 참조하면 이러한 시도들을 확인할 수 있다.
이전 nginx 관련 포스트에서 설명했던 바와 같이, nginx 에는 기본 로드밸런서 기능이 내장되어있다.
관련글 -> jayneWho(); > Post > Nginx 에 대하여 (Nginx Basic Usage)
또한 Docker Documentation 에도 Swarm 앞에 External Load Balancer 로 HAProxy 를 두는 법을 설명하고 있다. 아래 그림을 참고하자.
위와 같이 클라우드 인프라를 구축해놓았다면, 코드를 배포하는 일은 너무나 쉽다.
소스 코드 수정 후 docker image build
하기
Docker Hub Repository 에 새로 만든 이미지 push 하기
docker-compose.yml
파일 또는 swarm 에 bind-mount 파일 변경되었다면 docker-machine scp
로 전송\docker-machine ssh myvm1 "docker stack deploy -c ./docker-compose.yml"
로 Stack 재배포하면, Repository 에서 이미지 새로 끌어와서 업데이트된 컨테이너가 구축됨docker-compose-dev.yml
파일을 작성해서, 로컬에서 돌릴만한 Stack 구성을 작성해 local 의 docker engine 에서 이미지와 컨테이너가 잘 작동하는지 테스트하며 개발할 수 있다.
이로써 초기 구축, 스케일조정, 코드배포 까지 개발-배포 과정에서 docker 를 이용하는 방식을 살펴보았다. docker 공식 문서에 충실하게 말이다.
위와 같은 배포 flow 대로 충실히 수행한 toy-project 를 github 에서 발견하였다. 실제 코드가 보고싶을 때 “이 프로젝트 Github 링크” 로 들어가 프로젝트 코드를 살피면 좋을 듯 하다. backend service (django)(3 replicas) + frontend service (nginx)(2 replicas) 로 간단하게 구성되어있다. 이 곳에서는 docker stack deploy -c docker-swarm.yml
을 해야한다.
그런데 뭔가 배포한 Swarm 과 Stack 에 관한 시각화와 관리 툴이 있으면 좋겠다는 생각이 든다. 그 때 발견한 것이 Docker Cloud 이다.
Docker Cloud 를 이용하면 자신의 Swarm 과 그 위에 돌아가는 Stack, Service, Task Container 들을 관리할 수 있다. 자세한 spec 설정까지 가능하다.
자신의 Docker Hub Repository 에 있는 image 들도 불러와 관리할 수 있고, AutoBuild 기능으로 코드에 변화가 생겼을 때 바로바로 image 를 자동 재생성하는 기능 또한 갖췄다.
심지어 새로운 Swarm 이나 이미지를 웹 상에서 만드는 것도 가능하다.
(docker-machine 드라이버를 제공하는 다른 cloud hosting 서비스 업체들은 많지만, swarm 만들기를 지원하는건 아직 amazon 과 azure 뿐인가보다. 다른 서비스업체를 이용할 경우 직접 위 방식대로 swarm 을 만들어야겠다.)
매우 간단한 UI 이므로, 직접 사용해보는 것을 추천한다.
Docker Cloud Documentation 의 Manage Swarms 를 보면서 사용하면 좋을 듯 하다.