Introduction
In this article, we will see an overview of Docker Swarm and it’s concepts.
Running you containers on a single host is probably good for testing and development, but in a production environment, this may not be a good idea to have a single point of failure.
With Docker Swarm, you can combine multiple Docker hosts together into a single cluster and have High availability. Docker Swarm also helps us to balance load accross different systems.
Swarm Cluster Setup
First you need to have multiple hosts running Docker. Then you must designate one host to be the Docker Swarm cluster master and other hosts to be slaves or worker.
After that, run the following command on the master node :
$ docker swarm init
It will initialize the Swarm manager. The output of the command will also provides the commands you have to run on the workers. It will look like :
$ docker swarm join --token XXXX MASTER_IP_ADDRESS:2377
To add another master to the Swarm, you can run the following command and follow instructions :
$ docker swarm join-token manager
Docker Manager Node – Fault Tolerance
This master node as seen previously is where Swarm is initiated. It role is to be responsible for maintaining the cluster state, managing the workers, addind and removing workers and ensuring the state of containers accross all workers.
It is not recommanded to have a single worker node in case of failures. You can have multiple master nodes but to avoid any managing conflicts, only one master node is allowed to make management decisions. This master node is called the leader.
Using the Raft algorithm, Docker ensures that all managers have the same information about the cluster at all times.
Finally, just a quick reminder. To calculate the Quorum of your cluster, you can use the following formula :
quorum = abs (((number of nodes) / 2) + 1)
So based on this tab, if you have three nodes, you can loose and still have a fully running cluster with only two nodes. But what happens if on a cluster of three master nodes, we loose two nodes ?
Well, your application will still run but you won’t be able to perform any modifications on them like adding a new worker, updating a service configuration, updating, destroying or moving an existing service.
Docker Service
You can run multiple instances on your Swarm cluster using services. To create a service, simply run the following command on the master node :
$ docker service create --replicas=3 my-web-server
If a container fails, the manager becomes aware of it and reschedule a new task on the worker node which will create a new container.
There are two sorts of services :
- Replicated : services created with the –replica option to run multiple replicas accross the cluster (i.e multiple webservers.)
- Global : services created with the “–mode global” option if you want to run only one container on every node in the cluster (i.e an antivirus scanner, a monitoring tool.)
Docker Stacks
What are Stacks ?
A Stack is a group of interrelated services than together forms an entire application.
We have seen through different articles (i.e here) how to create applications through docker-compose.yml files on Docker.
In Docker Swarm, we do the same thing but slightly differently as we can run multiple instances of each service and orchestrate them with stacks. Instead of using the “docker run” command, we use the “docker service” command to create our services for each component in our application. Just as you convert your commands to a docker-compose.yml file, you can convert your docker service commands to a docker-compose.yml file with at least version 3.
When your yml file is ready, run the following command :
docker stack deploy myapp --compose-file docker-compose-myapp.yml
Voting App docker-compose file example
Here you can find the well known voting app application’s docker-compose file (take attention to the “deploy” parameters where you can specify constraints on placements, specify replicas etc.) :
version: "3"
services:
redis:
image: redis:alpine
ports:
- "6379"
networks:
- frontend
deploy:
replicas: 2
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
db:
image: postgres:9.4
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
deploy:
placement:
constraints: [node.role == manager]
vote:
image: dockersamples/examplevotingapp_vote:before
ports:
- 5000:80
networks:
- frontend
depends_on:
- redis
deploy:
replicas: 2
update_config:
parallelism: 2
restart_policy:
condition: on-failure
result:
image: dockersamples/examplevotingapp_result:before
ports:
- 5001:80
networks:
- backend
depends_on:
- db
deploy:
replicas: 1
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
worker:
image: dockersamples/examplevotingapp_worker
networks:
- frontend
- backend
deploy:
mode: replicated
replicas: 1
labels: [APP=VOTING]
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 120s
placement:
constraints: [node.role == manager]
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
stop_grace_period: 1m30s
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
networks:
frontend:
backend:
volumes:
db-data:
Docker Swarm Cheat sheet
Finally, here are useful commands on Docker Swarm :
##################
# Node management #
###################
# Initialize a swarm
$ docker swarm init
# List swarm nodes
$ docker node ls
# Get Token to join swarm
$ docker swarm join-token worker
# Get the command for new nodes to join a swarm
$ docker swarm join \
--token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
192.168.99.100:2377
# Check service manager reachability
$ docker node inspect manager-node-name --format "{{ .ManagerStatus.Reachability }}"
# Check node state
$ docker node inspect node-name --format "{{ .Status.State }}"
# Put a node in maintenance mode
$ docker node update --availability drain node_name
# Activate a node (after maintenance)
$ docker node update --availability active node_name
# Add a label
$ docker node update --label-add key=value node_name
# Remove a label
$ docker node update --label-rm key node_name
#Search label
$ docker node inspect node_name | grep Labels -C5
######################
# Service management #
######################
# List services (manager node)
$ docker service ls
# Describe services (manager node)
$ docker service ps service_name
# Inspect a service
$ docker service inspect service_name
# Scale a service
$ docker service scale service_name=N
# Remove service
$ docker service rm service_name
####################
# Stack management #
####################
# Deploy stack from docker-compose file
$ docker stack deploy -c docker-compose.yml stack_name
# List stacks
$ docker stack ls
# List stack services
$ docker stack services stack_name
# List stack tasks
$ docker stack ps stack_name
# Remove stack
$ docker stack rm stack_name
######################
# Network management #
######################
# List networks
$ docker network ls
# Create overlay network
$ docker network create -d overlay network_name
# Remove network
$ docker network rm network_name
####################
# Monitor services #
####################
# Docker stats
$ docker stats
# Service logs
$ docker service logs service_name
# Collect all container logs:
$ docker service create --mode global --name st-logagent \
--restart-condition any \
--mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
-e LOGS_TOKEN=YourLogsToken \
sematext/logagent:latest
That’s all for today – Thanks !
Sources
docker.com
github.com/ematext/cheatsheets
medium.com/lucjuggery/deploy-the-voting-apps-stack-on-a-docker-swarm-4390fd5eee4