Deploy Swarm Services with the new docker `stack` and a compose file!

On of the new additions of Docker 1.13 is the ability to use compose files to deploy swarm mode services!

This means that we can use docker-compose files to provision Swarm services.

That also means that we do not need anymore to type all the long docker service create commands.
A long list of docker service create commands would be simply replaced by a command like the below:

docker stack deploy --compose-file=docker-compose.yml my_stack

In this blog post, we will see that in action and discuss what is covered and what still lacks.

Life before Docker stack deploy

Or precisely, before docker stack deploy --compose-file <Path to a Compose file> we had to type a lot and maintain a shell script to start our services accross the Swarm.

What made things worse, is that before the addition of this command, as developers, we loved the docker-compose command to deploy a stack on our machines. But as you know, docker-compose couldn't benefit from all the nodes of the swarm cluster. It gave us a warning like the below:

docker-compose up -d

WARNING: The Docker Engine you're using is running in swarm mode.

Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.

To deploy your application across the swarm, use the bundle feature of the Docker experimental build.

More info:
https://docs.docker.com/compose/bundles

So even if you had a compose-file for local testing, you would have to prepare a set of commands to create the service on the Swarm and align those! Talk about technical debt...

Let's take a simple example where we want to deploy two service to monitor the swarm.

These two service I tend to always create first thing on my Swarms are the Visualizer and Portainer. Here is how I used to do so:

docker service create \
  --publish 9000:9000 \
  --name portainer \
  --constraint=node.role==manager \
  --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
  portainer/portainer 

docker service create \
  --publish=9090:8080 \
  --limit-cpu 0.5 \
  --name=viz \
  --constraint=node.role==manager \
  --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
  dockersamples/visualizer

Life after Docker stack deploy

Let's now deploy our monitoring stack again, but this time with the new shiny way:

curl -o docker-compose-stack-monitoring.yml \
https://raw.githubusercontent.com/jmkhael/compose-samples/master/docker-compose-stack-monitoring.yml

docker stack deploy -c docker-compose-stack-monitoring.yml monitoring

The first command downloaded the Compose file docker-compose-stack-monitoring.yml from the jmkhael/compose-samples repository.
The second command creates the services which form what I called the monitoring stack.

Note from the below output that it does incrementally handle new service:

Creating service monitoring_viz
Updating service monitoring_portainer (id: jbt006a7yoi8t0ok941b358k2)

If you check the created services, you'll see portainer and visualizer:

docker service ls
ID            NAME                  MODE        REPLICAS  IMAGE
jbt006a7yoi8  monitoring_portainer  replicated  1/1       portainer/portainer:latest
wqfb3odzmnfh  monitoring_viz        replicated  1/1       dockersamples/visualizer:latest

that's neat!

The docker-compose-stack-monitoring.yml file look like this:

version: '3'

services:

  portainer:
    image: portainer/portainer
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - 9000:9000
    deploy:
      placement:
        constraints: [node.role == manager]

  viz:
    image: dockersamples/visualizer
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    deploy:
      placement:
        constraints: [node.role == manager]
    ports:
      - 9090:8080

Note that the docker-compose file uses the version 3, introduced with Docker 1.13. (Check the schema here)

You can use some nice configurations under the deploy section such as deployment mode (replicated or global), replicas count (replicas: 3) or labels...

deploy:
  mode: replicated
  replicas: 2
  labels: [APP=CONQUER_UNIVERSE]

Is everything covered?

TL;DR:

The short answer is of course, No.

The longer answer is around these lines:

Networks

No support for attachable networks yet in the docker-compose v3.

Extends not supported

You cannot use the extends keyword. But there is a quick workaround for that. You'd need to resolve the docker-compose keyword by issuing:

docker-compose config > docker-compose-resolved.yml 

Unsupported docker-compose v2 keywords

The below keywords are still not supported.

  • "build",
  • "cap_add",
  • "cap_drop",
  • "cgroup_parent",
  • "devices",
  • "dns",
  • "dns_search",
  • "domainname",
  • "external_links",
  • "ipc",
  • "links",
  • "mac_address",
  • "network_mode",
  • "privileged",
  • "read_only",
  • "restart",
  • "security_opt",
  • "shm_size",
  • "stop_signal",
  • "tmpfs"

That's it for this post. Now go deploy some stacks!