Docker Executor
Run workflow steps in Docker containers for isolated, reproducible execution.
Basic Usage
yaml
steps:
- name: hello
executor:
type: docker
config:
image: alpine
autoRemove: true
command: echo "hello from container"
Execute in Existing Container
yaml
steps:
- name: exec-in-running
executor:
type: docker
config:
containerName: my-app
exec:
user: root
workingDir: /app
command: ./maintenance.sh
Configuration Options
Image Management
yaml
executor:
type: docker
config:
image: python:3.13
pull: always # always, missing, never
platform: linux/amd64
autoRemove: true
Volume Mounts
yaml
executor:
type: docker
config:
image: node:22
host:
binds:
- /host/data:/container/data:ro # Read-only
- ${PWD}/app:/app # Current directory
Environment Variables
yaml
executor:
type: docker
config:
image: postgres:17
container:
env:
- POSTGRES_PASSWORD=secret
- POSTGRES_USER=admin
- DEBUG=${DEBUG} # From host
Working Directory
yaml
executor:
type: docker
config:
image: maven:3
container:
workingDir: /project
host:
binds:
- ./:/project
Resource Limits
yaml
executor:
type: docker
config:
image: stress
host:
memory: 536870912 # 512MB
cpuShares: 512
Real-World Examples
Data Processing Pipeline
yaml
steps:
- name: extract
executor:
type: docker
config:
image: python:3.13-slim
autoRemove: true
host:
binds:
- ./data:/data
command: python extract.py /data/raw.csv
- name: transform
executor:
type: docker
config:
image: apache/spark:3.5.6
autoRemove: true
host:
binds:
- ./data:/data
memory: 2147483648 # 2GB
command: spark-submit transform.py
- name: load
executor:
type: docker
config:
image: postgres:17
autoRemove: true
container:
env:
- PGPASSWORD=${DB_PASSWORD}
command: psql -h db -U user -f load.sql
Build and Deploy
yaml
steps:
- name: build
executor:
type: docker
config:
image: golang:1.24
autoRemove: true
host:
binds:
- .:/app
container:
workingDir: /app
env:
- CGO_ENABLED=0
command: go build -o server .
- name: test
executor:
type: docker
config:
image: golang:1.24
autoRemove: true
host:
binds:
- .:/app
container:
workingDir: /app
command: go test ./...
- name: package
executor:
type: docker
config:
image: docker:latest
autoRemove: true
host:
binds:
- /var/run/docker.sock:/var/run/docker.sock
- .:/workspace
command: docker build -t myapp:${VERSION} /workspace
Database Operations
yaml
steps:
- name: backup
executor:
type: docker
config:
image: mysql:9.4
autoRemove: true
container:
env:
- MYSQL_PWD=${DB_PASSWORD}
host:
binds:
- ./backups:/backups
command: |
mysqldump -h db.example.com -u root \
--all-databases --single-transaction \
> /backups/backup-$(date +%Y%m%d).sql
- name: compress
executor:
type: docker
config:
image: alpine
autoRemove: true
host:
binds:
- ./backups:/backups
command: gzip /backups/backup-*.sql
Docker in Docker
Using Host Docker Socket
yaml
steps:
- name: docker-operations
executor:
type: docker
config:
image: docker:latest
autoRemove: true
host:
binds:
- /var/run/docker.sock:/var/run/docker.sock
command: docker ps
Docker Compose Setup
yaml
# compose.yml for Dagu with Docker support
services:
dagu:
image: ghcr.io/dagu-org/dagu:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./dags:/var/lib/dagu/dags
user: "0:0" # Run as root for Docker access
Advanced Patterns
Multi-Stage Processing
yaml
steps:
- name: compile
executor:
type: docker
config:
image: rust:1.88
autoRemove: true
host:
binds:
- ./src:/src
- ./target:/target
command: cargo build --release
- name: package
executor:
type: docker
config:
image: alpine
autoRemove: true
host:
binds:
- ./target/release:/app
command: tar -czf app.tar.gz /app
Platform-Specific Builds
yaml
steps:
- name: build-amd64
executor:
type: docker
config:
image: golang:1.24
platform: linux/amd64
autoRemove: true
command: GOARCH=amd64 go build
- name: build-arm64
executor:
type: docker
config:
image: golang:1.24
platform: linux/arm64
autoRemove: true
command: GOARCH=arm64 go build
Error Handling
Continue on Specific Exit Codes
yaml
steps:
- name: check-data
executor:
type: docker
config:
image: alpine
autoRemove: true
command: test -f /data/input.csv
continueOn:
exitCode: [1] # File not found is OK
- name: process-if-exists
executor:
type: docker
config:
image: python:3.13
autoRemove: true
command: python process.py || echo "No data to process"
Performance Tips
- Use specific tags instead of
latest
for reproducibility - Set
pull: missing
to use cached images - Remove containers with
autoRemove: true
- Mount only necessary directories to minimize overhead
- Use multi-stage builds for smaller final images
Security Considerations
- Docker socket access grants full control over host Docker
- Run as non-root when possible using
container.user
- Use read-only mounts for input data
- Avoid mounting sensitive host directories
- Set resource limits to prevent resource exhaustion
See Also
- Shell Executor - Run commands directly
- SSH Executor - Execute on remote hosts
- Execution Control - Advanced patterns