Docker swarm-mode
Docker 를 cluster로 만들어 쓰고자 하는 노력은 이전부터 있어 왔다. 제일 대표적이라 할수 있는 것은 구글에서 사용하고 있는 kubernetes이다. 하지만 docker 진영에서는 docker swarm 을 공식으로 밀고 있었는데, 1.12 부터 swarm-kit을 통합하여 swarm-mode 를 만들었다. 이 swarm-mode 는 기존의 swarm 과는 전혀 다른 개념을 가지고 있으며 docker swarm 으로 불리던것은 이제 classic swarm 으로 불린다.
최근(2016년 2월)에는 docker compose v3에서 swarm-mode를 지원한다고 선언함에 따라 이후에 docker clustering 의 핵심이 될 전망이다.
용어
- task
- 실행의 기본 단위이며 swarm kit에서의 life cycle 관리의 기본 단위 이다.
- service
- task 들의 모임이며 사용자는 service 가 기본 실행 단위가 된다.
- node
- manager
- agent
- leader
- slot
- service 내에서의 task 의 일련 번호이다. task 는 재활용 되지 않는 개체이기 때문에 매번 ID가 다르다. 그러나 그렇게 되면 service 를 사용하는 입장에서는 volume 할당 같은 곳에서 어려운 점이 많기 때문에 service내에서의 일련번호를 별도 부여한다. 이를 이용하여 stateful한 service를 구성할수 있다.
- orchestrator
Task
https://github.com/docker/swarmkit/blob/master/design/task_model.md
Docker swarm mode 에서의 기본 실행 단위는 task이다. docker에서는 container가 실행의 기본단위이며 docker 자체가 container 의 실행 주기를 관리하지만, swarm mode에서는 task 가 기본 단위이며 swarm kit은 이 task의 실행 주기를 관리한다. service 는 단순히 task 실행의 context의 의미만 가질 뿐이다.
클러스터에서는 실행주기 관리가 복잡해 질수 있는데 다행히 task는 life cycle이 단방향으로 일어난다. task는 재실행되지않고 재실행이 필요할때 새로 만들어져서 대체 된다.
- NEW
- orchestrator가 최초로 task를 생성한 상태이다.
- ALLOCATED
- network 같은 resource가 할당된 상태이다.
- 이때는 실질적으로 interface가 할당되거나 한 상태는 아니고, swarm kit내에서 ip 주소를 할당하는 것과 같은 논리적인 할당이다.
- vip는 이때 할당 한다.
- ASSIGNED
- 할당된 resource를 실질적으로 줄수 있는 node를 찾아 실질적으로 할당된 상태이다.
- 이 과정에서 노드를 선택하는데에 스케쥴링 정보가 사용된다.
- (agent 에서)
- ACCEPTED
- PREPARING
- STARTING
- RUNNING
- COMPLETE/FAILED
- COMPLETE : process의 return value 가 0
- FAILED : process의 return value 가 non-zero
- SHUTDOWN/REJECTED
Slot
Slot은 service 의 task 갯수를 관리하기 위한 수단이다. 따라서 slot number는 연속적이지 않을수 있다. swarm kit은 service내의 task 갯수를 관리하기 위해 replica 수만큼의 slot number를 할당하고 하나의 slot number에는 task 를 하나만 할당하게끔 유지한다. 그럼 만약 모종의 이유로(network가 끊겼다 붙는다던가) slot number가 겹치면 어떻게 되나면, 과감하게 하나를 죽인다. 이 slot은 단지 같은 slot number에 task를 하나 유지 하기 위함이므로 연속적인것을 보장하지 않는 것이다.
Task template
https://github.com/docker/swarmkit/blob/master/template/context.go Docker Service 를 생성할때 Task 의 slot별로 다른 정보를 주고 싶을 때가 있다.(예를 들어 테스크별로 다른 볼륨을 할당 한다던가, 다른 config 를 물게 만들고 싶다던가.) 그럴 때는 ‘{{.Task.Slot}}’ 과 같이 템플릿 문법을 활용해서 task 별로 다른 정보를 줄수도 있다. 예를 들면 다음과 같이 하는게 가능 하다.
docker service create --name test --label Cluster=dev \
--volume 'type=volume,src=config-{{.Task.Slot}}' \
--env 'BACKEND_ADDR=http://backend-{{.Task.Slot}-{{.Service.Labels.Cluster}}' \
nginx
task template은 일부 attribute에서만 동작한다. volume과 enviroments 에서는 동작하는 것이 확인되었다. argument에서는 template을 쓸수 없으므로 swarm 위에서 이런 template 기능을 쓰고 싶다면 반드시 환경 변수로 template을 사용하고 설정값을 전달해야 한다.
주로 volume이름에 slot number 를 넣어 task 별로 다른 volume을 마운트 할수 있도록 하거나, 환경변수로 넘겨서 원격의 서로 다른 config를 바라보도록 만드는데 쓰인다. 다만 이렇게 사용하게 되면 volume을 미리 만들어 두거나, config를 미리 만들어 두어야 하므로 scale out 에 별도의 툴이 필요하게 된서 좋지 않을수 있다.1
source 분석
swarmkit의 소스를 볼때는 주의할점이 있다. 바로 swarmkit는 standalone으로 동작할수 있다는점이다. swarmkit만 보면 대부분의 동작이 자신의 db에 무언가를 업데이트 하고 종료되게 되어 있다. 만약 이것을 보고 실질적인 동작을 찾는데 시간을 쏟는다면 속은 것이다. swarmkit/agent 는 단순히 자신의 local DB에 데이터를 저장한후 display하는 것이 전부이다. 당연히 docker내부의 무언가 동작하는 부분을 찾을수 없다. 그럼 실질적인 동작은 어디 있는고 하니 docker의 daemon/cluster 아래에 존재한다. 즉 docker는 단순히 swarmkit의 raft알고리즘과, manager 부분을 가져다 쓸뿐 agent의 구현체를 따로 구현하여 사용하는 것이다. 따라서 실제 docker 가 동작하는 부분을 찾으려면 docker의 source를 봐야 한다.
Tips
depandancy 가 있는 Job끼리의 ordering
Docker 문서에서도 설명하고 있지만, container 시작시에 특정 포트에 health check를 하거나 공유하고 있는 volume 에 특정 file 이 있는 지를 check 하는 식으로 하는 수 밖에 없다. 이는 귀찮은 작업이고 실제 application의 동작과는 어쩌면 상관 없을수 있기 때문에 thrid party에서 tool들이 개발되어 있다.
jwilder/dockerize 쪽이 좀더 기능이 풍부하고 쓰기가 쉽다.
docker swarm의 port binding 시 localhost 문제
docker swarm service 의 port expose 했을때 localhost로는 접근이 안되는데 외부에서는 접근이 되는 경우가 있다. 이는 swarm expose 가 docke brige를 이용하기 때문이다.
https://github.com/docker/for-aws/issues/7
따라서 docker_gwbridge의 ip 로 접근 하면 잘 접근 된다.
- 때문에 config를 동적 생성할수있는 MSA를 만드는 것이 이득이 될수 있다.