Docker and Swarm Mode – Part 1
In the following few posts I am going to demonstrate how we can use the new SwarmKit that is part of Docker 1.12 to manage a cluster of nodes (VMs) as a Docker Swarm. To not depend on any cloud provider we will be using VirtualBox on our developer machine to generate such a swarm. I will show how easy it is to get a completely working swarm in place and how to run an application consisting of a bunch of services on this swarm. The application that we’re going to use is borrowed from Jérôme Petazzo from Docker. This application is a good sample for a microservices based application using various different frameworks and languages to implement individual services. It would be a nightmare to have to run this application natively on a host due to all the different technologies involved. But with Docker and a Docker Swarm it is a breeze and straight forward.
Let’s start with part 1 and let’s immediately dive into this adventure…
Generate a cluster
In this post I will use Virtualbox to be able to work with multiple VMs. Please make sure you have Docker and Virtualbox installed on your system. The easiest way to do so is by installing the Docker Toolbox.
Docker Toolbox by default installs a tiny VM called default
in Virtualbox. Let’s stop this VM (and any other that might be running) to have sufficient resources for our cluster. Open a terminal (e.g. Docker Quickstart) and execute the following command
docker-machine stop default
We now want to create a cluster of 5 nodes. We can do that manually using docker-machine
or use a small script to quickly generate a bunch of nodes in VirtualBox
for N in 1 2 3 4 5; do docker-machine create --driver virtualbox node$N; done
The above command might take a few minutes, please be patient. Once done, double check that all nodes are up and running as expected
docker-machine ls
You should see something similar to this
ssh
into the first node with the help of docker-machine
using this command
docker-machine ssh node1
Once logged into node1 verify that Docker is in the latest version by issuing the command
docker info
Docker-Compose
Our nodes on Virtualbox consist of a minimal Linux installation with Docker and do not have docker-compose
installed which we will need in our exercise. Fortunately that’s no big deal, we can use a container image which has docker-compose
installed and use this instead of having docker-compose
directly installed on the node. Thankfully Docker has created such an image. Make sure to use the latest version of it which at the time of writing is 1.8.0. We can pull this image like
docker pull docker/compose:1.8.0
and then we can run a container with compose like this
Note how I mount the docker.sock
to have direct access to Docker on the host from within the container and I also mount the working directory into the container to have access to the files on the host like the docker-compose.yml
file, etc. If I run the above command the version of docker-compose will be printed. To simplify my life I can define an alias as follows
alias docker-compose='docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -v $(pwd):/app --workdir /app docker/compose:1.8.0'
and then we can use it like this
docker-compose --version
to e.g. print the version or
docker-compose up
to use the docker-compose.yml
file in the current directory and run the application described in there.
Working with the Swarmkit
Now we’re ready to create a new Docker swarm. Note that Docker (starting from version 1.12) can run in two modes, classical and swarm mode. The former is there for backwards compatibility and the latter uses the new swarm kit that is now part of Docker Engine. To initialize a new swarm use this command on node1:
docker swarm init --advertise-addr [ip-address]
where [ip-address]
is the public IP address of the node (e.g. 192.168.99.101). The above command will tell us in the output which command to use to join other worker nodes to the swarm. In my case this looks like this
Don’t worry if you forget this command. At any time we can retrieve it again using
docker swarm join-token worker
to get the join command for a worker or
docker swarm join-token manager
to get the equivalent for a node that should join as a manager.
Open another terminal window and ssh
into node2
docker-machine ssh node2
and run the join command needed for a worker (in my case this is)
In your case you will of course have another swarm token and probably a different IP address.
Now, we can do the very same for nodes 3 to 5 but that’s a bit tedious, especially if we don’t have 5 but 10 or more nodes. Let’s automate this
OK, so now we have a 5 node swarm as we can easily test by running the command
docker node ls
on node1
. We should see something similar to this
We can see that we have one master node (node1) that is also the leader in a quorum of master nodes. The other 4 nodes are all worker nodes. Worker nodes can be promoted to master nodes and vice versa. In a production environment we should have at least 3 master nodes for high availability since master nodes store all the information about the swarm and its state. Let’s promote node2
and node3
to master status using this command
docker node promote node2 node3
and then double check the new status with docker node ls
where we should see this
Evidently node2
and node3
are now also master nodes and are “reachable”. node1
still remains the leader, but if for some reason it goes away then node2
or node3
will take the leader position. Let’s try that and use docker-machine
to stop node1
docker-machine stop node1
by doing this we are of course kicked out of our ssh session on node1. Let’s ssh into node2, one of the other leaders and again use docker node ls
to check the new status. You might need to give it some time to reach the final state
And we see that now the former leader node1 is unreachable while node3 became the new leader. Let’s start node1 again and after it has stabilized it will be a master again but not the leader. Node3 will remain leader.
Private Registry
When we are building Docker images we have to store them somewhere. Usually we can use Docker Hub to store public images for free or if we have a private account we can also store private images there. But if that is not OK and we want to have our own private registry for images then we can use the Docker registry in our environment. Docker registry is OSS and is run as a container. By default images are stored in the container and thus will be lost if the container is removed or crashes. But it is very easy to configure the container to use a durable storage for the images like AWS S3 or so. To run the OSS version of Docker registry as a service listening on port 5000 use this command.
docker service create --name registry --publish 5000:5000 registry:2
By publishing the port on the swarm we make sure the registry can be reached from each node. This is a “trick” so each node can communicate with the registry via localhost:5000
and we don’t have to use TLS.
Once the service is running we can now (on any node of our cluster) execute the following command to get a list of all images
curl localhost:5000/v2/_catalog
Let’s test the registry. We can try to push e.g. the official alpine which we first want to pull from Docker hub
docker pull alpine
We use the alpine image since it is so small. Now to be able to push it to our private registry we first need to tag the image
docker tag alpine localhost:5000/alpine
and then push it
docker push localhost:5000/alpine
If we now query the registry we get this
Building and pushing services
Let’s first clone the sample application
git clone https://github.com/jpetazzo/orchestration-workshop
cd into the source directory of the repository
cd orchestration-workshop/dockercoins
and then build and push all the services using this script
If we query the registry again we should now find all the services just built in the catalog too.
Summary
In part 1 I have demonstrated how we can easily create a new Docker swarm on our development machine using VirtualBox and the Docker SwarmKit. We have learned how we can add nodes to the swarm and promote or demote them from worker to to master status and vice versa. We have also experienced what happens if the leader of the master nodes disappears. Another master node takes its role and the swarm continues to work just normally. Finally we have installed a private Docker registry in our cluster which we’ll be using to store our Docker images that we build from the sample application.
In part 2 we will use the new docker service
keyword to create, scale, and manipulate individual services. Stay tuned.