Try   HackMD

Day 2 - part C: Docker Swarm to manage multiple containers

tags: semiotmic2022

Based on:
https://github.com/docker/labs/blob/master/swarm-mode/beginner-tutorial/README.md
https://docs.docker.com/engine/swarm/

Check out the documentation on Docker Swarm Mode for more information.

Create your own Docker ID at https://hub.docker.com/signup and…

Since this example would require various machine it can be done online using: https://labs.play-with-docker.com/

What is a Docker Swarm?

Docker swarm is a container orchestration tool, meaning that it allows the user to manage multiple containers deployed across multiple host machines.

A swarm consists of multiple Docker hosts which run in swarm mode and act as managers (to manage membership and delegation) and workers (which run swarm services). A given Docker host can be a manager, a worker, or perform both roles. When you create a service, you define its optimal state (number of replicas, network and storage resources available to it, ports the service exposes to the outside world, and more). Docker works to maintain that desired state. For instance, if a worker node becomes unavailable, Docker schedules that node’s tasks on other nodes.
A task is a running container which is part of a swarm service and managed by a swarm manager, as opposed to a standalone container.


One of the key advantages of swarm services over standalone containers is that you can modify a service’s configuration, including the networks and volumes it is connected to, without the need to manually restart the service. Docker will update the configuration, stop the service tasks with the out of date configuration, and create new ones matching the desired configuration.


When Docker is running in swarm mode, you can still run standalone containers on any of the Docker hosts participating in the swarm, as well as swarm services. A key difference between standalone containers and swarm services is that only swarm managers can manage a swarm, while standalone containers can be started on any daemon.


You can use the Docker CLI to create a swarm, deploy application services to a swarm, and manage swarm behavior.
In the same way that you can use Docker Compose to define and run containers, you can define and run Swarm service stacks.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

One of the key benefits associated with the operation of a docker swarm is the high level of availability offered for applications.

About data

Swarm Mode itself does not do anything different with volumes, it runs any volume mount command you provide on the node where the container is running. If your volume mount is local to that node, then your data will be saved locally on that node. There is no built in functionality to move data between nodes automatically.

We will not consider this detail here. If interested, a good starting point is this: https://docs.docker.com/engine/swarm/services/#give-a-service-access-to-volumes-or-bind-mounts
or this:
https://devopsian.net/posts/share-persistent-storage-volumes-in-swarm/

Creating the nodes and Swarm

We start creating 5 nodes (the maximum allowed) to get something like this (IP addresses will vary):

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

We will now create a swarm by initializing it on the first node (node1). This is done using the command:

[node1] $ docker swarm init \ --listen-addr <IP_node1> --advertise-addr <IP_node1>

we have to explicitly indicate the addresses since the nodes we are using have multiple addresses on different interfaces.

We'll get:

Swarm initialized: current node (mopd8x5wn62zef4euks9i30vq) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-5thjr9bbckyfxfx2sqidv9gbh3thw5hm885hcijxpkgdppt886-7dtz99cahnr3hvsh6bt6fe0f2 192.168.0.13:2377

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

So, to get the token for the managers we do:

[node1] $ docker swarm join-token manager To add a manager to this swarm, run the following command: docker swarm join --token SWMTKN-1-2f4tkho405ez9hr9v3g42ym4quoodqsghefm2kvglzqohnmo7r-2knif0bnekclbqklf6wivaj9x 192.168.0.13:2377

WARNING: the actual values for the token returned and shown from here on can obviously change!

We will now create a swarm with 3 managers (red boxes) and 2 workers (grey circles) with the command obtained above:







%0



node1

node1



node4

node4



node1->node4





node5

node5



node1->node5





node2

node2



node2->node4





node2->node5





node3

node3



node3->node4





node3->node5





To show the members of swarm, from node1:

[node1] $ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION vz9ii3frm4r7v2jx9brszwtip * node1 Ready Active Leader 20.10.0 9guxhwn7g47q87o6xsvirg5mn node2 Ready Active Reachable 20.10.0 96myll5dzbzfec7q08e8ucgcj node3 Ready Active Reachable 20.10.0 h0mcls38aesrustmlmx823ui5 node4 Ready Active 20.10.0 6k01qk0gclz9f6ychkbktjhv8 node5 Ready Active 20.10.0

From now on, to help understand what happen during this seminar, we will use a tool called Docker Swarm Visualizer, and since we already have a swarm, we create a service with it with the command:

[node1] $ docker service create \ --name=viz \ --publish=8080:8080/tcp \ --constraint=node.role==manager \ --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \ dockersamples/visualizer

after a few seconds, we'll have a web page available that looks like this:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

We now create a new single service called web that runs the latest nginx. We are doing this in the manager node node1:

[node1] $ docker service create -p 80:80 --name web nginx:latest zvchlmwdtfz2hlc4lyculozky overall progress: 1 out of 1 tasks 1/1: running verify: Service converged

and:

[node1] $ docker service ls ID NAME MODE REPLICAS IMAGE PORTS 1i9vcslauzx4 viz replicated 1/1 dockersamples/visualizer:latest *:8080->8080/tcp tew0o5yjcd1p web replicated 1/1 nginx:latest *:80->80/tcp

Now you can see that from any of the nodes we have port 80 open and if we access it, will get the nginx welcome page:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

You can actually load any of the node ip addresses and get the same result because of Swarm Mode's Routing Mesh.

Scaling services

Now, let's scale the service:

[node1] $ docker service scale web=10 web scaled to 10 overall progress: 10 out of 10 tasks 1/10: running 2/10: running 3/10: running 4/10: running 5/10: running 6/10: running 7/10: running 8/10: running 9/10: running 10/10: running verify: Service converged

and:

[node1] $ docker service ls ID NAME MODE REPLICAS IMAGE PORTS 1i9vcslauzx4 viz replicated 1/1 dockersamples/visualizer:latest *:8080->8080/tcp tew0o5yjcd1p web replicated 10/10 nginx:latest *:80->80/tcp

Docker has spread the 10 services evenly over all of the nodes

[node1] $ docker service ps web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS kwgucargcd71 web.1 nginx:latest node4 Running Running 4 minutes ago yla2e36xrv73 web.2 nginx:latest node5 Running Running about a minute ago jzkvp5h1y2o0 web.3 nginx:latest node3 Running Running about a minute ago aeopsb0gnip2 web.4 nginx:latest node2 Running Running about a minute ago 26uv5aujn6vf web.5 nginx:latest node5 Running Running about a minute ago 9l91jgq4z39e web.6 nginx:latest node4 Running Running about a minute ago mk01nrm91stx web.7 nginx:latest node1 Running Running about a minute ago ru8t79l4ltzo web.8 nginx:latest node1 Running Running about a minute ago 2xa6pqo4rjfi web.9 nginx:latest node3 Running Running about a minute ago vlazyjipa91w web.10 nginx:latest node2 Running Running about a minute ago

We can also do a scale up or down by doing:

[node1] $ docker service scale web=5 web scaled to 5 overall progress: 5 out of 5 tasks 1/5: running 2/5: running 3/5: running 4/5: running 5/5: running verify: Service converged

In this moment the viz process is executing in node1. If we kill this service, the swarm will recreate it automatically in the same node or in another one of the swarm:

[node1] $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 373f2e02b32c nginx:latest "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 80/tcp web.7.mk01nrm91stxpuo0qjru96mom 5f3ee10fa4f5 dockersamples/visualizer:latest "npm start" 10 minutes ago Up 10 minutes (healthy) 8080/tcp viz.1.1voq9cg02sjhi9kbeiyc6cq85 [node1] $ docker stop 5f3ee10fa4f5 5f3ee10fa4f5 [node1] $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 373f2e02b32c nginx:latest "/docker-entrypoint.…" 5 minutes ago Up 5 minutes 80/tcp web.7.mk01nrm91stxpuo0qjru96mom [node1] $ docker service ps viz ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 3azlu5dipw1a viz.1 dockersamples/visualizer:latest node2 Running Starting 17 seconds ago 1voq9cg02sjh \_ viz.1 dockersamples/visualizer:latest node1 Shutdown Complete 36 seconds ago

Adding a new service

We create now another service based on redis by doing:

[node1] $ docker service create \ --replicas 3 \ --name redis \ --update-delay 10s \ redis:3.0.6 odbkv9uqhasiup238rbt8jcep overall progress: 3 out of 3 tasks 1/3: running [==================================================>] 2/3: running [==================================================>] 3/3: running [==================================================>] verify: Service converged [node1] $ docker service ls ID NAME MODE REPLICAS IMAGE PORTS odbkv9uqhasi redis replicated 3/3 redis:3.0.6 1i9vcslauzx4 viz replicated 1/1 dockersamples/visualizer:latest *:8080->8080/tcp tew0o5yjcd1p web replicated 5/5 nginx:latest *:80->80/tcp [node1] $ docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS d6achzobaxvy redis.1 redis:3.0.6 node1 Running Running about a minute ago pz12mhdq08o2 redis.2 redis:3.0.6 node4 Running Running about a minute ago 209m1diu1iz2 redis.3 redis:3.0.6 node3 Running Running about a minute ago

Updating a service

With swarm we can update automatically the version of the service that is currently executing, by doing:

[node1] $ docker service update --image redis:3.0.7 redis redis overall progress: 3 out of 3 tasks 1/3: running [==================================================>] 2/3: running [==================================================>] 3/3: running [==================================================>] verify: Service converged [node1] $ docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS f95vu5z6xpqj redis.1 redis:3.0.7 node1 Running Running about a minute ago d6achzobaxvy \_ redis.1 redis:3.0.6 node1 Shutdown Shutdown about a minute ago 1f6youskoht0 redis.2 redis:3.0.7 node4 Running Running about a minute ago pz12mhdq08o2 \_ redis.2 redis:3.0.6 node4 Shutdown Shutdown about a minute ago 97qc6hqts5xy redis.3 redis:3.0.7 node3 Running Running 2 minutes ago 209m1diu1iz2 \_ redis.3 redis:3.0.6 node3 Shutdown Shutdown 2 minutes ago

Draining a node

You can also drain a particular node, that is remove all services from that node. The services will automatically be rescheduled on the other nodes.

For example, starting from:

if we drain all services from node2 doing:

[node2] $ docker node update --availability drain node2

we will get (after a few seconds):

To bring node2 back online and show it's new availability, we have to do:

[node1] $ docker node update --availability active node2 node2 [node1] $ docker node inspect node2 --pretty ID: pectmlqbjc6oh0dsjrg5ec8bt Hostname: node2 Joined at: 2021-04-15 14:52:15.365686958 +0000 utc Status: State: Ready Availability: Active Address: 192.168.0.17 Manager Status: Address: 192.168.0.17:2377 Raft Status: Reachable Leader: No ...

There is still a lot more:

With Docker swarm you can also:

  • Change node availability:
    • drain a manager node so that only performs swarm management tasks and is unavailable for task assignment.
    • drain a node so you can take it down for maintenance.
    • pause a node so it can’t receive new tasks.
    • restore unavailable or paused nodes available status.
  • Promote or demote a node:
    • You can promote a worker node to the manager role. This is useful when a manager node becomes unavailable or if you want to take a manager offline for maintenance. Similarly, you can demote a manager node to the worker role.
  • a node can leave a swarm with: docker swarm leave. After a node leaves the swarm, you can run the docker node rm command on a manager node to remove the node from the node list.
  • Add manager nodes for fault tolerance
  • Remove a manager:
[node1] $ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION vz9ii3frm4r7v2jx9brszwtip * node1 Ready Active Leader 20.10.0 9guxhwn7g47q87o6xsvirg5mn node2 Ready Active Reachable 20.10.0 96myll5dzbzfec7q08e8ucgcj node3 Ready Active Reachable 20.10.0 h0mcls38aesrustmlmx823ui5 node4 Ready Active 20.10.0 6k01qk0gclz9f6ychkbktjhv8 node5 Down Active 20.10.0 [node1] $ docker swarm leave --force Node left the swarm.

now, if we go to another manager:

[node2] $ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION vz9ii3frm4r7v2jx9brszwtip node1 Down Active Unreachable 20.10.0 9guxhwn7g47q87o6xsvirg5mn * node2 Ready Active Leader 20.10.0 96myll5dzbzfec7q08e8ucgcj node3 Ready Active Reachable 20.10.0 h0mcls38aesrustmlmx823ui5 node4 Ready Active 20.10.0 6k01qk0gclz9f6ychkbktjhv8 node5 Down Active 20.10.0

much more!

You don't need to use the Docker CLI to perform these operations. You can use docker stack deploy --compose-file STACKNAME.yml STACKNAME instead. For an introduction to using a stack file in a compose file format to deploy an app, check out Deploying an app to a Swarm.