Docker Compose & Swarm

Docker Compose & Swarm

Docker Compose is designed to simplify running multi-container applications using a single command. With docker compose you use a yaml file to configure application’s services,configuration etc.Features of docker compose are:

  • Multiple isolated environment on single host.
  • Preserve volume data when containers are created.
  • Recreate containers that have changed.
  • Variables and moving composition between environment variables.
  • Orchestrate multiple containers that work together.

Swarm Mode tells docker that we will be running multiple docker engines and cooridinate operations across all of them.Swarm mode combines not only defines architecuture of the application like compose, additional to that many features like high availability,scaling,load balancing and more

Initialize Swarm: We want to tell docker to enable swarm mode, the super power mode of containers.Swarms can just be a single node,but this is not production and there is no requirement for high availability for the tutorial purpose let us consider a single node for the swarm.

Usually swarm mode consists of three manager nodes and many worker nodes, just like master slave. To initialize docker swarm mode execute the below command. docker swarm init --advertise-addr $(hostname -i), where hostname -i prints the ip address.

[node1] (local) root@192.168.0.8 ~
$ docker swarm init --advertise-addr $(hostname -i)
Swarm initialized: current node (wyx30wsjocpr2oikx16lrfk5y) is now a manager.
To add a worker to this swarm, run the following command:    

docker swarm join --token SWMTKN-1-xxxxxxxxxxxxxxxx 192.168.0.8:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instr
uctions.

Now to join any worker nodes,in the output above the command docker swarm join... is displayed to join any worker nodes to above the manager node.Execute the above command on the worker node to add the worker node to the cluster.

[node2] (local) root@192.168.0.7 ~
$ docker swarm join --token SWMTKN-1-xxxxxxxxxxxxxxxxxxxxxxxx 192.168.0.8:2377
This node joined a swarm as a worker.
  • docker node ls: displays the swarm members, here 2 members should be displayed one manager node and another worker node.
$ docker node ls
Error response from daemon: This node is not a swarm manager. Worker nodes can't beused to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager.

docker node ls command can only be executed on the manager node and not on the worker node

1. Deploy Service

After creating a swarm and adding worker nodes to the cluster, now lets deploy a service to the swarm

[node1] (local) root@192.168.0.13 ~
$ docker service create --replicas 1 --name helloworld alpine ping google.com
g4oeiuihfszu2k4f2u7fkzcxt
overall progress: 0 out of 1 tasks
overall progress: 1 out of 1 tasks
1/1: runningverify: Service converged

docker service create creates the service

--name flag names the service

--replicas flag specifies the desired state of 1 running instance

alpine ping google.com defines the service as an alpine linux container,that executes the command ping google.com.

2. Verify & Inspect

To verify the service is running or not, we use the command docker service ls to list the services running.

[node1] (local) root@192.168.0.13 ~
$ docker service ls
ID             NAME         MODE         REPLICAS   IMAGE           PORTS
g4oeiuihfszu   helloworld   replicated   1/1        alpine:latest
$ docker service inspect --pretty helloworld

ID:             g4oeiuihfszu2k4f2u7fkzcxt
Name:           helloworld
Service Mode:   Replicated
 Replicas:      1
Placement:
UpdateConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:         alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b
 Args:          ping google.com
 Init:          false
Resources:
Endpoint Mode:  vip

Displays basic information about the service, like name, replicas, container specs like image and args etc. To inspect the service in json format remove the --pretty flag.

$ docker service ps helloworld
ID             NAME           IMAGE           NODE      DESIRED STATE   CURRENT STATE           ERROR     PORTS
puzv0ft6owau   helloworld.1   alpine:latest   node2     Running         Running 22 minutes ago

Lists the tasks that are running as part of the specified services.

3. Scale Service

docker service scale <SERVICE-ID>=<NUMBER-OF-TASKS> is the command to scale the service running.

[node1] (local) root@192.168.0.13 ~
$ docker service ps helloworld
ID             NAME           IMAGE           NODE      DESIRED STATE   CURRENT STATE            ERROR     PORTS
puzv0ft6owau   helloworld.1   alpine:latest   node2     Running         Running 29 minutes ago

[node1] (local) root@192.168.0.13 ~
$ docker service scale helloworld=5
helloworld scaled to 5overall progress: 5 out of 5 tasks
1/5: running   [==================================================>]2/5: running   [==================================================>]
3/5: running   [==================================================>]
4/5: running   [==================================================>]
5/5: running   [==================================================>]
verify: Service converged

[node1] (local) root@192.168.0.13 ~
$ docker service ps helloworld
ID             NAME           IMAGE           NODE      DESIRED STATE   CURRENT STATE            ERROR     PORTS
puzv0ft6owau   helloworld.1   alpine:latest   node2     Running         Running 29 minutes ago
xl8wu6wzhv50   helloworld.2   alpine:latest   node1     Running         Running 9 seconds ago
sbtrkvwemt3m   helloworld.3   alpine:latest   node2     Running         Running 9 seconds ago
jw3t27spiu9i   helloworld.4   alpine:latest   node1     Running         Running 8 seconds ago
em82lpk3bc5z   helloworld.5   alpine:latest   node1     Running         Running 7 seconds ago
[node1] (local) root@192.168.0.13 ~

If you observe after upgrading the scale to 5 the number of services are increased, where the services are increased to 5 starting with helloworld.1 to helloworld.2. After upgrading the scalability,4 new task are created, total of 5 alpine instances.

4. Delete the service

To delete a docker swarm service use the command docker service rm <service-name>and to verify the deletion of the service use the inspect command.

[node1] (local) root@192.168.0.13 ~
$ docker service rm helloworld
helloworld

[node1] (local) root@192.168.0.13 ~
$ docker service inspect helloworld
[]
Status: Error: no such service: helloworld, Code: 1

5. Rolling Updates

To reduce the downtime of an application and also to introduce minimal downtime for rolling updates while docker swarm. Here lets us take an example image of alpine:3.17.7 and with the command to ping google.com, to demonstrate the rolling updates,let us update the image to alpine:3.18.6 while the container is running.

Pre-requisites are the enable the docker swarm mode, and add a worker node to the cluster.

[node1] (local) root@192.168.0.12 ~
$ docker service create --replicas 1 --name helloworld alpine:3.17.7 ping google.com
l9zrd6xtqkc23fns2ntmvavze
overall progress: 1 out of 1 tasks
1/1: runningverify: Service converged

Let us create a docker service with the number of replications as 1 and with the name of the service as helloworld using the image alpine:3.17.7 with the args ping google.com which runs inside the container.

Next step let us inspect the docker service, which displays information about the service state,number of replications, parallelism, container specification like image(alpine:3.17.7) and args(ping google.com).

$ docker service inspect --pretty helloworld

ID:             l9zrd6xtqkc23fns2ntmvavze
Name:           helloworld
Service Mode:   Replicated
 Replicas:      1
Placement:
UpdateConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:         alpine:3.17.7@sha256:53cf9478b76f4c8fae126acbdfb79bed6e69e628faff572ebe4a029d3d247d98
 Args:          ping google.com
 Init:          false
Resources:
Endpoint Mode:  vip

Now let us roll up the update, by updating the image to alpine:3.18.6, the command to update the image is docker service update --image <image:latest_tag> <service_name>

[node1] (local) root@192.168.0.12 ~
$ docker service update --image alpine:3.18.6 helloworld
helloworld
overall progress: 1 out of 1 tasks
1/1: running
verify: Service converged
[node1] (local) root@192.168.0.12 ~
$ docker service inspect --pretty helloworld

ID:             l9zrd6xtqkc23fns2ntmvavze
Name:           helloworld
Service Mode:   Replicated
 Replicas:      1
UpdateStatus:
 State:         completed
 Started:       22 seconds ago
 Completed:     5 seconds ago
 Message:       update completed
Placement:
UpdateConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:         alpine:3.18.6@sha256:11e21d7b981a59554b3f822c49f6e9f57b6068bb74f49c4cd5cc4c663c7e5160
 Args:          ping google.com
 Init:          false
Resources:
Endpoint Mode:  vip

If observed after inspecting the service, the container specification the image is updated to 3.18.6 from 3.17.7

[node1] (local) root@192.168.0.12 ~
$ docker service ps helloworld
ID             NAME               IMAGE           NODE      DESIRED STATE   CURRENTSTATE                 ERROR     PORTS
z7bfdjqy03ej   helloworld.1       alpine:3.18.6   node1     Running         Runningabout a minute ago
tt12qc43w4b1    \_ helloworld.1   alpine:3.17.7   node1     Shutdown        Shutdown about a minute ago

Now after checking the docker process the container with ID tt12qc43w4b1 is shutdown while the container with id z7bfdjqy03ej is running.

Steps for rolling updates.

  1. Stop the first task
  2. Schedule update for stopped task
  3. Start the container for updated task
  4. If any time during the update the state is changed to failed, inspect the service and restart the service using the command docker service update <service-name>.

Rollback Updates

To continue from the above rolling updates, if many such cases we would want to rollback to the previous state of the service, due to a bug etc, in our example we would want to rollback to our previous state which is from alpine:3.18.6 to alpine:3.17.7 we use the command docker service rollback <service-name>

[node1] (local) root@192.168.0.12 ~
$ docker serviec rollback helloworld
docker: 'serviec' is not a docker command.
See 'docker --help'
[node1] (local) root@192.168.0.12 ~
$ docker service rollback helloworld
helloworld
rollback: manually requested rollback
overall progress: rolling back update: 1 out of 1 tasks
1/1: running
verify: Service converged

[node1] (local) root@192.168.0.12 ~
$ docker service inspect --pretty helloworld

ID:             l9zrd6xtqkc23fns2ntmvavze
Name:           helloworld
Service Mode:   Replicated
 Replicas:      1
UpdateStatus:
 State:         rollback_completed
 Started:       About a minute ago
 Message:       rollback completed
Placement:
UpdateConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:         alpine:3.17.7@sha256:53cf9478b76f4c8fae126acbdfb79bed6e69e628faff572ebe4a029d3d247d98
 Args:          ping google.com
 Init:          false
Resources:
Endpoint Mode:  vip

Upon inspecting the service again, let us check the container specification we can find the the image has been rolled back to alpine:3.17.7 from 3.18.6.

After executing this command, the service is reverted to the configuration that was in place before the most recent docker service update command.

logs

docker service logs <service-name> displays the logs of the container, here in our example it is docker service logs helloworld command displays all the logs of the container to STDOUT.