Back to BlogDocker compose · docker

Converting Docker Compose to Swarm Mode with Deploy Configuration

2025-12-26

Docker Compose files designed for single-host development can be extended to run on Docker Swarm clusters through the deploy section. This section contains all Swarm-specific configuration, including replica counts, placement constraints, update policies, and rollback strategies. Understanding how to properly configure the deploy section transforms your Compose files from development tools into production-ready stack definitions.

Understanding the Deploy Section

The deploy section is ignored by standard docker-compose commands and only takes effect when deploying to a Swarm using docker stack deploy. This separation allows a single Compose file to work both locally and in Swarm mode.

version: '3.8'

services:
  web:
    image: nginx:alpine
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure

When you run docker-compose up, the deploy section is ignored. When you run docker stack deploy -c docker-compose.yml mystack, only the deploy configuration applies.

Basic Replica Configuration

The most fundamental Swarm configuration is specifying the number of service replicas:

version: '3.8'

services:
  api:
    image: myapp/api:latest
    deploy:
      replicas: 5

This creates five identical containers running the API service, distributed across available Swarm nodes. The Swarm scheduler automatically places replicas on different nodes for high availability.

Replicated vs Global Mode

Services can run in two modes:

Replicated mode (default): Runs a specified number of replicas

services:
  api:
    image: myapp/api:latest
    deploy:
      mode: replicated
      replicas: 3

Global mode: Runs exactly one replica on every Swarm node

services:
  monitoring:
    image: prometheus/node-exporter
    deploy:
      mode: global

Global mode is ideal for node-level services like monitoring agents, log collectors, or network proxies that need to run on every node in the cluster.

Placement Constraints

Control where services run using placement constraints:

version: '3.8'

services:
  database:
    image: postgres:14
    deploy:
      placement:
        constraints:
          - node.role == manager
          - node.labels.storage == ssd

This restricts the database to run only on manager nodes that have the storage=ssd label.

Common constraint patterns:

  • node.role == manager: Run only on manager nodes
  • node.role == worker: Run only on worker nodes
  • node.hostname == node1: Run on a specific node
  • node.labels.key == value: Match custom node labels

Multiple Placement Constraints

Combine constraints for precise placement:

services:
  cache:
    image: redis:alpine
    deploy:
      replicas: 3
      placement:
        constraints:
          - node.role == worker
          - node.labels.tier == cache
          - node.labels.datacenter == primary

All constraints must be satisfied for a replica to be placed on a node. This ensures cache services run only on worker nodes in the primary datacenter with the cache tier label.

Placement Preferences

While constraints are absolute requirements, preferences express preferred placement that the scheduler tries to honor:

services:
  web:
    image: nginx:alpine
    deploy:
      replicas: 6
      placement:
        preferences:
          - spread: node.labels.datacenter

This spreads replicas evenly across nodes with different datacenter label values, improving availability by distributing services across failure domains.

Multiple preferences create layered distribution:

services:
  api:
    image: myapp/api:latest
    deploy:
      replicas: 9
      placement:
        preferences:
          - spread: node.labels.datacenter
          - spread: node.labels.rack

This first spreads across datacenters, then spreads within each datacenter across racks.

Maximum Replicas Per Node

Limit how many replicas can run on a single node:

services:
  worker:
    image: myapp/worker:latest
    deploy:
      replicas: 10
      placement:
        max_replicas_per_node: 2

Even with 10 replicas, no single node will run more than 2 worker instances. This prevents resource saturation on individual nodes and improves fault tolerance.

Update Configuration

Control how services are updated when deploying new versions:

services:
  api:
    image: myapp/api:latest
    deploy:
      replicas: 6
      update_config:
        parallelism: 2
        delay: 10s
        failure_action: rollback
        monitor: 30s
        max_failure_ratio: 0.3
        order: stop-first

Update parameters:

  • parallelism: Number of replicas to update simultaneously
  • delay: Time to wait between update batches
  • failure_action: Action when update fails (pause, continue, rollback)
  • monitor: Time to monitor each task for failures after update
  • max_failure_ratio: Fraction of tasks allowed to fail during update
  • order: Update order (stop-first or start-first)

Update Order Strategies

The order parameter controls how replicas are replaced:

Stop-first (default): Stop old replica before starting new one

deploy:
  update_config:
    order: stop-first

This ensures no over-provisioning of resources but causes temporary capacity reduction.

Start-first: Start new replica before stopping old one

deploy:
  update_config:
    order: start-first

This maintains full capacity during updates but temporarily requires extra resources.

Rollback Configuration

Define how automatic rollbacks behave when updates fail:

services:
  api:
    image: myapp/api:latest
    deploy:
      replicas: 5
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: rollback
      rollback_config:
        parallelism: 2
        delay: 5s
        failure_action: pause
        monitor: 20s
        max_failure_ratio: 0.2
        order: stop-first

Rollback configuration mirrors update configuration but controls the rollback process. When an update fails and triggers a rollback, these parameters determine how quickly and safely the service returns to its previous state.

Restart Policy Configuration

Specify how Swarm handles container failures:

services:
  web:
    image: nginx:alpine
    deploy:
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s

Restart policy parameters:

  • condition: When to restart (none, on-failure, any)
  • delay: Time to wait before restart attempts
  • max_attempts: Maximum restart attempts before giving up
  • window: Time window for evaluating restart attempts

If a container fails max_attempts times within window, Swarm stops trying to restart it.

Endpoint Mode Configuration

Control how traffic routes to service replicas:

services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    deploy:
      replicas: 3
      endpoint_mode: vip

Endpoint modes:

  • vip (default): Virtual IP mode with built-in load balancing
  • dnsrr: DNS round-robin without load balancer

VIP mode provides better load distribution and connection handling, while DNS round-robin offers simpler networking for clients that handle load balancing themselves.

Labels for Services and Containers

Add metadata to services and their containers:

services:
  api:
    image: myapp/api:latest
    deploy:
      labels:
        com.example.service.type: "api"
        com.example.version: "2.0"
      replicas: 3
    labels:
      com.example.container.type: "api-instance"

Labels in the deploy section apply to the Swarm service, while labels outside deploy apply to individual containers. Service labels are used by orchestration tools and management systems, while container labels are visible to monitoring and logging agents.

Service-Level Resource Reservations

Request guaranteed resources for service replicas:

services:
  database:
    image: postgres:14
    deploy:
      replicas: 2
      resources:
        reservations:
          cpus: '1.0'
          memory: 2G

Reservations tell the Swarm scheduler to only place replicas on nodes with available resources. If no node has sufficient resources, the replica remains in pending state.

Service-Level Resource Limits

Set maximum resource usage for replicas:

services:
  worker:
    image: myapp/worker:latest
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: '2.0'
          memory: 4G

Limits prevent individual replicas from consuming excessive resources, protecting other services on the same node.

Combined Resource Configuration

Use both reservations and limits for comprehensive resource management:

services:
  api:
    image: myapp/api:latest
    deploy:
      replicas: 4
      resources:
        reservations:
          cpus: '0.5'
          memory: 512M
        limits:
          cpus: '2.0'
          memory: 2G

This configuration guarantees each replica at least 0.5 CPU and 512MB memory while preventing it from exceeding 2 CPU and 2GB memory.

Generic Resources for Specialized Hardware

Allocate specialized hardware resources like GPUs:

services:
  ml-processor:
    image: myapp/ml:latest
    deploy:
      replicas: 2
      resources:
        reservations:
          generic_resources:
            - discrete_resource_spec:
                kind: 'gpu'
                value: 1

This reserves one GPU for each replica. Nodes must advertise GPU availability for the scheduler to place these replicas appropriately.

Deployment Mode for Testing

Configure services that run once for initialization or testing:

services:
  database-migrator:
    image: myapp/migrator:latest
    deploy:
      restart_policy:
        condition: none
      replicas: 1

With condition: none, the service runs once and isn't restarted on failure, suitable for one-time tasks like database migrations or data initialization.

Update and Rollback Monitoring

Fine-tune failure detection during updates:

services:
  api:
    image: myapp/api:latest
    deploy:
      replicas: 10
      update_config:
        parallelism: 2
        delay: 15s
        monitor: 60s
        max_failure_ratio: 0.1
        failure_action: rollback

With a 60-second monitor window and 10% maximum failure ratio, if more than one replica (10% of 10) fails within 60 seconds of update, the entire update automatically rolls back.

Complex Placement Scenarios

Combine constraints and preferences for sophisticated placement:

services:
  frontend:
    image: myapp/frontend:latest
    deploy:
      replicas: 9
      placement:
        constraints:
          - node.role == worker
          - node.labels.tier == web
        preferences:
          - spread: node.labels.zone
          - spread: node.labels.rack
        max_replicas_per_node: 2

This ensures frontend replicas run only on web-tier worker nodes, spreads them across availability zones and racks, and limits node saturation by capping replicas per node.

Service Dependencies in Swarm

While Swarm doesn't enforce startup order like depends_on does locally, you can influence service startup timing:

version: '3.8'

services:
  database:
    image: postgres:14
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
        delay: 5s
  
  api:
    image: myapp/api:latest
    deploy:
      replicas: 3
      restart_policy:
        condition: on-failure
        delay: 10s

The API's longer restart delay gives the database time to initialize first. For more robust dependency handling, applications should implement connection retry logic.

Rolling Back to Specific Versions

Swarm maintains service version history, enabling rollback to previous states:

docker service update --rollback mystack_api

Configure how far back rollbacks can go:

services:
  api:
    image: myapp/api:latest
    deploy:
      replicas: 5
      rollback_config:
        parallelism: 2
        delay: 5s
        failure_action: pause

When triggered, Swarm reverts to the previous service configuration, not just the previous image.

Update Failure Scenarios

Handle various failure conditions appropriately:

services:
  critical-service:
    image: myapp/critical:latest
    deploy:
      replicas: 5
      update_config:
        parallelism: 1
        delay: 30s
        monitor: 60s
        failure_action: pause
        max_failure_ratio: 0

With max_failure_ratio: 0 and failure_action: pause, any failure during update pauses the rollout, requiring manual intervention. This is appropriate for critical services where partial updates are unacceptable.

For less critical services, allow some failure:

services:
  batch-processor:
    image: myapp/processor:latest
    deploy:
      replicas: 20
      update_config:
        parallelism: 5
        delay: 10s
        failure_action: continue
        max_failure_ratio: 0.25

This continues updating even if up to 25% of replicas fail, accepting some disruption in exchange for completing the deployment.

Phased Deployment Strategies

Implement canary deployments through careful update configuration:

services:
  api:
    image: myapp/api:v2
    deploy:
      replicas: 10
      update_config:
        parallelism: 1
        delay: 120s
        monitor: 180s
        max_failure_ratio: 0.1
        failure_action: rollback

With single-replica parallelism and long delays, you can observe each new replica's behavior extensively before proceeding. If issues arise, automatic rollback protects the remaining replicas.

Label-Based Service Selection

Use labels to select services for operations:

services:
  frontend:
    image: myapp/frontend:latest
    deploy:
      labels:
        com.example.tier: "presentation"
        com.example.team: "frontend-team"
      replicas: 3
  
  api:
    image: myapp/api:latest
    deploy:
      labels:
        com.example.tier: "application"
        com.example.team: "backend-team"
      replicas: 5

Labels enable filtering and bulk operations:

docker service ls --filter label=com.example.tier=application

This lists only services with the specified label, useful for managing large stacks with many services.

Graceful Service Shutdown

Configure how Swarm handles container termination:

services:
  worker:
    image: myapp/worker:latest
    stop_grace_period: 60s
    deploy:
      replicas: 5
      update_config:
        parallelism: 1
        delay: 30s

The stop_grace_period gives containers time to finish in-progress work before forceful termination. During updates, new replicas start while old ones gracefully shut down, minimizing disruption.

Service Lifecycle Management

A complete service configuration for production:

version: '3.8'

services:
  api:
    image: myapp/api:v1.5.0
    stop_grace_period: 30s
    deploy:
      mode: replicated
      replicas: 8
      labels:
        com.example.service: "api"
        com.example.version: "1.5.0"
      update_config:
        parallelism: 2
        delay: 20s
        failure_action: rollback
        monitor: 45s
        max_failure_ratio: 0.2
        order: start-first
      rollback_config:
        parallelism: 4
        delay: 10s
        failure_action: pause
        monitor: 30s
        max_failure_ratio: 0.1
        order: stop-first
      restart_policy:
        condition: on-failure
        delay: 10s
        max_attempts: 5
        window: 180s
      placement:
        constraints:
          - node.role == worker
          - node.labels.tier == application
        preferences:
          - spread: node.labels.zone
        max_replicas_per_node: 3
      resources:
        reservations:
          cpus: '0.5'
          memory: 512M
        limits:
          cpus: '2.0'
          memory: 2G
      endpoint_mode: vip

This configuration provides comprehensive control over service deployment, updates, placement, and recovery.

Stack Deployment Command

Deploy your configured stack to Swarm:

docker stack deploy -c docker-compose.yml mystack

This creates or updates all services defined in the Compose file according to their deploy configurations.

View deployed services:

docker stack services mystack

Remove the stack:

docker stack rm mystack

Updating Running Stacks

Modify the Compose file and redeploy to update services:

services:
  api:
    image: myapp/api:v1.6.0  # Changed from v1.5.0
    deploy:
      replicas: 10  # Increased from 8
      # Other configuration unchanged

Redeploy the stack:

docker stack deploy -c docker-compose.yml mystack

Swarm detects changes and updates only affected services according to their update configuration.

Service-Specific Update Policies

Different services may need different update strategies:

version: '3.8'

services:
  frontend:
    image: myapp/frontend:latest
    deploy:
      replicas: 5
      update_config:
        parallelism: 5  # Update all at once
        delay: 0s
        order: start-first
  
  api:
    image: myapp/api:latest
    deploy:
      replicas: 10
      update_config:
        parallelism: 2  # Gradual rollout
        delay: 30s
        order: start-first
  
  database:
    image: postgres:14
    deploy:
      replicas: 1
      update_config:
        parallelism: 1
        delay: 0s
        order: stop-first  # Prevent split-brain

The frontend can update quickly since it's stateless, the API updates gradually to ensure stability, and the database updates conservatively to prevent data issues.

Combining Local and Swarm Configuration

A single Compose file can support both local development and Swarm deployment:

version: '3.8'

services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    # Used locally
    restart: unless-stopped
    # Used in Swarm
    deploy:
      replicas: 3
      restart_policy:
        condition: on-failure

When running docker-compose up, the restart field applies. When running docker stack deploy, the deploy section applies.

Node Availability and Service Placement

Services react to node availability changes:

services:
  api:
    image: myapp/api:latest
    deploy:
      replicas: 6
      placement:
        constraints:
          - node.role == worker

When a worker node becomes unavailable, Swarm automatically reschedules its replicas to remaining healthy nodes, maintaining the desired replica count.

Deployment Strategies for Different Service Types

Stateless services: Aggressive parallel updates

services:
  stateless-api:
    image: myapp/api:latest
    deploy:
      replicas: 10
      update_config:
        parallelism: 5
        delay: 5s

Stateful services: Conservative sequential updates

services:
  stateful-processor:
    image: myapp/processor:latest
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 60s
        monitor: 120s

Singleton services: Zero-downtime updates with start-first

services:
  scheduler:
    image: myapp/scheduler:latest
    deploy:
      replicas: 1
      update_config:
        parallelism: 1
        order: start-first

Monitoring Deployment Progress

Track deployment status in real-time:

docker service ps mystack_api

This shows all tasks (replicas) for the service, including their current state, desired state, node assignment, and error messages.

Watch updates as they progress:

watch docker service ps mystack_api

This continuously refreshes the view, showing updates rolling across replicas.

Deployment Rollback Triggers

Configure when automatic rollbacks should occur:

services:
  critical-service:
    image: myapp/critical:latest
    deploy:
      replicas: 8
      update_config:
        parallelism: 2
        delay: 30s
        monitor: 90s
        max_failure_ratio: 0.125  # 1 out of 8
        failure_action: rollback

If any single replica fails within its 90-second monitoring window during update, the entire deployment rolls back. This extremely conservative approach protects critical services.

Best Practices for Deploy Configuration

Start with conservative update policies: Begin with low parallelism and long delays, then optimize based on observed stability.

Match update order to service type: Use start-first for stateless services and stop-first for stateful services or singletons.

Set appropriate monitoring windows: Longer monitoring catches delayed failures but slows deployments. Balance based on your application's failure patterns.

Use placement constraints strategically: Constrain services to appropriate node types but avoid over-constraining, which limits scheduling flexibility.

Implement proper restart policies: Configure restart policies that match your service's failure recovery characteristics.

Test rollback procedures: Regularly verify that rollback configurations work as expected by intentionally deploying failing versions.

Label extensively: Use labels to document service characteristics, ownership, and purpose for easier management.

Document update strategies: Comment your deploy configurations explaining the reasoning behind parameter choices.

Monitor resource usage: Ensure reservations match actual requirements and limits prevent resource exhaustion.

Plan for node failures: Design placement strategies and replica counts that maintain service availability during node outages.

Use version-specific image tags: Always deploy specific image versions rather than latest for predictable rollbacks.

Implement health checks: While outside the deploy section, health checks are critical for successful updates and rollbacks.

Docker Swarm's deploy section transforms Compose files into production orchestration configurations. By properly configuring replicas, placement, updates, rollbacks, and restart policies, you can deploy services that scale horizontally, update safely, recover automatically, and distribute intelligently across your cluster. The deploy section provides the foundation for running containerized applications at scale with high availability and operational resilience.

We use cookies to improve your experience and analyse site traffic. See our Privacy Policy.