Red Green Repeat Adventures of a Spec Driven Junkie

Getting Started with Docker Swarm

Quick introduction to getting around Docker Swarm, Docker’s native clustering system, similar to Kubernetes & Apache Mesos.

Docker Swarm logo

A quick definition:

swarm is a simple tool which controls a cluster of Docker hosts and exposes it as a single “virtual” host.

source

For me, Docker is a bit of a shift in thinking compared to a regular virtualbox. Docker Swarm takes the container applies concept to multi-node networked instances.

Requirements

For this article, I will be working with Docker Swarm within a single virtualbox, just to keep things simple.

  • Virtualbox installed
  • vagrant installed
  • Download this Vagrantfile

Getting Started

With everything in the requirements section completed, in the folder containing the Vagrantfile, run this command in the terminal:

$ vagrant up manager
... # lots of build messages
$ vagrant ssh manager

The rest of the article will work within the manager virtualbox.

Showing Docker Swarm Services

In Docker Swarm, every running container(s) is a service. Instead of Docker managing them directly, Docker Swarm uses the Docker API to create containers from images.

To see Docker Swarm services, run: docker swarm ls

vagrant@manager:/vagrant$ sudo docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
ID the container ID
NAME the unique name for the service
MODE which mode the service is in: replicated or global
REPLICAS the number of replicas the service is running in
IMAGE the Docker image used for the service
PORTS which ports connect the host to the service

more details on service modes

Contrast this with docker ps

vagrant@manager:/vagrant$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

So, different information for different use cases.

Start nginx Service

Now that we know how to see what Docker Swarm services are running, let’s start one up!

I’m going to use a simple & well-known image: nginx. I would like to focus on the other parts of the Docker Swarm commands before thinking about how to create an image for the service.

To create a Docker Swarm service with nginx, run command: docker service create <image name>

vagrant@manager:/vagrant$ sudo docker service create nginx
7ctrcae7sob0tjabccqfea1pd
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged
vagrant@manager:/vagrant$

Oooh, that loks a bit different. There’s a nice progress bar and a message stating the service status. Service converged

nginx Service Status

Let’s check out what the status of the service using docker service ls.

vagrant@manager:/vagrant$ sudo docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
7ctrcae7sob0        objective_hermann   replicated          1/1                 nginx:latest

Oooh, that’s cool. The service: replicated and it’s running on 1/1 replicas.

docker ps

Let’s checkout what docker ps shows:

vagrant@manager:/vagrant$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS               NAMES
5bb3e80c076d        nginx:latest        "nginx -g 'daemon of…"   About a minute ago   Up About a minute   80/tcp              objective_hermann.1.6agqbzmx8qiazhwwncdegknwa

Oooh, that’s interesting. The names match: objective_hermann, but the docker ps command lists and additional ending: .1.6agqbzmx8qiazhwwncdegknwa, so the container and service are not 1:1. The container ID is different than the service ID.

Docker Service ps

Docker Swarm has its own ps command, which gives different information:

vagrant@manager:/vagrant$ sudo docker service ps objective_hermann
ID                  NAME                  IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS
6agqbzmx8qia        objective_hermann.1   nginx:latest        manager             Running             Running about a minute ago
ID This
NAME Similar to the docker service ls and docker ps difference, this has only .1 added to its name
IMAGE This lists the image used for the service
NODE Nodes this service running on
DESIRED STATE The desired state of this service: running or shutdown
CURRENT STATE Current state of the service
ERROR Error meessage from creating the service
PORTS Ports connecting the host to the service

Stopping Docker Service

Now that we have a Docker Service running in Swarm, how can we stop it?

By using the command: docker service rm <service name>, so to remove the objective_hermann service:

vagrant@manager:/vagrant$ sudo docker service rm objective_hermann
objective_hermann

and checking:

vagrant@manager:/vagrant$ sudo docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS

That was easy!

Accessing Service

nginx that is not accessible through any ports is not fun. Let’s create the service again with ports mapped using the option: --publish <host port number>:<service port number>

vagrant@manager:/vagrant$ sudo docker service create --publish 80:80 nginx

m6e5hvq8jnwahuy7x93rb1yk6
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged

Let’s check by using a quick curl to see what nginx returns:

vagrant@manager:/vagrant$ curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

More Formal Format

Another, more formal and explicit version of the same command:

vagrant@manager:/vagrant$ sudo docker service create --publish published=80,target=80 nginx

Updating Service Port

If the service is already running, say you forgot to specify ports when creating the service, use the docker service update command with publish-add to update the service:

vagrant@manager:~$ sudo docker service create nginx
s65up92ko7hxdi2lei91358el
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged
vagrant@manager:~$ sudo docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
s65up92ko7hx        eloquent_bohr       replicated          1/1                 nginx:latest
vagrant@manager:~$ sudo docker service update --publish-add 80:80 eloquent_bohr
eloquent_bohr
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged
vagrant@manager:~$ sudo docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
s65up92ko7hx        eloquent_bohr       replicated          1/1                 nginx:latest        *:80->80/tcp

It’s basically the same as if you manually stopped the service and restarted with the right fields, but in update case, the service ID does not change.

Conclusion

This time, I went over how in a single node Docker Swarm to:

  • list services
  • create a new Docker Swarm from the nginx image
  • make the service accessible by specifying or updating its ports
  • delete services that are in a single node Docker Swarm.

Docker Swarm builds on the concepts of Docker, and although commands are similar, like ps is in both docker and docker service, it’s intended usage is different.

I chose to focus on using a known Docker image, nginx, to learn about Docker Swarm.

Next time, I will focus on how to create a service in Docker Swarm from your Docker image.