Docker Swarm Fundamentals, Services, Stacks, Secrets, Overlay Networks, Rolling Updates, and Legacy Estate Support: Guided Hands-On Workflow and Core Operations
Build and inspect a disposable Swarm safely: services, tasks, overlay networking, fake secrets, rolling updates, rollback, and stack deployment with bounded cleanup.
Learning objectives
- Create and dismantle a disposable single-node Swarm without touching production membership.
- Deploy and inspect a replicated service, task history, overlay network, fake secret, and stack.
- Perform a bounded rolling update and explicit rollback while preserving first-failure evidence.
-
Compare
docker composeanddocker stack deploybehavior from observed output. - Clean only chapter-labeled resources and leave the disposable Swarm deliberately.
docker info shows an existing
swarm, production containers, or unknown workloads, stop and use the
read-only/conceptual path. Never initialize or leave Swarm on an
estate you did not create for this lab.
1. Preflight: prove the host and context before changing cluster state
docker version
docker context show
docker info --format 'Swarm={{.Swarm.LocalNodeState}} Containers={{.Containers}}'
docker ps --format 'table {{.ID}} {{.Names}} {{.Image}}'
The intended disposable precondition is Swarm=inactive.
Existing standalone containers are not automatically deleted by
swarm init, but this course still requires an isolated
lab Engine because swarm membership, ingress networking, and later
cleanup are host-level state changes.
2. Initialize a single-node training swarm
docker swarm init
docker info --format '{{json .Swarm}}'
docker node ls
docker swarm init makes the current Engine the first
manager and creates cluster state plus built-in swarm networking. Do
not copy or publish join tokens. A single manager is intentionally
suitable only for this lab; it has zero manager-failure tolerance.
4. Create a labeled overlay and fake Swarm secret
docker network create --driver overlay --label academy.chapter=39 ch39_overlay
printf 'training-only-value
' > ch39-secret.txt
docker secret create --label academy.chapter=39 ch39_fake_secret ch39-secret.txt
rm -f ch39-secret.txt
docker network inspect ch39_overlay --format '{{json .Labels}}'
docker secret inspect ch39_fake_secret --format '{{json .Spec.Labels}}'
The secret’s value is intentionally not printed. Its object identity, labels, and service grant are enough to prove control-plane state.
5. Create a replicated service from digest A
docker service create \
--name ch39_app \
--label academy.chapter=39 \
--network ch39_overlay \
--secret ch39_fake_secret \
--replicas 2 \
--restart-condition on-failure \
--update-parallelism 1 \
--update-delay 3s "$IMAGE_A" sh -c 'test -s /run/secrets/ch39_fake_secret && while true; do sleep 30; done'
docker service inspect ch39_app --pretty
docker service ps --no-trunc ch39_app
On one node both replicas land on the same Engine, so this tests service/task semantics—not high availability. The secret grant is part of the service spec; task containers receive the secret only while they run.
6. Inspect the service, tasks, and node-local containers separately
docker service inspect ch39_app --format 'ID={{.ID}} Version={{.Version.Index}} Image={{.Spec.TaskTemplate.ContainerSpec.Image}}'
docker service ps --no-trunc --format 'table {{.ID}} {{.Node}} {{.DesiredState}} {{.CurrentState}} {{.Error}}' ch39_app
docker ps --filter label=com.docker.swarm.service.name=ch39_app --format 'table {{.ID}} {{.Names}} {{.Image}}'
Service ID/version belongs to the manager object. Task IDs belong to scheduler attempts. Container IDs belong to the node runtime. Keep all three identities in incident evidence.
7. Perform a successful serial update to digest B
docker service update --image "$IMAGE_B" --update-parallelism 1 --update-delay 3s --update-failure-action pause ch39_app
docker service ps --no-trunc ch39_app
docker service inspect ch39_app --format '{{json .UpdateStatus}}'
docker service inspect ch39_app --format '{{.Spec.TaskTemplate.ContainerSpec.Image}}'
Watch task generations change. The old tasks remain visible in history, which is why you should preserve output instead of relying only on the currently running containers.
8. Roll back deliberately
docker service rollback ch39_app
docker service ps --no-trunc ch39_app
docker service inspect ch39_app --format 'Image={{.Spec.TaskTemplate.ContainerSpec.Image}} Rollback={{json .UpdateStatus}}'
Rollback restores the previous service specification. Verify the resulting image digest and task states; do not infer success merely from the command returning zero.
9. Deploy a small stack and observe the compatibility boundary
cat > ch39-stack.yml <<EOF
version: "3.8"
services:
sleeper:
image: ${IMAGE_A}
command: ["sh", "-c", "while true; do sleep 30; done"]
networks: [labnet]
deploy:
replicas: 1
labels:
academy.chapter: "39"
networks:
labnet:
driver: overlay
EOF
docker stack deploy -c ch39-stack.yml ch39demo
docker stack services ch39demo
docker stack ps --no-trunc ch39demo
This file intentionally uses the V3-era deployment subset understood
by docker stack deploy. A modern local Compose feature
such as develop.watch is not proof of Swarm stack
compatibility.
10. Inspect only chapter-owned resources before cleanup
docker service ls --filter label=academy.chapter=39
docker network ls --filter label=academy.chapter=39
docker secret ls --filter label=academy.chapter=39
docker stack ls
Inventory first. Stack-generated objects have stack namespace labels; the explicitly created service/network/secret also carry the chapter label.
11. Bounded cleanup
docker stack rm ch39demo
docker service rm ch39_app
docker secret rm ch39_fake_secret
docker network rm ch39_overlay
rm -f ch39-stack.yml
docker service ls
docker network ls --filter label=academy.chapter=39
docker secret ls --filter label=academy.chapter=39
No prune command is used. Removal names exact disposable objects.
12. Leave Swarm only after proving it is the disposable single-manager lab
docker node ls
docker info --format '{{json .Swarm}}'
# Only if this is the lab swarm you created above and it has one manager:
docker swarm leave --force
docker info --format '{{.Swarm.LocalNodeState}}'
--force to leave. That is acceptable only for this
explicitly disposable one-node lab. In a real estate, manager
removal is a quorum operation: demote/remove nodes with a plan and
never force-leave casually.
13. Small challenge: choose the layer before the command
A service shows two desired replicas, but one slot repeatedly
creates failed tasks. Which layer do you inspect first: the
node-local container list, the service/task scheduler state, the
overlay network, or the registry? Start with
docker service ps --no-trunc to preserve task errors
and placement evidence, then follow the error to image, node,
secret/config, mount, or network state. The challenge is to
identify the failing layer before “fixing” anything.
Knowledge check
Why is docker service ps usually more
informative than docker ps for a failed Swarm
rollout?
It shows task history, desired/current state, node placement,
and scheduler/runtime errors across task generations;
docker ps is node-local and mostly
current-container state.
What did the single-node lab prove about overlay networking?
It proved the Swarm overlay object and service attachment semantics, but not multi-host overlay dataplane behavior or node-failure availability.
Why remove the stack before the externally created secret?
A running service may still reference a secret. Removing dependent services first preserves referential integrity and avoids turning cleanup into a troubleshooting incident.
When is docker swarm leave --force appropriate
in this lesson?
Only after proving the node is the disposable single-manager lab created for the exercise. It is not a routine production-manager cleanup command.
After an update command succeeds, what must you still verify?
Service image/spec, UpdateStatus, task generations/current state, and application behavior. Command success is not workload convergence evidence.
Official references and version notes
2026-09-22. Course baseline: Docker Engine/CLI 29.8.1, Compose 5.5.1, Buildx 0.37.1, BuildKit 0.33.0. The executable labs record the learner’s actual installed component versions. Swarm mode remains built into current Docker Engine and current Docker documentation explicitly describes it as a production runtime option; this chapter uses “legacy estate” to mean an existing platform that must be operated or evaluated deliberately, not that Swarm mode is removed.
- Docker Docs — Swarm mode — current support position and core feature set.
- Docker Docs — How services work — desired state, services, tasks, replicas, constraints, and update behavior.
- Docker Docs — How nodes work — managers, workers, scheduling, and manager-count guidance.
- Docker Docs — Administer and maintain a swarm — quorum, manager distribution, backup, and disaster recovery.
- Docker Docs — Raft consensus — replicated manager state and majority requirements.
- Docker Docs — Manage swarm service networks — overlay, ingress, routing mesh, and control/data-plane traffic.
- Docker Docs — Manage sensitive data with Docker secrets — encrypted Raft storage and in-memory task mounts.
- Docker Docs — Docker configs — immutable configs and service/stack lifecycle.
- Docker Docs — Apply rolling updates to a service — update delay, parallelism, and task replacement.
- Docker Docs — Rolling update tutorial — observing task transitions during updates.
- Docker Docs — Deploy a stack to a swarm — manager-only stack deployment and Compose-file compatibility warning.
- Docker CLI — docker stack deploy — current flags including image digest resolution and registry auth propagation.
- Docker CLI — docker service update — rolling-update, rollback, image, secret, config, and publish controls.
- Docker Engine 29 release notes — current Engine-era compatibility baseline.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.