Skip to main content

What is Docker Swarm?

Docker Swarm is Docker's native, built-in cluster orchestrator. Out of the box, every Docker installation can become a manager or worker node in a Swarm cluster — no separate install, no separate CLI. The price for the simplicity is a smaller ecosystem and slower development compared to Kubernetes.

Theory

TL;DR

  • Swarm = a cluster of Docker hosts working as one. Built into the Docker engine since 1.12 (2016).
  • Architecture: managers (raft consensus, control plane) + workers (run containers).
  • Services: docker service create declares the desired state (image, replicas, ports, network); Swarm schedules tasks (running containers) to satisfy it.
  • Built-in features: service discovery (via overlay network DNS), routing mesh (any node can receive traffic for any service), rolling updates, restart policies, encrypted overlay networks, secrets.
  • Honest assessment in 2026: Swarm works and is genuinely simpler than K8s, but new production projects almost always choose Kubernetes. Use Swarm for small clusters, on-prem, or where K8s is genuinely overkill.

Architecture

+-----------+ +-----------+ +-----------+ | manager 1 | <-> | manager 2 | <-> | manager 3 | (raft) +-----------+ +-----------+ +-----------+ ^ ^ ^ | | | | gossip / control plane | | | +-----------+ +-----------+ +-----------+ | worker A | | worker B | | worker C | | (tasks) | | (tasks) | | (tasks) | +-----------+ +-----------+ +-----------+
  • Managers form a raft quorum. Odd number recommended (3, 5, 7) for fault tolerance. Lose majority → cluster cannot accept new operations.
  • Workers run tasks. Cannot make scheduling decisions; just execute what managers tell them.
  • A node can be both manager and worker simultaneously (--availability=active). Small clusters often have 3 managers that are also workers.

Core concepts

Service

Declarative description of a workload. Like a Kubernetes Deployment.

bash
docker service create \ --name api \ --replicas 5 \ --publish 80:80 \ --network appnet \ --update-parallelism 2 \ --update-delay 10s \ --restart-condition on-failure \ --restart-max-attempts 5 \ myorg/api:1.2.0

Task

A running instance of a service. If --replicas 5, the service has 5 tasks. Each task is a single container running on one node. If a task dies, Swarm spawns a new one.

Node

A machine in the cluster. Either manager or worker (or both). Each node has labels you can target with placement constraints (--constraint node.labels.tier==edge).

Stack

A group of services deployed together via a Compose file. docker stack deploy -c compose.yaml mystack.

Setting up a Swarm cluster

bash
# On node-1 (will be the manager) node-1$ docker swarm init --advertise-addr 192.168.1.10 Swarm initialized: current node (xxx) is now a manager. To add a worker, run: docker swarm join --token SWMTKN-... 192.168.1.10:2377 # On node-2 (worker) node-2$ docker swarm join --token SWMTKN-... 192.168.1.10:2377 # Back on manager node-1$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS xxx node-1 Ready Active Leader yyy node-2 Ready Active

Two commands and you have a working cluster. Compare with Kubernetes' kubeadm init + CNI install + storage class setup + RBAC tuning.

Routing mesh and service discovery

When you publish a service port:

bash
docker service create --name api --publish 80:80 --replicas 3 myapp

Swarm creates an ingress overlay network that all nodes participate in. Any node can receive traffic on port 80, even if no replica runs there — the routing mesh forwards to a healthy task.

Services on the same overlay network resolve each other by name:

bash
# Inside any task on appnet $ nslookup api Name: api Address: 10.0.0.5 # virtual IP, IPVS-balanced across replicas

The service name resolves to a virtual IP; kernel IPVS load-balances across healthy replicas.

Updating and scaling

bash
# Scale docker service scale api=10 # Rolling update docker service update --image myorg/api:1.3.0 api # Honors --update-parallelism, --update-delay, --update-failure-action # Rollback docker service rollback api

Rolling updates are first-class: change one parallelism slice at a time, wait, verify health, continue or roll back automatically.

Stacks via Compose

yaml
# stack.yaml services: api: image: myorg/api:1.2.0 deploy: replicas: 3 update_config: parallelism: 1 delay: 10s order: start-first restart_policy: condition: on-failure placement: constraints: [node.role == worker] networks: [appnet] web: image: nginx:1.27-alpine ports: ["80:80"] networks: [appnet] networks: appnet: driver: overlay
bash
docker stack deploy -c stack.yaml mystack docker stack services mystack docker stack ps mystack docker stack rm mystack

Swarm's stack format is largely compatible with Compose (with deploy: keys honored only in Swarm).

Honest comparison with Kubernetes (2026)

SwarmKubernetes
Setupdocker swarm initkubeadm init + CNI + storage + ingress
Learning curvea weekendmonths
Manifest formatCompose-flavored YAMLk8s YAML (verbose)
Ecosystemsmall, mostly Docker Incenormous (CNCF, vendors, community)
Multi-tenantweakstrong (namespaces, RBAC, quotas)
Maintainedyes, but feature-frozenactively developed
Use today forsmall clusters, edge, simplicityalmost everything else

The 2026 reality: most production teams pick Kubernetes. Swarm is alive but not the default. Cloud providers have stopped emphasizing managed Swarm; managed K8s (EKS, GKE, AKS) is everywhere.

Common mistakes

Treating Swarm like Compose

Most Compose features work, but Swarm-specific keys (deploy.placement, deploy.update_config, deploy.replicas) are honored only in Swarm. docker compose up ignores them.

Running with one manager

A single manager has no fault tolerance. Lose it → cluster is unrecoverable. Always 3 managers minimum for production.

Forgetting that bind mounts do not span nodes

A task scheduled on node-2 cannot read a bind mount from node-1's filesystem. Use volumes with networked drivers (NFS, EBS) for stateful workloads, or pin tasks to specific nodes.

Routing mesh hiding source IP

The ingress mesh DNATs incoming traffic. Your app sees the Swarm node's IP, not the client's. Use --publish mode=host if you need real client IPs (sacrifices the mesh's any-node receiving).

Real-world usage

  • Small on-prem clusters: 5-20 nodes. Swarm's simplicity beats K8s setup pain.
  • Edge / IoT: lightweight orchestration for small fleets.
  • Low-resource environments: Swarm has lower overhead than full K8s.
  • Internal tools, side projects: when you do not need K8s' depth.

Follow-up questions

Q: Should I learn Swarm in 2026?


A: As your only orchestrator, no — career-wise, Kubernetes is the dominant skill. As a stepping stone or for a small specific use case, sure. Concepts (services, tasks, declarative state, rolling updates) transfer to K8s anyway.

Q: Can Swarm and Kubernetes run on the same nodes?


A: Technically yes (different ports, different namespaces), but it is fragile and a maintenance burden. Pick one orchestrator per cluster.

Q: What is the difference between a Service and a Task?


A: Service is the declaration ("I want 5 replicas of myapp:1.0"). Tasks are the running instances that satisfy the declaration. Swarm reconciles: if the desired state says 5 and only 4 are running, it spawns one more.

Q: How does Swarm handle storage?


A: Local volumes per node (work for stateless or single-node-pinned services), or volume drivers (NFS, REX-Ray, AWS EBS plugins) for portable storage. Real production storage on Swarm is usually external (managed DB, object storage), not local volumes.

Q: (Senior) Why has Swarm lost ground to Kubernetes despite being simpler?


A: Network effects + ecosystem. K8s has Helm, Operators, Istio, Prometheus, Argo, Crossplane, thousands of vendor integrations. Swarm has the basics, well-implemented, and stops there. For complex multi-tenant production, the K8s ecosystem solves problems Swarm has no answer for. Swarm wins on simplicity if simplicity is what you need; K8s wins everywhere else by virtue of mass adoption.

Examples

Bootstrap a 3-node Swarm

bash
# Manager + 2 workers node-1$ docker swarm init --advertise-addr 192.168.1.10 # (note the join token from output) node-2$ docker swarm join --token SWMTKN-... 192.168.1.10:2377 node-3$ docker swarm join --token SWMTKN-... 192.168.1.10:2377 node-1$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS xxx node-1 Ready Active Leader yyy node-2 Ready Active zzz node-3 Ready Active

Deploy a service spread across the cluster

bash
node-1$ docker network create -d overlay appnet node-1$ docker service create \ --name api \ --replicas 6 \ --network appnet \ --publish 80:80 \ --update-parallelism 2 \ --update-delay 10s \ --restart-condition on-failure \ myorg/api:1.0 node-1$ docker service ps api # 6 tasks distributed across node-1, node-2, node-3 # All reachable on any node's port 80 via the routing mesh

Stack from Compose-style file

bash
node-1$ docker stack deploy -c stack.yaml mystack Creating network mystack_appnet Creating service mystack_api Creating service mystack_web node-1$ docker stack services mystack ID NAME REPLICAS IMAGE ... mystack_api 3/3 myorg/api:1.2.0 ... mystack_web 1/1 nginx:1.27-alpine

One file, one command, multi-host deployment. The simplicity Swarm fans love.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Comments

No comments yet