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.
- Stop the first task
- Schedule update for stopped task
- Start the container for updated task
- If any time during the update the state is changed to
failed
, inspect the service and restart the service using the commanddocker 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.