Intro to Docker 1.12 and Swarm mode

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
  • Scaling
  • Desired state reconciliation
  • Multi-host networking
  • Service discovery
  • Load balancing (Container-native load balancing.)
  • Secure by default (Automated key rotation.)
  • Rolling updates

Multi-Host Networking??

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.

alt

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)

cli

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.

cli

$ 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

the 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

Using 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 manager1

$ 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

The join-token command prints out the command we need to run on manager and 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.

cli

$ 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 (:8080).

http://192.168.99.100:8080

or

$ http://192.168.99.101:8080

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.

In my next article, I will discuss in more depth the inner workings of load balancing, the network internals, and what really makes docker swarm work.

*Photo credit to @kaptopz.

Wesley Blake

Principal Cloud Architect | DevOps Engineer | Sysadmin | Linux and Open Source advocate | Craft Home Brewer

Subscribe to Strato Technology | DevOps

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!