Imagine you configured your new shiny Docker cluster and now ready to fill it with dockerized applications. How exactly are you going to do that? Not by manually typing docker service create
for every app, right? Especially when average application that requires cluster will contain more than one service in it.
In standalone Docker we had docker-compose
tool, which allowed us to describe all app containers in single docker-compose.yml
file and then start it with docker-compose up
. Can we use the same for Swarm? Absolutely.
Introducing docker stack
Among the other commands brought by Docker in Swarm mode there is docker stack
, which, believe it or not, works almost the same as docker-compose
. With little to no modification it even can use compose YAML files. If you’d want to update your existing compose file to be compatible with Stack, you’d need to do the following:
- Use at least 3rd version of compose file. E.g.
version: '3.1'
- Make sure there’re no
build
(and few others) commands in it.
And that’s it! Now you’re ready to type docker stack deploy -c my-compose-file.yml my-stack-name
and send YAML file to the cloud.
Example
In last article we ended up with Docker cluster and two services in it: viz
for visualizing cluster state and replicated web
service for performance testing. Even though it wasn’t much of a typing to create those, commands themselves were reasonably complicated and involved Swarm features like constraints and replicas. Instead, we can create two docker-compose
-like YAML files for viz
and web
services and make their deployment absolutely trivial.
0. Prerequisites
To follow along you’ll need a configured instance of Docker in Swarm mode and previous article explains how to create one (steps 0 and 1). You don’t even need multi-host cluster: local machine in Swarm mode is perfectly fine.
1. Stack definition for viz
In case you forgot (like I did) how visualization service command looked like, it was the following:
1 2 3 4 5 6 |
docker service create \ --name=viz \ --publish=8080:8080 \ --constraint=node.role==manager \ --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \ dockersamples/visualizer |
YAML file for it will look pretty much like the one you’d create for docker-compose
:
1 2 3 4 5 6 7 8 9 10 11 12 |
version: "3.1" services: viz: image: dockersamples/visualizer ports: - 8080:8080 volumes: - /var/run/docker.sock:/var/run/docker.sock deploy: placement: constraints: [node.role == manager] |
The difference is in latest version number 3.1
and deploy
section which was introduced specifically for Swarm. The following command will deploy the stack:
1 2 3 |
docker stack deploy -c viz.yml viz #Creating network viz_default #Creating service viz_viz |
-c viz.yml
specifies file name to use and viz
is the stack name. Now, when command has finished, we can list deployed stacks with docker stack ls
and navigate to port 8080 to see visualization service in action:
1 2 3 |
docker stack ls #NAME SERVICES #viz 1 |
2. Stack definition for web
web
service was good old nginx container with port 80 being published. To make things a little bit more interesting, let’s put two services into the same file. Just to make sure it works the same way as it did in docker-compose. Let’s call the first service web1
, the second – web2
and this is how their YAML looks like:
1 2 3 4 5 6 7 8 9 10 11 |
version: '3.1' services: web1: image: nginx ports: - 8081:80 web2: image: httpd ports: - 8082:80 |
As for deployment command, it hasn’t changed a bit:
1 2 3 4 |
docker stack deploy -c web.yml web #... #Creating service web_web1 #Creating service web_web2 |
Again, checking the stack status:
1 2 3 4 |
docker stack ls #NAME SERVICES #web 2 #viz 1 |
So far, so good.
3. How to update existing stack
I remember, when I had to update container deployed with docker-compose, I had to do at least three steps: docker-compose stop srv
, docker-compose build srv
and docker-compose up -d --no-deps srv
. It got a little bit simpler with stacks.
Original web
service definition from previous article ended up being upscaled to two replicas. For today’s service we can specify number of replicas directly in YAML file and that also will be a good reason to update the whole stack. What’s more, why not replicate both web1
and web2
services? More containers, more colored rectangles at visualization page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
version: '3.1' services: web1: image: nginx ports: - 8081:80 deploy: replicas: 3 web2: image: httpd ports: - 8082:80 deploy: replicas: 2 |
And this is how stack update command would look like:
1 2 3 |
docker stack deploy -c web.yml web #Updating service web_web2 (id: 18hq0xui4ek3cbczt8cd9kni3) #Updating service web_web1 (id: i8mmj4vfccqodu3fudg3ew507) |
Yup, this is the same command as for stack initial deployment: deploy
does both installs and upgrades.
Summary
There’re good news: docker-compose
approach for complex containerized applications deployment is still there. For Docker in Swarm mode it’s called docker stack
and it’s not something new to learn. If you know compose, you already know Stack. It uses slightly newer YAML file format with new Swarm specific settings in it and few limitations, but other than that it’s good old compose in disguise.