skip to content

How does deploying a Compose file with `docker stack deploy` differ from running the same file with `docker compose up`, and which Compose keys are ignored when deploying to a swarm?

level: middleimportance: should knowfreq 34%

answer

  1. stack deploy = swarm; compose up = one engine
  2. deploy: block only honoured by stack deploy
  3. build, container_name, depends_on, links ignored
  4. --with-registry-auth for private images
  5. named volumes are per node

basics

~20 s

docker compose up runs containers on one engine and can build images. docker stack deploy sends the file to swarm managers, which create services across the cluster; it honours the deploy: section and ignores single-host keys such as build, container_name, depends_on and links.

solid answer

~50 s

Same file format, two different execution models. `docker compose up` talks to one engine, can `build` images locally, honours `depends_on` ordering, `container_name`, `links` and `restart`, and gives you containers. `docker stack deploy -c stack.yml myapp` talks to a swarm manager. Every service in the file becomes a swarm service across the cluster, labelled with the stack name so `docker stack services/ps/rm` can act on the group. The `deploy:` block — replicas, mode, placement constraints, resource reservations and limits, restart_policy, update_config and rollback_config — is honoured *only* here; `docker compose up` largely ignores it. Conversely swarm ignores single-host keys. `build:` is the big one: images must already exist in a registry every node can pull from, and private ones usually need `--with-registry-auth`. `container_name`, `links`, `network_mode` and `depends_on` ordering are also not applied — services must tolerate starting in any order.

code

yaml · 26 lines
yaml
services:
  api:
    image: registry.example.com/api:1.4.2
    networks: [appnet]
    ports:
      - "8080:8080"
    environment:
      DB_URL: postgres://db:5432/app
    deploy:
      replicas: 4
      restart_policy:
        condition: on-failure
      update_config:
        parallelism: 1
        delay: 15s
        order: start-first
        failure_action: rollback
      resources:
        limits:
          cpus: "1.0"
          memory: 512M
      placement:
        constraints: [node.role == worker]
networks:
  appnet:
    driver: overlay

go deeper

for a junior

Know the two commands target different things — one engine versus a swarm — and that stack deploy needs an image from a registry.

for a middle

Name the deploy: block as swarm-only and list the ignored single-host keys, with build and depends_on as the ones that bite.

for a senior

Talk about the migration checklist and the operational consequences: registry auth, per-node volumes, retry-based start-up, immutable tags.

for a principal

Decide whether the same file should serve both development and production, or whether the divergence in honoured keys makes a separate generated stack spec more honest.

## One file, two runtimes The Compose file describes services, networks and volumes. What differs is who executes it. **`docker compose up`** is a client-side orchestrator against a single Docker Engine. It builds images if asked, creates containers with predictable names, wires them onto a bridge network, and starts them in `depends_on` order. It is a development and single-host tool. **`docker stack deploy -c stack.yml <stack>`** sends the parsed spec to a swarm manager, which creates one *service* per Compose service and reconciles it across nodes. Everything is labelled with `com.docker.stack.namespace=<stack>`, and networks named in the file are created as overlay networks prefixed with the stack name unless declared `external: true`. Managing the group is then `docker stack ls`, `docker stack services <stack>`, `docker stack ps <stack>`, `docker stack rm <stack>`. ## The deploy: block Swarm-specific settings live under `deploy:` — `replicas`, `mode: global`, `placement.constraints`, `placement.preferences`, `resources.limits` and `reservations`, `restart_policy`, `update_config`, `rollback_config` and `labels`. This is where the cluster behaviour of the service is expressed, and it is the section `docker compose up` mostly disregards. When reviewing a stack file, the deploy blocks are where the production decisions live. ## Keys swarm ignores The exact list has shifted between Compose file versions and the Compose Specification, so state the principle first — *anything that only makes sense on one host is dropped* — and then the well-known members: - **`build:`** — there is no cluster-wide build; pre-build and push, then reference the image. `docker stack deploy` will not build for you. - **`container_name:`** — task containers get generated names; the service name is the addressable identity. - **`depends_on:`** — no start ordering. Services must retry their dependencies. This is the most common source of "it worked in compose" bugs. - **`links:`, `external_links:`, `network_mode:`** — superseded by overlay networks and service DNS. - **`restart:`** — replaced by `deploy.restart_policy`. Because the precise set depends on file version and engine, the honest interview answer gives the principle plus these examples and says you check the reference for the version in use. ## Practical consequences - **Registry.** Every node pulls the image itself. A locally built image exists on one node only, so tasks scheduled elsewhere fail to start. Push to a registry, prefer immutable tags or digests, and pass `--with-registry-auth` so managers forward your credentials to the nodes. - **Volumes.** A named volume in a stack is created per node by default, so three replicas on three nodes get three independent volumes. Shared state needs an external volume driver or an external service. - **Secrets and configs.** Swarm's top-level `secrets:` and `configs:` sections deliver files into tasks from the encrypted Raft store, which has no single-host Compose equivalent. - **Interpolation.** Variables such as `${TAG}` are resolved client-side before the spec is sent, from your shell, not from the cluster. ## Migration checklist Turning a development Compose file into a stack: remove `build` (or keep it for local use and accept it is ignored), replace `restart` with `deploy.restart_policy`, delete `depends_on` and add retry logic, add `deploy.replicas` and resource limits, move host-specific bind mounts to volumes or configs, and check that every image reference is a registry path.

  • Your stack file has depends_on and the app breaks on deploy. What is the fix?
    Swarm ignores depends_on, so tasks start in arbitrary order and a service may come up before its database. The fix is in the application: retry the connection with backoff at start-up, and expose a healthcheck so the service is only considered healthy once its dependency is reachable. Wait-for scripts help, but resilient start-up is the real answer since dependencies can also disappear mid-life.
  • Why does docker stack deploy need --with-registry-auth for a private image?
    Each node pulls the image itself, and the nodes do not have your local credentials. The flag tells the manager to take the registry authentication token from your client session and include it in the service spec so agents can authenticate the pull. Without it, tasks fail on private images with authentication errors even though the deploy command itself succeeded.

saying these in an interview costs you the question

  • Expecting docker stack deploy to build images from the build: key
  • Relying on depends_on for start ordering in a swarm
  • Assuming a named volume is shared across nodes
  • Thinking docker compose up honours the deploy: section's replicas
  • Referencing a locally built image tag with no registry

context