Deploy and Check a Docker Swarm Stack Safely
You will deploy a small Compose-based application as a Docker Swarm stack, verify that its services and tasks converge, and remove the test deployment cleanly. Allow 15 to 30 minutes if a Swarm manager and reachable images already exist. The examples use Docker CLI 29.8.1 from the installed docker-ce-cli package.
The route
Jump straight to the step you need, or tick off Done means at the end.
This is a manager-side workflow. Docker's stack command manages Swarm stacks; it is not the same as docker compose starting containers on one host. For a multi-node Swarm, run the commands from a manager and use image names that every node can pull, normally from a registry.
Checkpoint
This guide changes cluster state when you deploy and removes that state when you run the final command. Do not use the example stack name or file in a production Swarm without reviewing the images, ports, volumes and secrets first.
1. Confirm the CLI and Swarm context
Check the client version and whether the current Docker endpoint responds:
$ docker version --format '{{.Client.Version}}'
29.8.1
$ docker info --format 'Swarm: {{.Swarm.LocalNodeState}} ({{.Swarm.ControlAvailable}})'
Swarm: active (true)
The exact version and status will differ. You need an active Swarm and a manager. If docker info reports an inactive Swarm, initialise or join one according to your cluster procedure before continuing. Those actions change cluster membership and are deliberately outside this guide. If the CLI needs elevated access on your system, use your normal Docker access arrangement; do not add sudo automatically to every command.
2. Create a minimal stack file
Make a new working directory and create compose.yaml with an image that your nodes can pull. This example publishes the web service through Swarm's routing mesh and keeps Redis internal to the stack:
$ mkdir -p ~/stackdemo
$ cd ~/stackdemo
$ editor compose.yaml
services:
web:
image: registry.example.invalid/example/web:1.0
ports:
- "8000:8000"
deploy:
replicas: 2
redis:
image: redis:7-alpine
Replace the example web image with a real, pushed image before deployment. A local image or a Dockerfile build instruction is not a substitute for distributing the image to Swarm nodes. Docker's stack deployment uses the legacy Compose file version 3 format rather than every feature in the current Compose Specification, so check the supported stack syntax before copying a Compose file intended only for local development.
Before changing the Swarm, ask Docker to render the merged and interpolated configuration:
$ docker stack config --compose-file compose.yaml
services:
redis:
image: redis:7-alpine
web:
deploy:
replicas: 2
image: registry.example.invalid/example/web:1.0
ports:
- mode: ingress
target: 8000
published: 8000
networks:
default: {}
Review this output for unintended published ports, image tags, environment interpolation and mounts. With multiple files, pass them all with repeated --compose-file options in the order you want them merged.
3. Deploy the stack
State change: the next command creates or updates Swarm services and networks. Confirm that the stack name and file are correct first:
$ docker stack deploy --compose-file compose.yaml stackdemo
Creating network stackdemo_default
Creating service stackdemo_web
Creating service stackdemo_redis
The command's default detached mode returns after submitting the desired state rather than proving that every replica is ready. With registry credentials needed by workers, add --with-registry-auth only when your deployment policy allows the credentials to be sent to Swarm agents. Treat that option as security-sensitive and avoid exposing its output in shared logs.
Checkpoint
List the stack and confirm that Docker sees it:
$ docker stack ls
NAME SERVICES
stackdemo 2
4. Verify services and tasks
First check the desired and running replica counts:
$ docker stack services stackdemo
ID NAME MODE REPLICAS IMAGE
abc123 stackdemo_redis replicated 1/1 redis:7-alpine
def456 stackdemo_web replicated 2/2 registry.example.invalid/example/web:1.0
Wait and repeat the command if a service is still pulling an image. A count such as 1/2 means the desired state has not yet converged. It is not success merely because the service appears in the table.
For the reason behind a missing replica, inspect the tasks:
$ docker stack ps stackdemo
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
abc111 stackdemo_web.1 registry.example.invalid/example/web:1.0 worker-1 Running Running 2 minutes ago
abc222 stackdemo_web.2 registry.example.invalid/example/web:1.0 worker-2 Running Running 2 minutes ago
abc333 stackdemo_redis.1 redis:7-alpine worker-1 Running Running 2 minutes ago
Look at the ERROR column when a task is rejected or repeatedly restarted. Common causes include an image that workers cannot pull, an occupied published port, unsatisfied placement constraints, invalid mounts, or a process that exits. Use --no-trunc when the normal task message is too short.
5. Update without losing your reference point
Change one intentional value in compose.yaml, such as the web image tag, render the file again, then redeploy the same stack name:
$ docker stack config --compose-file compose.yaml > rendered.yaml
$ less rendered.yaml
$ docker stack deploy --compose-file compose.yaml stackdemo
Updating service stackdemo_web
$ docker stack services stackdemo
The rendered file is a review aid, not a substitute for keeping the source file. Do not use --prune casually: it removes services belonging to this stack that are no longer referenced by the submitted file. That can be useful for deliberate cleanup, but it can also remove a service that someone expected to remain.
If an update is unhealthy, first inspect docker stack ps stackdemo and the service logs with your normal operational tooling. Roll back using the previously reviewed image or Compose file, then deploy it again. Keep the old file until the new tasks have passed your application-level checks; Docker has no universal application health guarantee just because replicas say 2/2.
6. Remove the test stack
Destructive action
This removes the stack's services and networks. It can interrupt users and discard attached resources, so verify the name before running it:
$ docker stack ls
$ docker stack rm stackdemo
Removing service stackdemo_web
Removing service stackdemo_redis
Removing network stackdemo_default
Run docker stack ls again to confirm that the stack is gone. Removing a stack does not restore application data already written to external systems, and it is not a backup or rollback mechanism. Preserve any named volumes, external networks or data services according to their own recovery procedure.
Done means
- The current Docker endpoint is an active Swarm manager.
- The stack file has been rendered and reviewed before deployment.
docker stack servicesshows the expected service names and running replica counts.docker stack psshows tasks running on the intended nodes without errors.- Updates were reviewed before redeployment, and
--prunewas used only deliberately. - The test stack was removed only after its name and operational impact were checked.