Disclaimer: all code snippets below are working only with Docker 1.13+
Docker 1.13 simplifies deployment of composed application to a swarm (mode) cluster. And you can do it without creating a new dab
(Distribution Application Bundle) file, but just using familiar and well-known docker-compose.yml
syntax (with some additions) and --compose-file
option.
Docker Engine 1.12 introduced a new swarm mode for natively managing a cluster of Docker Engines called a swarm. Docker swarm mode implements Raft Consensus Algorithm and does not require using external key value store anymore, such as Consul or etcd.
If you want to run a swarm cluster on a developer’s machine, there are several options.
The first option and most widely known, is to use a docker-machine
tool with some virtual driver (Virtualbox, Parallels or other).
But, in this post I will use another approach: using docker-in-docker Docker image with Docker for Mac, see more details in my Docker Swarm cluster with docker-in-docker on MacOS post.
When you deploy a new service on local swarm cluster, I recommend to setup local Docker registry mirror and run all swarm nodes with --registry-mirror
option, pointing to local Docker registry. By running a local Docker registry mirror, you can keep most of the redundant image fetch traffic on your local network and speedup service deployment.
I’ve prepared a shell script to bootstrap 4 nodes swarm cluster with Docker registry mirror and very nice swarm visualizer application.
The script initialize docker engine as a swarm master, then starts 3 new docker-in-docker containers and joins them to the swarm cluster as worker nodes. All worker nodes run with --registry-mirror
option.
#!/bin/bash
# vars[ -z "$NUM_WORKERS" ] && NUM_WORKERS=3
# init swarm (need for service command); if not createddocker node ls 2> /dev/null | grep "Leader"if [ $? -ne 0 ]; thendocker swarm init > /dev/null 2>&1fi
# get join tokenSWARM_TOKEN=$(docker swarm join-token -q worker)
# get Swarm master IP (Docker for Mac xhyve VM IP)SWARM_MASTER=$(docker info --format "{{.Swarm.NodeAddr}}")echo "Swarm master IP: ${SWARM_MASTER}"sleep 10
# start Docker registry mirrordocker run -d --restart=always -p 4000:5000 --name v2_mirror \-v $PWD/rdata:/var/lib/registry \-e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \registry:2.5
# run NUM_WORKERS workers with SWARM_TOKENfor i in $(seq "${NUM_WORKERS}"); do
docker node rm --force \$(docker node ls --filter "name=worker-${i}" -q) \> /dev/null 2>&1
docker rm --force \$(docker ps -q --filter "name=worker-${i}") > /dev/null 2>&1
docker run -d --privileged --name worker-${i} \--hostname=worker-${i} \-p ${i}2375:2375 \-p ${i}5000:5000 \-p ${i}5001:5001 \-p ${i}5601:5601 \docker:1.13-rc-dind \--registry-mirror http://${SWARM_MASTER}:4000
docker --host=localhost:${i}2375 swarm join \--token ${SWARM_TOKEN} ${SWARM_MASTER}:2377done
# show swarm clusterprintf "\nLocal Swarm Cluster\n===================\n"
docker node ls
# echo swarm visualizerprintf "\nLocal Swarm Visualizer\n===================\n"docker run -it -d --name swarm_visualizer \-p 8000:8080 -e HOST=localhost \-v /var/run/docker.sock:/var/run/docker.sock \manomarks/visualizer:beta
The Docker compose
is a tool (and deployment specification format) for defining and running composed multi-container Docker applications. Before Docker 1.12, you could use docker-compose
tool to deploy such applications to a swarm cluster. With 1.12 release, it’s not possible anymore: docker-compose
can deploy your application only on single Docker host.
In order to deploy it to a swarm cluster, you need to create a special deployment specification file (also knows as Distribution Application Bundle) in dab
format (see more here).
The way to create this file, is to run the docker-compose bundle
command. The output of this command is a JSON file, that describes multi-container composed application with Docker images referenced by @sha256
instead of tags. Currently dab
file format does not support multiple settings from docker-compose.yml
and does not allow to use supported options from docker service create
command.
Such a pity story: the dab
bundle format looks promising, but currently is totally useless (at least in Docker 1.12).
With Docker 1.13, the “new” way to deploy a multi-container composed application is to use docker-compose.yml
again (hurrah!). Kudos to Docker team!
*Note: And you do not need the docker-compose
tool, only yaml
file in docker-compose format (version: "3"
)
$ docker deploy --compose-file docker-compose.yml
version: "3"
)So, what’s new in docker compose version 3?
First, I suggest you take a deeper look at docker-compose schema. It is an extension of well-known docker-compose
format.
Note: docker-compose
tool (ver. 1.9.0
) does not support docker-compose.yaml version: "3"
yet.
The most visible change is around swarm service deployment. Now you can specify all options supported by docker service create/update
commands:
I’ve created a “new” compose file (v3) for classic “Cats vs. Dogs” example. This example application contains 5 services with following deployment configurations:
voting-app
- a Python webapp which lets you vote between two options; requires redis
redis
- Redis queue which collects new votes; deployed on swarm manager
nodedb
- Postgres database backed by a Docker volume; deployed on swarm manager
noderesult-app
- Node.js webapp which shows the results of the voting in real time; 2 replicas, deployed on swarm worker
nodesworker
.NET worker which consumes votes and stores them in db
;swarm worker
nodes onlyversion: "3"
services:
redis:image: redis:3.2-alpineports:- "6379"networks:- voteappdeploy:placement:constraints: [node.role == manager]
db:image: postgres:9.4volumes:- db-data:/var/lib/postgresql/datanetworks:- voteappdeploy:placement:constraints: [node.role == manager]
voting-app:image: gaiadocker/example-voting-app-vote:goodports:- 5000:80networks:- voteappdepends_on:- redisdeploy:mode: replicatedreplicas: 2labels: [APP=VOTING]placement:constraints: [node.role == worker]
result-app:image: gaiadocker/example-voting-app-result:latestports:- 5001:80networks:- voteappdepends_on:- db
worker:image: gaiadocker/example-voting-app-worker:latestnetworks:voteapp:aliases:- workersdepends_on:- db- redis# service deploymentdeploy:mode: replicatedreplicas: 2labels: [APP=VOTING]# service resource managementresources:# Hard limit - Docker does not allow to allocate morelimits:cpus: '0.25'memory: 512M# Soft limit - Docker makes best effort to return to itreservations:cpus: '0.25'memory: 256M# service restart policyrestart_policy:condition: on-failuredelay: 5smax_attempts: 3window: 120s# service update configurationupdate_config:parallelism: 1delay: 10sfailure_action: continuemonitor: 60smax_failure_ratio: 0.3# placement constraint - in this case on 'worker' nodes onlyplacement:constraints: [node.role == worker]
networks:voteapp:
volumes:db-data:
Run the docker deploy — compose-file docker-compose.yml VOTE
command to deploy my version of “Cats vs. Dogs” application on a swarm cluster.
Cats vs. Dogs on Swarm cluster
Hope you find this post useful. I look forward to your comments and any questions you have.
Originally published at Codefresh Blog.