Elton's Container Show


Elton's Container Show - resources for the YouTube broadcast

View the Project on GitHub sixeyed/ecs

ECS-O2: Containers in Production with Docker Swarm

Docker Swarm is the production-grade orchestrator built into Docker. There are no managed Swarm services in the cloud, but you can run a supported cluster in the datacenter with Docker Enterprise (previously a Docker product, now owned by Mirantis).

Swarm is an opinionated orchestrator which is simple to work with. It uses the Docker Compose specification to model applications so it’s easy for people to transition from Compose on a single machine to a Swarm cluster.

In this episode we create a Swarm cluster and deploy some applications, showing how the Compose spec can be extended to include production concerns.

Here’s it is on YouTube - ECS-O2: Containers in Production with Docker Swarm


I’m running Linux VMs for the Swarm cluster using Vagrant.

You can set the VM up with:

cd episodes/ecs-o2/vagrant

vagrant up

You can run all the examples with Docker Desktop, except for the node management section because you’ll only have a single node.

Demo 1 - Initializing the cluster

The orchestration component in Docker Swarm is a separate open-source project called SwarmKit. It’s baked into the Docker Engine so when you run in Swarm mode there are no additional components.

Initialize the Swarm on the manager node:

vagrant ssh manager

docker swarm init

docker swarm join-token manager

docker swarm join-token worker


You now have a functional single-node Swarm. The output shows the command you run on other nodes to join the Swarm.

Join the worker nodes:

vagrant ssh worker1

[docker swarm join]


Run the docker swarm join command from the manager node.

vagrant ssh worker2

[docker swarm join]


Check the cluster status:

vagrant ssh manager

docker node ls

docker node inspect worker1

Nodes are top-level objects, but you need to be connected to a manager to work with them.

Demo 2 - Running Docker Swarm services

Swarm mode takes the service abstraction from Docker Compose and makes it into a first-class object. You can create services on the Swarm, and the orchestrator schedules containers to run.

Deploy a basic web app:

docker service create --name apache -p 8080:80 diamol/apache

docker service ps apache

docker node inspect worker1 -f ''

docker node inspect worker2 -f ''

There’s a single container running, but you can browse to port 8080 on any node and the traffic gets routed to the container.

Scale up and more containers will be created - incoming requests get load-balanced between them:

docker service update --replicas 10 apache

docker service ps apache

docker node inspect manager -f ''

Browse to the site and refresh a few times

Check the logs and clear up:

docker service logs apache

docker service rm apache

docker ps

Demo 3 - Deploying a Docker Compose manifest

Swarm can run applications defined for Docker Compose - any parts of the Compose spec which aren’t relevant in Swarm mode (like depends_on) get ignored.

This simple docker-compose.yml file is perfectly valid to run in the cluster. It gets deployed as a stack, which is a grouping for services, networks and other resources.

Deploy the app as a stack:

cd /ecs-o2

docker stack deploy -c docker-compose.yml todo1

docker network inspect todo1_todo-net

In Swarm mode the default network driver is overlay, which spans all the nodes in the cluster.

Check the resources:

docker stack ls

docker stack services todo1 

docker stack ps todo1

Browse to a node on port 8010.

Demo 4 - Deploying a production-grade Docker stack

The cluster has it’s own HA database, replicated across all the manager nodes (typically 3 in a production cluster). The database stores all the app specs and you can use it for configuration objects.

That lets you separate configuration management from app management. We’ll deploy the to-do app next using custom config objects: todo-web-config.json and todo-web-secrets.json

Create the app config in the Swarm:

docker config create todo-web-config ./configs/todo-web-config.json

docker config ls

docker config inspect todo-web-config --pretty

Anyone can read the contents of a config object.

And the secret:

docker secret create todo-web-secrets ./secrets/todo-web-secrets.json

docker secret ls

docker secret inspect todo-web-secrets --pretty

Secrets are encrypted and can only be read inside the container filesystem.

This new docker-stack.yml spec models the to-do app with configs and secrets mounted into the container.

Deploy the new stack:

docker stack deploy -c docker-stack.yml todo2

docker stack ps todo2

In a new window open a session to the node running the container and check the filesystem:

vagrant ssh [node]

docker ps

docker exec -it [container] sh

ls -l /app/config

cat /app/config/config.json

cat /app/config/secrets.json


For a production deployment you would also add healthchecks, update and rollback configuration, security settings (like user IDs for the container processes) and more.

There’s some extra production detail in docker-stack-2.yml - adding process constraints to the containers, and running multiple replicas of the web app.

Back on the manager node, update the stack:

docker stack deploy -c docker-stack-2.yml todo2

docker stack ps todo2

The update happens as a staged rollout. Try the app at :8020

Demo 5 - Node management

Creating a Swarm is easy, and so is managing the nodes in the Swarm/

Take a node out of action for maintenance:

docker service ps todo2_todo-web

docker node update --availability drain worker1

docker node ls

docker node ps worker1

docker service ps todo2_todo-web

Containers are shut down and replaced on other nodes. Drained nodes won’t schedule any more containers.

Bring the node back online:

docker node update --availability active worker1

docker node ps worker1

docker node ls

The node is back online, but running services aren’t automatically rebalanced.

Update a service to force rebalancing:

docker service update --force todo2_todo-web

docker service ps todo2_todo-web -f "desired-state=running"


Delete stacks and leave the Swarm:

docker stack rm $(docker stack ls)

docker ps

docker swarm leave -f

docker node ls


Repeat the swarm leave command on all nodes.

Remove all the VMs:

vagrant destroy

Coming next