Docker Swarm

Docker Swarm

Bitnesia Sep 14, 2026 10 ID

Running a single container via docker run is sufficient for development, but once an application needs to be available on more than one server simultaneously and stay alive even if one server dies, Sysadmin/DevOps Engineers need an orchestration tool to manage container placement, load balancing, and automated recovery. Docker Swarm is the built-in clustering and orchestration mode of Docker Engine that transforms a pool of Docker hosts into a single logical cluster, simply enabled via everyday Docker CLI commands without requiring any additional components outside Docker Engine itself. This chapter covers Swarm basics from cluster initialization, managing services running on top of it, load balancing mechanisms via the routing mesh, to safe rolling update strategies for updating applications without downtime.

38.1 Swarm Basics

Before any service can be run, a pool of Docker hosts must first be joined into a single Swarm cluster with a centralized control point. This section covers how to initialize the cluster, add new nodes, and understand the roles of managers and workers within it.

38.1.1 Swarm Initialization and Manager Node

Swarm mode is not enabled by default in a standard Docker Engine installation; it must be explicitly activated via the docker swarm init command on a single host that will become the first manager. Prepare at least one server with Docker Engine installed, then run the following command on that server.

docker swarm init --advertise-addr 192.168.99.100

The --advertise-addr option specifies the IP address that other nodes use to contact this manager; set it to an IP accessible by other nodes on the same network, not 127.0.0.1. If the server has only one network interface, Docker Engine can usually detect it automatically without this option, but on servers with multiple interfaces (for instance, having both a public IP and a private IP), this option must be explicitly set so Swarm does not choose the wrong interface. The output of this command displays a complete docker swarm join command with a token, which is used by other nodes to join as workers.

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

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

    docker swarm join \
    --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
    192.168.99.100:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

Store this token securely because anyone who holds it can add new nodes to the cluster. If the token needs to be retrieved later, run docker swarm join-token worker for a worker token or docker swarm join-token manager for a manager token, either of which can be executed at any time from any manager node in the cluster.

38.1.2 Adding Worker Nodes

After the first manager is active, add worker nodes by running the docker swarm join command shown in the previous docker swarm init output, executed on another server that has not joined any Swarm yet.

docker swarm join \
  --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
  192.168.99.100:2377

Before executing this command in a production environment, ensure that ports 2377/tcp (cluster management communication), 7946/tcp and 7946/udp (inter-node discovery), and 4789/udp (overlay network data plane) are open between nodes in the firewall, according to official Docker documentation regarding Swarm mode port requirements. Verify that nodes have joined by running docker node ls from the manager node.

docker node ls
ID                            HOSTNAME            STATUS    AVAILABILITY   MANAGER STATUS
dxn1zf6l61qsb1josjja83ngz *   manager1            Ready     Active         Leader
2p5s8vpz4jm7yl8xxfpb9j0dc     worker1             Ready     Active
9lvo9v3nrwtq6vy5j75kv2vg1     worker2             Ready     Active

An empty MANAGER STATUS column indicates that the node is a regular worker that only executes container tasks, rather than participating in cluster orchestration decisions. The node currently running the docker node ls command is indicated by an asterisk in the ID column. If a node's STATUS column displays Down even though the Docker Engine process on that server is still alive, the most common real-world cause is that one of the ports 2377/tcp, 7946/tcp, 7946/udp, or 4789/udp is blocked by a firewall; recheck firewall rules on both sides before assuming other issues in the Swarm configuration.

38.1.3 Manager Roles, Worker Roles, and Raft Quorum

A Swarm cluster consists of two node roles: managers which manage cluster state, schedule tasks to nodes, and serve the Swarm API, and workers which purely run containers as instructed by managers without participating in orchestration decisions. Each manager can also act as a worker simultaneously unless its availability is explicitly changed via docker node update --availability drain.

Manager nodes store cluster state using the Raft consensus protocol, which requires a majority (quorum) of managers to remain active and reachable so that the cluster can continue accepting configuration changes. Official Docker documentation recommends three or five managers for high availability, always an odd number, because an even number provides no additional fault tolerance over the odd number below it; 3 and 4 managers can both tolerate losing 1 manager before quorum is lost, whereas 5 and 6 managers can both tolerate losing 2 managers. If quorum is lost, tasks already running on worker nodes continue to run normally, but the cluster can no longer accept new commands like scaling or service updates until quorum is restored.

Promote a worker to an additional manager using the following command, executed from an active manager.

docker node promote worker1

In practice, adding more than five managers is generally not recommended because each additional manager adds Raft consensus communication overhead without adding meaningful resilience benefits; if more compute capacity is needed, add regular worker nodes instead of managers.

38.2 Service Management

In Swarm mode, the unit of work managed is not directly a container, but rather a service, which is a declaration of which image to run, how many replicas, and its configuration; Swarm itself decides on which nodes those tasks are placed. This section covers creating, scaling, and monitoring services.

38.2.1 Creating a New Service

Create a first service from the Nginx image with three replicas, executed from a manager node.

docker service create \
  --name web \
  --replicas 3 \
  --publish published=8080,target=80 \
  nginx:1.27-alpine

Swarm automatically distributes all three task replicas to available nodes in the cluster based on its built-in scheduling algorithm, without requiring Sysadmin/DevOps Engineers to manually specify target nodes one by one. Check the status of the newly created service with the following command.

docker service ls
ID             NAME      MODE         REPLICAS   IMAGE                PORTS
qwlm3c1qmvhr   web       replicated   3/3        nginx:1.27-alpine    *:8080->80/tcp

A REPLICAS column displaying 3/3 indicates that all tasks have reached the requested replica count and are in running status. Besides the replicated mode used above, Swarm also supports global mode via the --mode global option, which runs exactly one task on every cluster node (suitable for monitoring agents or log collectors that must be present on all nodes), unlike replicated mode where replica count is set manually via --replicas and is not tied to node count.

38.2.2 Scaling Service Replicas

Change the replica count of an already running service without needing to remove and recreate the service, using the docker service scale command.

docker service scale web=6

This command adds new tasks until total replicas reach six, or removes surplus tasks if the input number is smaller than the current replica count. Scaling down means Swarm stops running tasks; ensure the application is stateless or its state is stored outside the container (for instance in separate volumes or external databases) before scaling down in production, so no critical data is lost when tasks are terminated. Verify scaling results with docker service ls; the REPLICAS column should change to 6/6 as soon as all new tasks reach Running status.

38.2.3 Service Inspection and Monitoring

View task distribution for a service, including which node each task runs on and its current status, using the docker service ps command.

docker service ps web
ID             NAME     IMAGE               NODE        DESIRED STATE   CURRENT STATE
u5th78ojfvfy   web.1    nginx:1.27-alpine   worker1     Running         Running 2 minutes ago
sxeb8k7fkuwt   web.2    nginx:1.27-alpine   manager1    Running         Running 2 minutes ago
n8v5fu3v9mth   web.3    nginx:1.27-alpine   worker2     Running         Running 2 minutes ago

For complete configuration details of a service, including the current update strategy and endpoint mode, use docker service inspect with the --pretty option to make output easier to read than raw JSON format.

docker service inspect --pretty web

Aggregated logs from all tasks of a service, without needing to log in individually to each node running the tasks, can be retrieved using docker service logs.

docker service logs -f web

The -f option streams new logs continuously (similar to tail -f), useful when monitoring service behavior right after scaling or performing an update. In real-world environments, combining docker service ps to view node placement and docker service logs to view log output is typically sufficient for initial diagnosis before investigating a specific node via SSH.

38.3 Load Balancing

Tasks of the same service are spread across multiple nodes, so incoming traffic must be automatically distributed to healthy tasks without Sysadmin/DevOps Engineers having to manually configure a separate load balancer. Swarm provides this load balancing natively via the routing mesh and overlay network.

38.3.1 Routing Mesh for Published Ports

When a service publishes a port via --publish, all nodes in the cluster (not just nodes currently running its tasks) listen on that port through a mechanism called the routing mesh. Requests arriving at the published port on any node are automatically routed to one of the healthy service tasks, even if that task is actually running on another node, per official Docker documentation regarding Swarm mode routing mesh.

docker service create \
  --name web \
  --replicas 3 \
  --publish published=8080,target=80 \
  nginx:1.27-alpine

Using the configuration above, accessing http://ANY_NODE_IP:8080 from any node in the cluster (including nodes not running a web task) will be directed by the routing mesh to one of the three running tasks. This publication mode is called ingress mode and is the default; if mode is not explicitly specified in the long form of --publish, Docker uses ingress mode. Because all nodes listen on this port, external load balancers (such as in front of the cluster) only need to target any node IP without needing to track which node is currently running the task.

38.3.2 VIP versus DNS Round Robin

Inside an overlay network, Swarm provides service discovery via built-in DNS using two modes: VIP (virtual IP) as default, and DNSRR (DNS round robin) as an alternative. In VIP mode, each service receives a single virtual IP serving as the front door for clients; requests directed to this virtual IP are transparently load-balanced to underlying tasks via Linux IPVS at layer 3/4, without clients needing to know how many tasks are actually running.

In DNSRR mode, there is no single virtual IP; DNS queries to the service name directly return a list of IP addresses for all currently running tasks, and the client itself (or a resolver in front of it) picks one via round robin. This mode is suitable when custom layer 7 load balancing is required (for instance, via a reverse proxy with custom routing logic) that cannot be achieved via VIP. Change a service endpoint mode to DNSRR using the following option when creating the service.

docker service create \
  --name api \
  --replicas 3 \
  --endpoint-mode dnsrr \
  myregistry/api:1.0

Note that a service configured with --endpoint-mode dnsrr cannot simultaneously publish ports via ingress mode routing mesh, because routing mesh relies on VIP to function; if a service needs to publish ports while using DNSRR endpoint mode, use host publication mode instead. For most common use cases like standard web services, default VIP mode is sufficient and simpler to manage than DNSRR.

38.3.3 Service Discovery over Overlay Network

Services needing to communicate with each other (such as an API service calling a database service) must join the same overlay network, a network type specifically designed for inter-container communication across nodes in a Swarm cluster. Create the overlay network prior to creating the services.

docker network create --driver overlay backend-net
docker service create \
  --name api \
  --network backend-net \
  --replicas 3 \
  myregistry/api:1.0

docker service create \
  --name db \
  --network backend-net \
  --replicas 1 \
  postgres:16

When both services are joined to backend-net, the api service can directly contact the db service using its service name (for instance, postgres://db:5432) without needing to know actual database task IPs, as Swarm's built-in DNS automatically resolves the service name to its VIP. To retrieve individual task IPs behind a service (for example, for debugging purposes), perform a DNS lookup for tasks.<service-name>, which returns a list of all running task IPs, one per replica.

38.4 Rolling Updates

Updating the image of a service serving production traffic must not terminate all replicas simultaneously, as that causes full downtime during the update process. Swarm provides a rolling update mechanism that updates tasks incrementally, along with an automated fallback path to revert to a previous version if an update encounters issues.

38.4.1 Update Strategy and Parallelism

Update the image of a running service using docker service update combined with options controlling how many tasks are updated concurrently and the delay between batches.

docker service update \
  --image myregistry/api:2.0 \
  --update-parallelism 2 \
  --update-delay 10s \
  api

The configuration above updates at most two tasks concurrently in a single batch, then waits 10 seconds before proceeding to the next batch, according to official Docker documentation regarding service rolling updates. A smaller --update-parallelism value makes the update process slower but safer, because the count of older-version tasks serving traffic remains higher relative to newer-version tasks undergoing stability verification; conversely, larger parallelism speeds up rollout but increases risk if the new version proves faulty, as more tasks are replaced simultaneously before issues are detected.

The --update-order option controls execution sequence per updated task: stop-first (default) stops the old task version before starting the new task version, while start-first starts the new task version first and lets both run concurrently briefly before stopping the old task. For services requiring higher availability during updates (such as APIs that cannot afford temporary capacity dips), use start-first so total capacity does not drop during the rolling update process.

docker service update \
  --image myregistry/api:2.0 \
  --update-order start-first \
  api

38.4.2 Update Failure Action and Rollback

Updates running automatically without oversight risk continuing rollouts even when new task versions fail. The --update-failure-action option defines Swarm behavior when a task update fails, offering three choices: pause (default, halts the update process and waits for manual intervention), continue (proceeds to the next batch despite failures), or rollback (automatically reverts the entire service to its previous specification once the failure threshold is crossed).

docker service update \
  --image myregistry/api:2.0 \
  --update-failure-action rollback \
  --update-max-failure-ratio 0.2 \
  --update-monitor 15s \
  api

--update-max-failure-ratio configures tolerance thresholds; in the example above, up to 20% of updated tasks may fail before triggering rollback; --update-monitor sets the observation window following each task update to detect failures before Swarm considers the task successful and moves to the next batch. The default value for --update-monitor when omitted is 30 seconds, according to official Docker documentation on rolling update configurations; tasks failing to start or stopping during this window count as update failures, whereas failures occurring after this window expires are no longer counted. If the failure threshold is exceeded, Swarm automatically triggers rollback without requiring manual intervention, reverting the service to the previous image and configuration version stored automatically on every docker service update invocation.

If --update-failure-action is left at its default value pause, a failed update does not automatically roll back but halts midway waiting for manual action. Inspect the status of a paused update using docker service inspect --pretty, which displays the line Update status: paused along with a short message describing the cause.

Update status:
 State:      paused
 Started:    11 seconds ago
 Message:    update paused due to failure or early termination of task 9p7ith557h8ndf0ui9s0q951b

From this paused state, Sysadmin/DevOps Engineers can choose to run docker service rollback to revert to the previous version, or resolve the issue first (such as a mistagged image) and rerun docker service update to resume the paused process. Manual rollbacks can also be triggered at any time, without waiting for automated failure thresholds or paused status, using the following command.

docker service rollback api

This command reverts the service to the exact spec prior to the latest update, including image, environment variables, and other modified configurations, per official Docker CLI reference documentation for docker service rollback. Rollback behavior itself (parallelism, delay, order) can be configured independently via --rollback-parallelism, --rollback-delay, and --rollback-order options, following the same option pattern as standard updates.

38.4.3 Health Check as Update Gatekeeper

According to official Docker documentation on rolling updates, a task is considered failed during update if it fails to reach Running status or stops running within the --update-monitor window after starting. Containers failing their HEALTHCHECK are also stopped automatically by Swarm and marked as failed tasks, making proper HEALTHCHECK instructions in the image a primary mechanism to ensure failures are accurately detected, rather than relying solely on container processes remaining alive while internal applications fail to handle requests.

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
  CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "src/index.js"]

Without a proper HEALTHCHECK, Swarm relies solely on container process status (running or stopped) to evaluate update success, causing containers whose processes remain running but cannot actually process requests (such as failing database connections on startup) to still be marked successful, allowing rollouts to proceed to subsequent batches despite broken new versions. In production, health check endpoints should actively verify critical application dependencies (such as database connectivity) rather than returning a static 200 status, ensuring the rolling update gatekeeper functions effectively as a safety net before issues reach all production replicas.