Docker 1.12 is in general availability and ready for production. Swarm has been around in previous versions of docker, however its implementation was slightly more complicated, requiring you to run swarm as container.
So why all the rage about Docker 1.12 and Swarm? Lets look at some of the feature highlights:
- Cluster management integrated with Docker Engine
- Decentralized design
- Declarative service model
- Desired state reconciliation
- Multi-host networking
- Service discovery
- Load balancing (Container-native load balancing.)
- Secure by default (Automated key rotation.)
- Rolling updates
To me, this is by far one of the greatest enhancements to Docker. Amongst all the other awesome features built in, Swarm is now native to Docker, and this means it could be a really solid container orchestration service, even competing with the likes of Kubernetes, Rancher and so on.
Another great feature swarm feature enforces, is TLS mutual authentication and encryption to secure communications between itself and all other nodes. There is also cert rotation, which is awesome especially from a compliance point of view. The TLS encryption also ensures that the nodes are connecting to the correct managers in the swarm.
Docker / Swarm has seriously improved container networking, and the ability for containers to be load balanced and networked across multiple hosts within your swarm cluster, simplifies infrastructure that would have been a bit more complicated to setup in the past.
What exactly is a Swarm?
A swarm is composed of nodes joined together. A node is the base unit of computation for a swarm. a node in its simplest form is any machine running docker 1.12. (ie a Swarm Cluster)
Lets see what swarm can do:
$ docker swarm Usage: docker swarm COMMAND Manage Docker Swarm Options: --help Print usage Commands: init Initialize a swarm join Join a swarm as a node and/or manager join-token Manage join tokens update Update the swarm leave Leave a swarm Run 'docker swarm COMMAND --help' for more information on a command.
We have the ability to create and intialise a swarm, join nodes as workers/managers to swarm, update the swarm, or tell a node to leave the swarm. Pretty simple…
And what is a node?
A node is the base unit of computation for a swarm. a node in its simplest form is any machine running docker 1.12.
There are two types of nodes in a cluster:
- Manager nodes: responsible for the scheduling/orchestration etc.
- Worker nodes: only responsible for taking work, executing it, and reporting back.
$ docker node Usage: docker node COMMAND Manage Docker Swarm nodes Options: --help Print usage Commands: demote Demote a node from manager in the swarm inspect Display detailed information on one or more nodes ls List nodes in the swarm promote Promote a node to a manager in the swarm rm Remove a node from the swarm ps List tasks running on a node update Update a node
docker node has some useful things too. We can ls all nodes in the swarm, promote a worker node, to a manager node in the swarm, we can remove nodes from a swarm, we can inspect detailed info of one or more nodes in the swarm, we can also update a ndoe or view a list of running tasks on a node. Awesome!
In my next post, I will deep-dive into the network topology of a Swarm, but for now, lets see it in action!
I currently use
docker-machine for test purposes. Docker-machine is a great tool that can use various drivers to spin up docker ready machines. I use the virtual box driver by default, and
docker-machine allows me to spin up virtual machines that I can test. Head over to Docker to get started with Docker machine.
Lets create a swarm cluster
docker-machine lets create a some hosts to work with:
$ docker-machine create -d virtualbox manager1 $ docker-machine create -d virtualbox worker1 $ docker-machine create -d virtualbox worker2 $ docker-machine create -d virtualbox worker3 $ docker-machine ls NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS manager1 - virtualbox Running tcp://192.168.99.100:2376 v1.12.0 worker1 - virtualbox Running tcp://192.168.99.101:2376 v1.12.0 worker2 - virtualbox Running tcp://192.168.99.102:2376 v1.12.0 worker3 - virtualbox Running tcp://192.168.99.103:2376 v1.12.0
We now have 4 docker machines running the latest version of docker.
Now we need to initialise our swarm. We are going to do this on the manager node. In this case, I have named my host
manager1 to be the manager.
Once we have all our machines running, lets initialise a swarm on the host we decided to be the manager node for the swarm (in this case
$ eval $(docker-machine env manager1) $ docker swarm init \ --advertise-addr $(docker-machine ip manager1) \ --listen-addr $(docker-machine ip manager1):2377
or ssh directly onto the host:
$ docker swarm init \ --advertise-addr 192.168.99.100 \ --listen-add 192.168.99.100:2377
In order to join nodes to our swarm, we need generate a swarm token.
To create the swarm token for manager nodes we run the join-token command on our initial manager:
$ docker swarm join-token manager To add a manager to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-4x502sygb5ws0wwmpevndnp4d55bbxsmts339ylpuh37kiy5sv-79ugs5f3pwvv5jrom5b8dinhs \ 192.168.99.100:2377
To get the worker join-token we run the following command:
$ docker swarm join-token worker To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-4x502sygb5ws0wwmpevndnp4d55bbxsmts339ylpuh37kiy5sv-dl7jurksix80niuo2ncj9v0ak \ 192.168.99.100:2377
join-token command prints out the command we need to run on
worker nodes. So from that output, we can now join nodes to the swarm. For this example, Im going to connect the the remaining three machines I created, as worker nodes, and run the join command with the worker join token:
# start with worker1 $ eval $(docker-machine env worker1) $ docker swarm join \ --token SWMTKN-1-4x502sygb5ws0wwmpevndnp4d55bbxsmts339ylpuh37kiy5sv-dl7jurksix80niuo2ncj9v0ak \ 192.168.99.100:2377 # and then worker2 $ eval $(docker-machine env worker2) $ docker swarm join \ --token SWMTKN-1-4x502sygb5ws0wwmpevndnp4d55bbxsmts339ylpuh37kiy5sv-dl7jurksix80niuo2ncj9v0ak \ 192.168.99.100:2377 # and finally, worker3 $ eval $(docker-machine env worker3) $ docker swarm join \ --token SWMTKN-1-4x502sygb5ws0wwmpevndnp4d55bbxsmts339ylpuh37kiy5sv-dl7jurksix80niuo2ncj9v0ak \ 192.168.99.100:2377
We now successfully have a Swarm cluster! Lets view some information about our swarm:
$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 97zmo0c36dfj675dpg2q2rtg0 worker2 Ready Active c0q0ckwe3h39fbu9sv33069fo worker3 Ready Active cjzcy20zu8uarq6g2l8z4eg9n * manager1 Ready Active Leader dmt4kjgeeem6bsqb2jcmvzuj1 worker1 Ready Active
Now that we have a swarm running, lets dive into what makes Swarm mode awesome.
What is a service
A service defines tasks that are executed in the swarm.
$ docker service Usage: docker service COMMAND Manage Docker services Options: --help Print usage Commands: create Create a new service inspect Display detailed information on one or more services ps List the tasks of a service ls List services rm Remove a service scale Scale one or multiple services update Update a service
What is a task?
A task is the scheduling and execution of a service on a node.
$ docker service ls ID NAME REPLICAS IMAGE COMMAND 1q10x534o7r7 vote 4/4 instavote/vote
Lets create a service:
For illustrative purposes, Im going to use an image use the instavote/vote image by the Richard Nelson. Its a great image to illustrate load balancing, scaling and orchestration of swarm mode.
We will use the
docker service create command to create a service.
docker service create \ --name vote \ -p 8080:80 \ instavote/vote
Once the image has been pulled and the serice has started, if we run
docker service ls, we will see the replica count and service id of our services
$ docker service ls ID NAME REPLICAS IMAGE COMMAND 1q10x534o7r7 vote 1/1 instavote/vote
But we want to know where the service is running, and what state it is…
$ docker service ps vote ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR 4a4kv8mul0z87l5xx6aetkcnq vote.1 instavote/vote worker1 Running Running 7 minutes ago
From that, we can tell that one container is running, as expected, it is running on the
worker1 node in our swarm, its in a running state (sweet!), and its been running for since 7mins ago. Great!
But now, lets see how we can scale up our service. Lets run the
docker scale command to increase the replicas to our desired state.
$ docker service scale vote=8 vote scaled to 8
Lets verify that this worked:
$ docker service ls ID NAME REPLICAS IMAGE COMMAND 1q10x534o7r7 vote 8/8 instavote/vote
NOTE: you can scale multiple services with one command if you need to
$ docker service scale vote=8 redis=3
That would scale our vote service to 8 and our redis service to 3. Neat! You can start to get the picture of how orchestration is now built into to Docker 1.12
Now that we have our services running, lets hit any of the IP addresses in our swarm, with the specified public port (
The swarm handles the requests across hosts within network. Meaning if I hit http://192.168.99.101:8080, but this host doesnt have our
vote container running, it will serve the request from a host which does have the service and task running. It load balances across the network, and has service discovery thanks to the embedded DNS and routing mesh. So hosts can communicate with services running on other hosts!
Refresh your browser a few times (without changing your URL), and pay attention to the container that is displayed. You will notice that you will be served a new container ID each request. This is the load balancing in action! Change your URL to another host’s in your swarm, and refresh. You will notice the same events occurring. Although this is a very simple example, you can understand the benefit of how Swarm can simplify our lives! Scale the service down to even one host, and you will still be able to access the task!
What about rolling updates?
We have the ability to perform a rolling update across services, we can set up how many tasks to update simultaneously using the -
-update-parallelism parameter, and provide a delay between these updates using the
--update-delay parameter in our command.
So lets update our vote service, to a new a image, by updating two tasks at a time, with a delay of 5 seconds.
docker service update --update-parallelism 2 --update-delay 5s --image instavote/vote:movies vote
So what is actually happening? :
$ docker service ps vote ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR bzbiaatsepuelp5xed2r3buoz vote.1 instavote/vote:movies worker1 Running Running 5 seconds ago 76z1q06wkwmfa3vi3takbzyja \_ vote.1 instavote/vote worker2 Shutdown Shutdown 10 seconds ago esqzhtcnhbeggm6vqzgg2in1d vote.2 instavote/vote worker2 Running Running 12 minutes ago 8kpimpn23rbblkd9ryo20f3pe vote.3 instavote/vote:movies manager1 Running Running 16 seconds ago 2izr8nj1b6rpasb2ma1fm8au5 \_ vote.3 instavote/vote worker1 Shutdown Shutdown 22 seconds ago 3exkbmpp0p3c6ykgbks61ho81 vote.4 instavote/vote:movies worker3 Running Running 16 seconds ago 0llc7vko44azbomlft2xyp5wg \_ vote.4 instavote/vote worker3 Shutdown Shutdown 22 seconds ago 7uuq8e5zwtq1y749n6qowz8e0 vote.5 instavote/vote worker3 Running Running 12 minutes ago 7w86nraco4vbiv87vuusb20z8 vote.6 instavote/vote worker1 Running Running 12 minutes ago 6e3cia1clf84ei0e3pfnqjaor vote.7 instavote/vote:movies worker1 Running Running 5 seconds ago 5jdzyeiio5fw3bq5zbrvsnghu \_ vote.7 instavote/vote manager1 Shutdown Shutdown 10 seconds ago dv50nygbudyc4amdt0p3eg7rq vote.8 instavote/vote manager1 Running Running 12 minutes ago
We can see the scheduling at hand here. It tells us the state of the running tasks, its scheduled services for updates, and will give us the state of each task at hand. After some time, all tasks will be running with the new image, and we would have had 0 down time in our rolling update.