services: postgres: image: postgres:18 container_name: kestra-postgres volumes: - /path/to/kestra/postgres-data:/var/lib/postgresql environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"] interval: 30s timeout: 10s retries: 10 networks: - kestra-net kestra: image: kestra/kestra:latest container_name: kestra pull_policy: always # Kestra, by default, has a termination grace period of 5m. We need to wait a little more to be sure no active tasks are running. stop_grace_period: 6m # Note that this setup with a root user is intended for development purpose. # Our base image runs without root, but the Docker Compose implementation needs root to access the Docker socket user: "root" restart: unless-stopped command: server standalone volumes: - /path/to/kestra/kestra-data:/app/storage - /var/run/docker.sock:/var/run/docker.sock - /tmp/kestra-wd:/tmp/kestra-wd # Mounted read-only so Kestra flows can drive the ansible repo directly - /path/to/repos/ansible:/opt/repos/ansible:ro - /path/to/ansible-venv:/home/user/ansible-venv:ro - /path/to/ssh-keys:/home/user/.ssh:ro environment: KESTRA_CONFIGURATION: | datasources: postgres: url: jdbc:postgresql://postgres:5432/kestra driverClassName: org.postgresql.Driver username: ${POSTGRES_USER} password: ${POSTGRES_PASSWORD} kestra: server: basic-auth: username: ${USERNAME} password: ${PASSWORD} repository: type: postgres storage: type: local local: base-path: "/app/storage" queue: type: postgres tasks: tmp-dir: path: /tmp/kestra-wd/tmp url: http://localhost:8080/ ports: - "${HTTP_PORT}:8080" - "8081:8081" depends_on: postgres: condition: service_started networks: - kestra-net networks: kestra-net: external: true