Docker Compose
Dockflow uses a standard docker-compose.yml file located at .dockflow/docker/docker-compose.yml. This file defines your application services, networks, and volumes.
Basic Structure
services:
app:
image: my-app
build:
context: ../..
dockerfile: Dockerfile
ports:
- "${APP_PORT}:3000"
environment:
DB_PASSWORD: ${DB_PASSWORD}
ENV: ${ENV}
networks:
- app-network
networks:
app-network:The build section tells Dockflow how to build the image. The context is relative to the compose file location (.dockflow/docker/), so ../.. points to the project root.
Environment Variables
Environment variables can come from multiple sources:
servers.yml— defined per-environment or per-server (see Servers & Connections)- CI secrets — override
servers.ymlvalues - Nunjucks templating — all files in
.dockflow/are automatically rendered with Nunjucks
services:
app:
image: my-app
environment:
ENV: ${ENV} # Injected automatically
VERSION: ${VERSION} # Injected automatically
DB_HOST: ${DB_HOST} # From servers.yml or CI secrets
SECRET_KEY: ${SECRET_KEY} # From servers.yml or CI secrets
ports:
- "${APP_PORT:-3000}:3000" # With default value${ENV} and ${VERSION} are always available — Dockflow injects them automatically during deployment.
Automatic Image Tagging
Dockflow automatically appends the environment and version to image names for isolation:
my-app → my-app-production:1.0.0
my-app → my-app-staging:abc123When a Docker registry is configured, the registry URL is also prepended:
my-app → ghcr.io/myorg/my-app-production:1.0.0This behavior can be disabled with image_auto_tag: false in config.yml.
Deploy Configuration
The deploy section controls how the orchestrator manages your services. Dockflow injects sensible defaults for Swarm — on k3s these settings are translated to Kubernetes resource equivalents. You only need to specify what you want to override.
Default Values
Dockflow automatically injects these deploy settings for application services:
| Setting | Default |
|---|---|
update_config.parallelism | 1 |
update_config.delay | 10s |
update_config.failure_action | rollback |
update_config.monitor | 30s |
update_config.order | start-first |
update_config.max_failure_ratio | 0 |
rollback_config.parallelism | 1 |
rollback_config.delay | 5s |
rollback_config.monitor | 15s |
rollback_config.order | start-first |
Your compose file values always take priority over these defaults.
Replicas and Resources
services:
app:
image: my-app
deploy:
replicas: 3
resources:
limits:
cpus: "1.0"
memory: 512M
reservations:
cpus: "0.25"
memory: 128MCustom Update Strategy
services:
app:
image: my-app
deploy:
replicas: 2
update_config:
parallelism: 1
delay: 30s
order: start-first # Start new before stopping old (zero-downtime)
failure_action: rollback
rollback_config:
parallelism: 1
order: start-firstHealth Checks
Docker health checks let the orchestrator verify that containers are actually working:
services:
app:
image: my-app
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40sDockflow also supports its own health check system that runs external HTTP checks after deployment, independently of Docker’s built-in health checks.
Volumes
services:
app:
image: my-app
volumes:
- app-data:/app/data
- /host/path:/container/path # Bind mount
volumes:
app-data:On Swarm, volumes and networks are automatically prefixed with the stack name (e.g., myapp-production_app-data). On k3s, resources are scoped to the dockflow-{stackName} namespace.
Networks
services:
app:
image: my-app
networks:
- frontend
- backend
db:
image: postgres:16
networks:
- backend
networks:
frontend:
backend:External networks (Swarm only)
When a network is marked external: true, Dockflow automatically creates it on the Swarm manager before deploying if it doesn’t already exist:
services:
app:
networks:
- shared-net
networks:
shared-net:
external: trueThis is useful when multiple independent stacks need to communicate over a shared overlay network. Dockflow creates the network with --driver overlay --attachable so any stack can attach to it.
For communication between an app stack and its accessories stack within the same project, you don’t need an external network. Use the Swarm DNS name directly: {{ project_name }}-{{ env }}-accessories_servicename.
Placement Constraints
For multi-host deployments, you can control which nodes run each service:
services:
app:
image: my-app
deploy:
placement:
constraints:
- node.role == manager
- node.hostname == server-1
worker:
image: my-worker
deploy:
placement:
constraints:
- node.role == workerSee Multi-Host Deployment for details on configuring a multi-node cluster.
Multi-Service Example
services:
frontend:
image: my-frontend
build:
context: ../..
dockerfile: Dockerfile.frontend
ports:
- "80:80"
- "443:443"
environment:
API_URL: http://backend:3000
networks:
- frontend
deploy:
replicas: 2
backend:
image: my-backend
build:
context: ../..
dockerfile: Dockerfile.backend
environment:
DB_HOST: ${DB_HOST}
DB_PASSWORD: ${DB_PASSWORD}
REDIS_URL: redis://redis:6379
networks:
- frontend
- backend
deploy:
replicas: 3
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
networks:
frontend:
backend:Environment Isolation
Dockflow ensures complete isolation between environments (production, staging, etc.) through:
- Image names — automatically tagged with environment and version (
my-app-production:1.0.0) - Stack names — each environment gets its own isolated stack or namespace
- Networks and volumes — scoped per stack (Swarm prefix, k3s namespace)
Next: Build Strategy — choose how to build and transfer Docker images.