Swarm 101 - Manage services

Second post of the tutorial Swarm for beginners. This post will cover the creation of services, update them in different ways, inspecting them, publishing ports and removing the services. Now, what's a service?

A service in a Swarm cluster is each application we want to deploy; tipically, we think of micro-services because those application should tend to be small pieces. Examples of services: API, database, front, backoffice, queues, application server…

You should follow this post after the post of how to create a cluster. In this post, we'll deal only with stateless services. If we need a database, we'll put it outside the cluster for now; replicating and synchronizing databases have other concerns that are way far from the scope of this post or tutorial (or my current knowledge :P). The same applies to static files, we can assume that they are out of the cluster (for instance in Amazon S3).

In the next examples, we're going to use docker images from the Docker Hub. First of all, let's create a service. All service management has to be done in a manager node, so we enter the server1 virtual machine:

(myhost)$ vagrant ssh server1

And now we can create the service:

(server1)$ docker service create --replicas 1 --name myping alpine ping docker.com

Let's go through the command:

  • docker service create is quite straigth forward: we want to create a service
  • –replicas 1 means that we are creating only one replica of the service in the cluster. Later, we'll go deeper into this “replica” option.
  • –name myping a unique and meaningful name for the service.
  • alpine ping docker.com indicates the images to use in the service (an alpine image) and the command to start the image.

You can see that the options are pretty similar when you run an image with plain docker. Let's see some useful commands; first, list all the services in the cluster:

(server1)$ docker service ls
ID              NAME      MODE          REPLICAS    IMAGE            PORTS
bjvi88pqv957    myping    replicated    1/1         alpine:latest

The column mode says if the service is deployed replicated or global:

  • replicated mode is used to deploy our business services. Swarm will create as many replicas as commanded, and it will distribute them among the cluster. We can find more than one replica in a node of the cluster.
  • global mode is used to deploy helpers as monitoring systems, or backups. When Swarm deploys a global service, it creates one and only one replica in every node of the cluster.

Now, let's print the status of one process:

(server1)$ docker service ps myping
ID              NAME        IMAGE            NODE       DESIRED STATE    CURRENT STATE             ERROR    PORTS
mi2hqax5l9da    myping.1    alpine:latest    server1    Running          Running 24 minutes ago

The number next to the name of the service, myping.1, is like an index of replicas of one service and the node column says in which server it's been deployed.

We can also inspect the service:

(server1)$ docker service inspect --pretty myping
ID:		bjvi88pqv957v61ey7sbapnmn
Name:		myping
Service Mode:	Replicated
 Replicas:	1
 Parallelism:	1
 On failure:	pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
 Parallelism:	1
 On failure:	pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
 Image:		alpine:latest@sha256:0b94d1d1b5eb130dd0253374552445b39470653fb1a1ec2d81490948876e462c
 Args:		ping docker.com
Endpoint Mode:	vip

Right now, this inspect is more curious than useful, because we're keeping the default settings. If you go further studying Swarm deployments, you'll find this information more meanigful.

Besides, as we are managing docker containers, we can go to the node where the container is deployed and use the docker interface to inspect the state:

(server1)$ docker ps -a

As well as creating a service, we can remove it:

(server1)$ docker service rm myping

| You cannot remove a service by removing its containers. If you delete a container, Swarm will be noticed and will create a new replica to keep the state of the service. This is part of the awesomeness of Swarm.

We can update a service changing the state (number of replicas for instance) or changing the proper service (the docker image, the command, the published ports, etc). Both cases work in the same way, with the command docker service update. Let's go through some examples. First of all, we want to create the same myping service:

(server1)$ docker service create --replicas 1 --name myping alpine ping docker.com

Now, we're going to update it to add more replicas:

(server1)$ docker service update --replicas 3 myping

You can see the status of the service:

ubuntu@server1:~$ docker service ps myping
ID              NAME        IMAGE            NODE       DESIRED STATE    CURRENT STATE                ERROR    PORTS
mi2hqax5l9da    myping.1    alpine:latest    server1    Running          Running about an hour ago
5y2ifjrrhqh2    myping.2    alpine:latest    server3    Running          Running 3 seconds ago
yt74o8vzg7lt    myping.3    alpine:latest    server2    Running          Running 3 seconds ago

Wow! Now we have three replicas, easy peasy! You can see in the name column the indexes I was talking above. Remove this service and let's try a different update. Again, the first step is creating a service:

(server1)$ docker service create --replicas 3 --name redis --update-delay 3s redis:3.0.6

The only new parameter is –update-delay which indicates the time between updating containers. According to the default settings, when we update a service, Swarm will follow these actions:

  • stop one replica
  • launch a new replica with the new image
  • wait the update-delay time (by default is 10 seconds, and I've made it just faster)
  • repeat the three previous steps until there are no old containers left

Open a new terminal and vagrant ssh server1; yes, two terminals in the same virtual machine :D. In one of them, type:

(server1)$ watch docker service ps redis

In the other terminal, let's update the service:

(server1)$ docker service update --image redis:3.0.7 redis

Now, take a look at the first terminal; you can see how Swarm is stopping a container and launching one new container; then stopping another container and so on… Congratulations! You've done great! We've only one more topic to cover in this post: routing mesh and publishing ports.

This is probably the part that I found more difficult to understand, so I'll try to make it clear. Until now, we've been creating simple services; usually, we'll need to publish a port, so the external users can reach our service; for instance, an Nginx for serving our application. Once again, let's remove all previous services, and let's create a new one:

(server1)$ docker service create --replicas 1 --name nginx --publish 8000:80 nginx

With the new –publish parameter we're exposing the port 80 of the containers in the port 8000 of the hosts (in this case, the virtual machines). To check it, open a browser and go to (the IP of the manager node); you'll see the welcome message of Nginx. Then, go to and to (server2 and server3 IPs): you'll see the same message. Notice that we only launched one replica, but you can access the service from the three nodes. This is due to the routing mesh, the system that Swarms uses to manage routes in the cluster.

Every time we create a service that exposes a port, Swarm will open the same port in all the nodes of the cluster, even if those nodes don't have any replicas of the service. In our example, we know that we can access the port 8000 of each node, even though we've only one replica. If a request goes to a node without the Ningx, the routing mesh will redirect the request to a node where an actual nginx is listening.

Mind you, this routing mesh applies only to the exposed ports; inside the cluster, the containers see each other through the overlay network, as it happens with regular docker containers.

You can inspect the nginx service, remove it, create again and update to more replicas. Try to play a bit with the commands so you can feel confortable with the Swarm interface and options. Well done! Thanks for following the tutorial up to this point, and congratulations, you've learned some interesting things about orchestration.

In the next post, you'll learn how to manage a swarm with a docker-compose.yml file with our own project, so it will be even more understandable. And feel free to drop any comments below. Happy hacking!

comments powered by Disqus