Skip to content
DevOps devops orchestration 5 min read

Docker Swarm — A Simpler Alternative

Kubernetes is powerful, but it is also a lot to learn and operate. Docker Swarm is a much simpler way to run containers across more than one server. It is built right into Docker, so if you already know docker and docker compose, you already know most of Swarm. This page shows you how Swarm turns a Compose file into a real cluster, and gives you an honest comparison so you can decide when Swarm is the smart, pragmatic choice — and when it is not.

What Docker Swarm is

A cluster is a group of servers that work together and act like one big computer. Orchestration is the job of deciding which container runs on which server, restarting containers that crash, and replacing servers that die. Kubernetes is the most popular orchestrator. Docker Swarm is a lighter one that ships inside Docker itself — there is nothing extra to install.

In Swarm, every server is called a node. Nodes come in two kinds:

  • A manager node runs the “brain”: it stores the desired state of your apps and tells the workers what to do. You can have several managers for high availability (so the cluster keeps working if one manager dies).
  • A worker node just runs your containers.

A small manager can also run containers itself, so a one-server “cluster” is perfectly valid for learning.

When to use this

Reach for Swarm when you have a handful of servers, a small team, and you want multi-node container scheduling without paying the Kubernetes learning tax. If you are already on a managed Kubernetes service, or you need a rich ecosystem (auto-scaling, service meshes, operators), Swarm is the wrong tool — use Kubernetes instead.

Setting up a Swarm on Ubuntu

These steps assume Docker is already installed on Ubuntu 22.04 or 24.04 LTS. Run the init command on the machine you want to be the first manager.

sudo docker swarm init --advertise-addr 203.0.113.10

The --advertise-addr value is the IP address other nodes will use to reach this manager. Use the server’s real public or private IP.

Output:

Swarm initialized: current node (k9p2x1abc3def) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-49nj1...-8vxv8 203.0.113.10:2377

To add a manager to this swarm, run 'docker swarm join-token manager'.

Now SSH into each worker server and paste the docker swarm join line Docker printed:

sudo docker swarm join --token SWMTKN-1-49nj1...-8vxv8 203.0.113.10:2377

Output:

This node joined a swarm as a worker.

Back on the manager, check that every node is healthy:

sudo docker node ls

Output:

ID              HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS
k9p2x1abc3def * manager-1   Ready     Active         Leader
m4f8t2ghi5jkl   worker-1    Ready     Active
n7q3v6mno8pqr   worker-2    Ready     Active

Swarm uses ports 2377 (cluster management), 7946 (node communication), and 4789 (the overlay network for container-to-container traffic). If you run a firewall, open them between your nodes only — never expose 2377 to the public internet. With ufw: sudo ufw allow from 203.0.113.0/24 to any port 2377 proto tcp.

Services: Compose, but for a cluster

In plain Docker you start one container with docker run. In Swarm you create a service, which is a description of how many copies (called replicas) of a container you want and which image to use. Swarm then keeps that many copies running across the cluster, restarting and rescheduling them automatically.

sudo docker service create --name web --replicas 3 --publish 8080:80 nginx:1.27

This launches three nginx containers spread across your nodes. The --publish 8080:80 part uses Swarm’s routing mesh: a request to port 8080 on any node is forwarded to one of the running copies, even if that copy lives on a different node. Check it:

sudo docker service ls

Output:

ID             NAME   MODE         REPLICAS   IMAGE        PORTS
8tz1w2x3y4z5   web    replicated   3/3        nginx:1.27   *:8080->80/tcp

Scaling up or down is a single command:

sudo docker service scale web=5

Stacks: deploying a whole app from one file

This is where Swarm shines. A stack is a full multi-service app described in a Compose file and deployed to the cluster at once. The file is nearly identical to a normal docker-compose.yml; you just add a deploy: block for Swarm-specific settings.

# stack.yml
services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"
    deploy:
      replicas: 3
      restart_policy:
        condition: on-failure
      update_config:
        parallelism: 1
        delay: 10s
  api:
    image: ghcr.io/acme/api:1.4.0
    deploy:
      replicas: 2

Deploy it with one command:

sudo docker stack deploy -c stack.yml myapp

Output:

Creating network myapp_default
Creating service myapp_web
Creating service myapp_api

To update the app, change the image tag in stack.yml and run the same stack deploy command again. Thanks to update_config, Swarm does a rolling update — it replaces containers one at a time so the app stays online. List and remove stacks like this:

sudo docker stack services myapp
sudo docker stack rm myapp

Swarm vs Kubernetes — when to use which

ConcernDocker SwarmKubernetes
Setup effortMinutes (swarm init)Hours, or a managed service
Learning curveLow — it is just ComposeSteep — many new concepts
Config filesFamiliar Compose YAMLNew manifest objects
Auto-scaling on loadNot built inBuilt in (HPA)
Ecosystem & add-onsSmallHuge (Helm, operators, meshes)
Managed cloud offeringsRareEverywhere (EKS, GKE, AKS)
Best forSmall teams, few serversLarge scale, big teams

The honest summary: Swarm gets a small cluster running in an afternoon and stays out of your way. But its ecosystem is small and largely frozen — most new tooling, hiring, and tutorials target Kubernetes. Choose Swarm for simplicity today; choose Kubernetes if you expect to grow or need its add-ons.

Best Practices

  • Run an odd number of managers (3 or 5) for production so the cluster can survive a manager failure; one manager is fine only for learning.
  • Pin image tags (nginx:1.27, not nginx:latest) so every node runs the exact same version.
  • Use Docker secrets (docker secret create) for passwords and API keys instead of putting them in the Compose file.
  • Set restart_policy and update_config in every service so crashes self-heal and deploys roll out safely.
  • Restrict the Swarm ports (2377, 7946, 4789) to your private network with ufw; never expose them publicly.
  • Keep your stack.yml in version control — it is the single source of truth for the whole app.
  • Be realistic about the future: if you outgrow a few nodes, plan a migration to Kubernetes rather than fighting Swarm’s limits.
Last updated June 15, 2026
Was this helpful?