Docker Swarm turns a handful of machines running Docker into one cluster you can deploy to as if it were a single machine. You describe the service you want, and Swarm decides where its containers run, keeps the right number alive and routes traffic to them.
Why one server stops being enough
Running containers on one machine is simple. docker run starts them, and with Docker Compose you can describe a whole app in one file. The trouble starts when the app grows, or when it matters more.
One machine has a fixed amount of CPU and memory. When traffic outgrows it, you can buy a bigger machine, but that has a ceiling and a price. It is also a single point of failure: a dead disk or a power cut takes every container down at once.
The other option is to spread the work across several machines, which is horizontal scaling. Doing that by hand gets painful quickly. You have to decide which container goes where and restart containers when a machine dies, and every client needs to know which addresses to use. An orchestrator does that bookkeeping for you.
What Docker Swarm is
Docker Swarm is a container orchestrator built into Docker Engine. When you switch on 'swarm mode', the machines (called nodes) form a cluster, and you talk to that cluster with the docker commands you already know.
Kubernetes solves the same problem, and Swarm is the simpler, lighter alternative. You install nothing beyond Docker itself, and its service definitions are close to the Compose files many teams already have.
A swarm has two kinds of node:
- Managers keep the cluster's state, accept your commands and decide where containers run. They agree on that state with the Raft consensus algorithm, so a change only counts once a majority of managers have recorded it.
- Workers run the containers they are given and report back. Managers run containers too, unless you tell them not to.
Services, tasks and desired state
In a swarm you don't start containers one by one. You create a service: a description of what should run, such as the image, the number of copies (replicas), the ports and the networks. Each copy is a task, and each task runs one container on one node.
Swarm works from desired state. You tell Swarm what you want ('three copies of nginx, published on port 8080'), and the managers keep comparing that with what is actually running. Whenever the two differ, Swarm acts to close the gap. That is why you deploy a service once and Swarm keeps it alive afterwards.
When a machine goes down
Desired state is what keeps the app up when a node fails. Here is what happens when one of three workers stops answering:
A worker fails and Swarm replaces its task
Step 1 of 6: The service asks for three copies of web, and the manager runs one on each worker.
Swarm does not move tasks back to a node that recovers, so a cluster can end up lopsided after an outage. Running docker service update --force web restarts the service's tasks and spreads them out again.
A worked example: a small web service
Say you have three Linux machines with Docker installed, and they can reach each other on the network. On the first one, start a swarm:
docker swarm init --advertise-addr 10.0.0.1That machine is now a manager. The command prints a docker swarm join line with a token; run it on the other two machines to add them as workers. If you lose it, docker swarm join-token worker prints it again.
docker swarm join --token <token> 10.0.0.1:2377Back on the manager, check the cluster and create a service with three replicas:
docker node ls
docker service create --name web --replicas 3 \
--publish published=8080,target=80 nginx
docker service ps webdocker service ps lists the three tasks and the node each one landed on. Visit port 8080 on any of the three machines and nginx answers.
Scaling and updating
When traffic grows, change the number and Swarm schedules the extra tasks:
docker service scale web=6Updates roll out gradually. Swarm replaces tasks a batch at a time, so the service keeps serving while the new version goes out:
docker service update --image nginx:alpine \
--update-parallelism 1 --update-delay 10s webIf the new version misbehaves, docker service rollback web returns the service to its previous definition.
The same thing as a file
For anything beyond a demo, keep the definition in a Compose file and deploy it as a stack. The deploy section is the part only Swarm reads:
services:
web:
image: nginx:alpine
ports:
- "8080:80"
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failuredocker stack deploy -c stack.yml shopRun the same command after editing the file and Swarm applies the changes. A stack can't build images, though: docker stack deploy ignores build, so push the image to a registry every node can pull from first.
Networking, load balancing and service discovery
Swarm handles the networking that a cluster needs, starting with load balancing. Its routing mesh makes a published port answer on every node, including nodes that run no task for that service, and passes each request on to one of the service's tasks. You can put an external load balancer in front of all the nodes without it needing to know where the containers are.
Containers on different machines talk to each other over an overlay network, which spans every node as if they shared one network. Create one with docker network create --driver overlay backend and attach services to it, or let a stack create one for you.
Service discovery works on top of that: on an overlay network, each service is reachable by its name. A container in an api service can call http://web and reach nginx. Swarm's built-in DNS resolves the name to a virtual IP, and traffic to that IP is spread across the service's tasks. When tasks move, the name keeps working.
Swarm or Kubernetes
Both run containers across a cluster from a desired state, and both replace failed containers.
Swarm fits when you want orchestration with little to learn: a small team, a handful of nodes, apps already in Compose files, or a homelab. Setup is a couple of commands, and the concepts fit on a page.
Kubernetes fits when you need what Swarm doesn't have: built-in autoscaling, a large ecosystem of operators and tools, finer control over scheduling and access, and managed offerings from every major cloud provider. In return you take on more concepts to learn and more configuration to look after.
Moving later is possible, since both run the same container images, but the deployment files have to be rewritten.
Common mistakes
- One manager, or an even number: managers need a majority to make changes. Three managers survive one failure and five survive two; four survive only one, the same as three. With a single manager, losing it means you can't change the cluster at all, even though the running containers carry on.
- Keeping state in a local volume: a named volume lives on one node. If the task moves, its data stays behind. Use storage every node can reach, or pin the stateful service to one node with a placement constraint.
- Blocked ports between nodes: nodes need TCP 2377 for cluster management, TCP and UDP 7946 for node-to-node traffic, and UDP 4789 for overlay networks. A firewall that blocks them gives you a swarm that half works.
- Taking a node down without draining it: before maintenance, run
docker node update --availability drain <node>so its tasks move elsewhere in an orderly way. - Expecting autoscaling: Swarm keeps the replica count you set, so scaling up for a spike is your job, or a script's.
Key takeaways
- Docker Swarm is Docker's built-in orchestrator: several machines act as one cluster you deploy to with familiar
dockercommands. - You declare a service's desired state, and the managers keep reality matching it, replacing tasks when a node fails.
- Scaling is one command, and updates roll out a batch at a time, with rollback on hand.
- The routing mesh, overlay networks and built-in DNS give you load balancing and service discovery without extra setup.
- Run an odd number of managers, keep state off local volumes, and choose Kubernetes when you need its autoscaling and ecosystem.