Skip to main content
DevOps Insightsguides & answers

Docker Swarm · guide

Docker Swarm Guide

Swarm mode, built into Docker Engine, manages a cluster of Docker hosts as one swarm. You declare services and replicas; the swarm decides which node runs what. See the official Swarm docs.

Last updated

On this page · 13 sections

1. What Is Docker Swarm

Docker Swarm is Docker's built-in container orchestration. It is included in every Docker Engine installation — no extra software to install. Swarm is a good choice when you need multi-node clustering without the complexity of Kubernetes.

Key concepts:

  • Manager nodes handle scheduling, state management, and the Raft consensus.
  • Worker nodes run the actual container workloads. (Managers also run tasks by default unless you drain them.)
  • Services are the unit of deployment (like a Compose service, but distributed).
  • Tasks are individual containers running as part of a service.

2. Initialize a Swarm

Run this on the machine that will be the first manager. This enables swarm mode and makes the current node a manager.

bash
docker swarm init

If the machine has multiple network interfaces, specify the advertise address:

bash
docker swarm init --advertise-addr 192.168.1.10

After init, Docker prints a docker swarm join command with a token. Save it to add worker nodes.

bash
# View the join token again later
docker swarm join-token worker
docker swarm join-token manager

3. Adding Worker and Manager Nodes

Run the join command on each additional machine. The token determines whether it joins as a worker or manager.

Add a worker node:

bash
# Run on the machine you want to add as a worker
docker swarm join --token SWMTKN-1-xxxxx 192.168.1.10:2377

Add a manager node:

bash
# Get the manager join token (run on existing manager)
docker swarm join-token manager

# Then run the printed command on the new manager node
docker swarm join --token SWMTKN-1-yyyyy 192.168.1.10:2377
bash
# List all nodes in the swarm (run on a manager)
docker node ls

# Promote a worker to manager
docker node promote <node-name>

# Demote a manager to worker
docker node demote <node-name>

# Remove a node (run on manager) — it must have left the swarm or be down first;
# --force is for a node you can no longer reach
docker node rm <node-name>

# Leave the swarm (run on the node itself)
docker swarm leave
# For a manager, demote it first (docker node demote <node-name>), then run
# docker swarm leave without --force. --force skips the quorum safeguard: only use it
# when the swarm will not be used again, e.g. a single-node swarm
docker swarm leave --force

For high availability, use 3 or 5 manager nodes (always an odd number for Raft consensus).


4. Creating Services

A service is how you deploy a container to the swarm. The swarm scheduler decides which node(s) run it.

bash
# Create a simple service with 1 replica
docker service create --name web --publish 80:80 nginx:alpine

# Create a service with 3 replicas
docker service create --name api --replicas 3 --publish 4000:4000 my-api:1.0

# Create a service with environment variables
docker service create --name db \
  --env POSTGRES_USER=app \
  --env POSTGRES_PASSWORD=secret \
  --mount type=volume,source=pgdata,target=/var/lib/postgresql/data \
  postgres:16-alpine

# List all services
docker service ls

# Show detailed info about a service
docker service inspect --pretty web

# Show which nodes are running a service's tasks
docker service ps web

5. Scaling Services

Scale a service up or down by changing the replica count. The swarm distributes tasks across available nodes.

bash
# Scale to 5 replicas
docker service scale web=5

# Scale multiple services at once
docker service scale web=5 api=3

# Verify the scaling
docker service ls
docker service ps web

To scale to zero (stop all tasks without removing the service):

bash
docker service scale web=0

6. Rolling Updates and Rollbacks

Swarm performs rolling updates by default — replacing tasks one (or a few) at a time so the service stays available.

bash
# Update the image for a service
docker service update --image nginx:1.30-alpine web

# Control update behavior
docker service update \
  --image my-api:2.0 \
  --update-parallelism 2 \
  --update-delay 10s \
  --update-failure-action rollback \
  --update-order start-first \
  api

Update options explained:

  • --update-parallelism 2 — update 2 tasks at a time.
  • --update-delay 10s — wait 10 seconds between batches.
  • --update-failure-action rollback — auto-rollback if the update fails.
  • --update-order start-first — start the new task before stopping the old one (zero-downtime).
bash
# Manually rollback to the previous version
docker service rollback web

# Check update/rollback status
docker service inspect --pretty web

7. Stack Deploys with Compose Files

A stack is a group of services deployed from a Compose file. This is the recommended way to deploy multi-service apps to Swarm.

yaml
# stack.yml
services:
  web:
    image: nginx:alpine
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
    ports:
      - "80:80"

  api:
    image: my-api:1.0
    deploy:
      replicas: 2
    environment:
      DATABASE_URL: postgres://app:secret@db:5432/appdb

  db:
    image: postgres:16-alpine
    deploy:
      replicas: 1
      placement:
        constraints:
          # Pin to ONE node: named volumes are local to a node, so a task that
          # moved to another manager would start with an empty pgdata.
          # Label it first: docker node update --label-add db=true <node>
          - node.labels.db == true
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: appdb

volumes:
  pgdata:
bash
# Deploy a stack
docker stack deploy -c stack.yml myapp

# List stacks
docker stack ls

# List services in a stack
docker stack services myapp

# List tasks in a stack
docker stack ps myapp

# Remove a stack
docker stack rm myapp

Note: docker stack deploy ignores build: (it prints "Ignoring unsupported options: build"), so all images must be pre-built and available (either on a registry or locally on every node). It also reads the legacy Compose file format 3, not the current Compose Specification, so some keys that work with docker compose are not supported in a stack file.


8. Overlay Networks

Overlay networks span multiple nodes, allowing containers on different hosts to communicate. Application traffic on an overlay is not encrypted unless you create the network with --opt encrypted (IPsec; it has a performance cost and is not supported for Windows containers).

bash
# Create an overlay network
docker network create --driver overlay my-overlay

# Create an attachable overlay (allows standalone containers to join too)
docker network create --driver overlay --attachable my-overlay

# Create a service on the overlay network
docker service create --name api --network my-overlay my-api:1.0
docker service create --name db --network my-overlay --env POSTGRES_PASSWORD=change-me postgres:16-alpine

In a stack file, networks are created automatically:

yaml
services:
  web:
    image: nginx:alpine
    networks:
      - frontend

  api:
    image: my-api:1.0
    networks:
      - frontend
      - backend

  db:
    image: postgres:16-alpine
    networks:
      - backend

networks:
  frontend:
    driver: overlay
  backend:
    driver: overlay

Swarm provides built-in DNS so services find each other by name. The api service can reach db at hostname db on port 5432.


9. Secrets and Configs

Swarm has built-in secret management. Secrets are encrypted at rest and only sent to nodes that need them.

bash
# Create a secret from stdin (printf, not echo, so no trailing newline ends up in the
# secret; the value is left in your shell history)
printf "supersecretpassword" | docker secret create db_password -

# Create a secret from a file
docker secret create tls_cert ./server.crt

# List secrets
docker secret ls

# Use a secret in a service (mounted at /run/secrets/<name>)
docker service create --name db \
  --secret db_password \
  --env POSTGRES_PASSWORD_FILE=/run/secrets/db_password \
  postgres:16-alpine

Configs work like secrets but for non-sensitive configuration files:

bash
# Create a config
docker config create nginx_conf ./nginx.conf

# Use it in a service
docker service create --name web \
  --config source=nginx_conf,target=/etc/nginx/nginx.conf \
  nginx:alpine

In a stack file:

yaml
services:
  db:
    image: postgres:16-alpine
    secrets:
      - db_password
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password

secrets:
  db_password:
    external: true   # secret must be created before deploying

10. Placement Constraints and Labels

Control which nodes run which services using placement constraints and labels.

bash
# Add a label to a node
docker node update --label-add disk=ssd node-03

# Create a service constrained to manager nodes
docker service create --name monitoring \
  --constraint 'node.role == manager' \
  prom/prometheus:v3.15.0

# Create a service constrained to nodes with a label
docker service create --name db \
  --constraint 'node.labels.disk == ssd' \
  --env POSTGRES_PASSWORD=change-me \
  postgres:16-alpine

In a stack file:

yaml
services:
  db:
    image: postgres:16-alpine
    deploy:
      placement:
        constraints:
          - node.role == manager
          - node.labels.disk == ssd
      replicas: 1

  worker:
    image: my-worker:1.0
    deploy:
      placement:
        preferences:
          - spread: node.labels.zone
      replicas: 6

The spread preference distributes replicas evenly across the specified label values (e.g., availability zones).


11. Resource Limits and Reservations

bash
# Ceilings: the container is killed if it exceeds the memory limit
docker service create --name web-limited \
  --limit-memory 512m --limit-cpu 1.5 nginx:alpine

# Floors: what each task needs before the scheduler will place it
docker service create --name web-reserved \
  --reserve-memory 256m --reserve-cpu 0.5 nginx:alpine

# Change them on a running service
docker service update --limit-memory 1g web

⚠️ Reservations are scheduling constraints, and this is the one that surprises people: if no node has the reserved amount free, the task is not placed and the service sits in Pending indefinitely. Nothing has failed, so nothing restarts — the scheduler is still waiting for somewhere to put it, and the task's ERROR column says so: no suitable node (insufficient resources on N nodes).

bash
# Tasks stuck Pending, with the reason in the error column
docker service ps web --no-trunc

# What each node has to offer
docker node inspect <node> --format '{{.Description.Resources.NanoCPUs}} {{.Description.Resources.MemoryBytes}}'

💡 Reserve what a task needs, not what it peaks at. Reservations are subtracted from a node's advertised capacity whether or not the task is using them, so generous reservations quietly shrink the cluster.


12. Monitoring and Troubleshooting

Use these commands to inspect the state of your swarm and debug issues.

bash
# List all services and their replica counts
docker service ls

# Show tasks for a service (which node, status, errors)
docker service ps web
# Full task IDs and untruncated error messages (failed and shut-down tasks are
# listed by default; add --filter desired-state=running to hide them)
docker service ps web --no-trunc

# View logs for a service (aggregated from all replicas)
docker service logs -f web

# View logs for a specific task
docker service logs <task-id>

# Inspect a service for full config details
docker service inspect --pretty web

# Inspect a node
docker node inspect --pretty <node-name>

# Check node availability and drain a node for maintenance
docker node update --availability drain <node-name>
# Bring it back
docker node update --availability active <node-name>

Common issues:

  • Service stuck at 0/N replicas: Check docker service ps <name> for error messages. Common causes: image not found (not pushed to registry), port conflicts, resource constraints.
  • Tasks in "rejected" state: The worker node rejected the task — commonly because the image could not be pulled (No such image in the error column). Unmet placement constraints or resource reservations do not reject a task; they leave it Pending.
  • Nodes showing "down": Network partition or Docker stopped on that node. Check connectivity and systemctl status docker.

13. Firewall Ports

For swarm nodes to communicate, the following ports must be open between the nodes — and only between them. Port 4789 carries VXLAN, which has no authentication: never open it to the internet or at a perimeter firewall. If you use encrypted overlay networks (--opt encrypted), also allow IP protocol 50 (ESP).

PortProtocolPurpose
2377TCPCluster management and Raft consensus
7946TCP + UDPNode discovery and gossip protocol
4789UDPVXLAN overlay network traffic
bash
# Replace 192.168.1.0/24 with the subnet your swarm nodes use

# UFW (Ubuntu)
sudo ufw allow from 192.168.1.0/24 to any port 2377 proto tcp
sudo ufw allow from 192.168.1.0/24 to any port 7946 proto tcp
sudo ufw allow from 192.168.1.0/24 to any port 7946 proto udp
sudo ufw allow from 192.168.1.0/24 to any port 4789 proto udp

# firewalld (CentOS/RHEL) — a zone that applies only to traffic from the node subnet
sudo firewall-cmd --permanent --new-zone=swarm
sudo firewall-cmd --permanent --zone=swarm --add-source=192.168.1.0/24
sudo firewall-cmd --permanent --zone=swarm --add-port=2377/tcp
sudo firewall-cmd --permanent --zone=swarm --add-port=7946/tcp
sudo firewall-cmd --permanent --zone=swarm --add-port=7946/udp
sudo firewall-cmd --permanent --zone=swarm --add-port=4789/udp
sudo firewall-cmd --reload

# iptables
sudo iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 2377 -j ACCEPT
sudo iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 7946 -j ACCEPT
sudo iptables -A INPUT -s 192.168.1.0/24 -p udp --dport 7946 -j ACCEPT
sudo iptables -A INPUT -s 192.168.1.0/24 -p udp --dport 4789 -j ACCEPT

If you use cloud provider security groups (AWS, GCP, etc.), add these rules to allow traffic between your swarm nodes.

Terms used here (1)

Short definitions for the vocabulary on this page, in case any of it is new. Each links to the full entry.

Docker Swarm
Docker Engine's built-in orchestration mode (swarm mode), which joins Docker hosts into a cluster of managers and workers and keeps each service at the number of replicas you declare. Swarm provides service discovery, load balancing, and rolling updates with a simpler learning curve than Kubernetes.

All 59 terms in the glossary