Software & Configuration

Docker Swarm

Set up Docker Swarm for container orchestration across multiple servers, simpler than Kubernetes, built into Docker

Docker Swarm is Docker's built-in container orchestration system. It's simpler than Kubernetes and ideal for teams that already use Docker Compose and want multi-server deployments without the complexity of K8s.

When to use Swarm vs K3s

  • Docker Swarm, you already use Docker Compose, want minimal ops overhead, small to medium scale
  • K3s, need more features (autoscaling, advanced networking), larger scale, more ecosystem support

Architecture

Manager Node (orchestrates, schedules)
    ├── Worker Node 1 (runs containers)
    ├── Worker Node 2 (runs containers)
    └── Worker Node 3 (runs containers)

For HA, use 3 or 5 manager nodes. For simplicity, 1 manager + N workers works fine.


Initialize the swarm (on the manager)

docker swarm init --advertise-addr YOUR_MANAGER_IP

This outputs a join token. Save it, you'll need it to add workers.

Check the swarm status:

docker node ls

Add worker nodes

On each worker server, run the join command from the init output:

docker swarm join --token SWMTKN-1-xxxxx MANAGER_IP:2377

If you lost the token, regenerate it on the manager:

docker swarm join-token worker

Firewall rules (between nodes)

# On all nodes: open Swarm ports
sudo ufw allow 2377/tcp   # Cluster management
sudo ufw allow 7946/tcp   # Node communication
sudo ufw allow 7946/udp
sudo ufw allow 4789/udp   # Overlay network

Deploy a stack

Docker Swarm uses the same docker-compose.yml format with a few additions. Create a stack file:

nano docker-stack.yml
version: '3.8'

services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
    networks:
      - webnet

  api:
    image: myapp:latest
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: '0.5'
          memory: 256M
    networks:
      - webnet

networks:
  webnet:
    driver: overlay

Deploy:

docker stack deploy -c docker-stack.yml myapp

Manage stacks and services

# List stacks
docker stack ls

# List services in a stack
docker stack services myapp

# List running tasks (containers)
docker stack ps myapp

# Scale a service
docker service scale myapp_web=5

# Update a service image
docker service update --image nginx:1.25 myapp_web

# Rolling update
docker service update \
  --update-parallelism 1 \
  --update-delay 30s \
  --image myapp:v2 \
  myapp_api

# Remove a stack
docker stack rm myapp

Secrets management

Swarm has built-in encrypted secrets:

# Create a secret
echo "mysecretpassword" | docker secret create db_password -

# Or from a file
docker secret create ssl_cert ./cert.pem

# List secrets
docker secret ls

Use in stack file:

services:
  db:
    image: mysql:8
    secrets:
      - db_password
    environment:
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_password

secrets:
  db_password:
    external: true

Overlay networks

Services in the same overlay network can communicate by service name:

networks:
  backend:
    driver: overlay
    encrypted: true  # Encrypt traffic between nodes

From inside a container in the backend network:

curl http://api:3000/health

Shared storage with NFS

Swarm doesn't handle persistent storage natively. Use NFS or a distributed volume driver:

services:
  web:
    image: nginx
    volumes:
      - webdata:/var/www/html

volumes:
  webdata:
    driver: local
    driver_opts:
      type: nfs
      o: "addr=10.0.0.1,rw"
      device: ":/exports/webdata"

Monitor the swarm

# Node status
docker node ls

# Service status
docker service ls

# Inspect a service (see placement, ports, replicas)
docker service inspect myapp_web --pretty

# Live log from all replicas of a service
docker service logs -f myapp_web

# Events
docker events

Promote a worker to manager

docker node promote worker1

Demote:

docker node demote worker1

Drain a node (for maintenance)

# Move all containers off a node
docker node update --availability drain worker1

# Bring it back
docker node update --availability active worker1

Leave the swarm

On a worker:

docker swarm leave

On the manager (force):

docker swarm leave --force

On this page