networks: # Overlay network used by your Swarm services (Traefik, Vault, etc.) cicd: external: true secrets: woodpecker_vault_role_id: external: true woodpecker_vault_secret_id: external: true configs: woodpecker_vault_agent_hcl: file: ./vault/agent.hcl tpl_agent_secret: file: ./vault/templates/agent_secret.ctmpl tpl_gitea_client_id: file: ./vault/templates/gitea_client_id.ctmpl tpl_gitea_client_secret: file: ./vault/templates/gitea_client_secret.ctmpl tpl_pg_dsn: file: ./vault/templates/pg_dsn.ctmpl volumes: # tmpfs volume for rendered secrets (read by server/agent) vault_secrets: driver: local driver_opts: type: tmpfs device: tmpfs o: size=32m,uid=0,gid=0,mode=0750 services: # Vault Agent sidecar to render secrets from Vault into files vault-agent-woodpecker: image: hashicorp/vault:latest networks: [cicd] cap_add: ["IPC_LOCK"] environment: # Use the actual Swarm service DNS name of Vault inside the overlay VAULT_ADDR: "http://vault_vault:8200" secrets: - source: woodpecker_vault_role_id target: /vault/secrets/role_id - source: woodpecker_vault_secret_id target: /vault/secrets/secret_id volumes: - vault_secrets:/vault/secrets:rw configs: - source: woodpecker_vault_agent_hcl target: /etc/vault/agent.hcl - source: tpl_agent_secret target: /etc/vault/templates/agent_secret.ctmpl - source: tpl_gitea_client_id target: /etc/vault/templates/gitea_client_id.ctmpl - source: tpl_gitea_client_secret target: /etc/vault/templates/gitea_client_secret.ctmpl - source: tpl_pg_dsn target: /etc/vault/templates/pg_dsn.ctmpl command: ["sh", "-lc", "vault agent -config=/etc/vault/agent.hcl"] healthcheck: test: ["CMD-SHELL", "test -s /vault/secrets/agent_secret -a -s /vault/secrets/gitea_client_id -a -s /vault/secrets/gitea_client_secret -a -s /vault/secrets/pg_dsn" ] interval: 10s timeout: 3s retries: 30 # Woodpecker Server (HTTP UI on :8000, gRPC on :9000) woodpecker-server: user: "0:0" # ensures read access to tmpfs secrets (mode 0750) image: woodpeckerci/woodpecker-server:v3-alpine networks: [cicd] depends_on: [vault-agent-woodpecker] volumes: - vault_secrets:/vault/secrets:ro environment: WOODPECKER_HOST: "https://ci.sendico.io" WOODPECKER_OPEN: "false" # Gitea OAuth WOODPECKER_GITEA: "true" WOODPECKER_GITEA_URL: "https://git.sendico.io" WOODPECKER_GITEA_CLIENT_FILE: "/vault/secrets/gitea_client_id" WOODPECKER_GITEA_SECRET_FILE: "/vault/secrets/gitea_client_secret" # Shared secret between server and agent WOODPECKER_AGENT_SECRET_FILE: "/vault/secrets/agent_secret" # Postgres DSN from Vault Agent rendered file WOODPECKER_DATABASE_DRIVER: "postgres" WOODPECKER_DATABASE_DATASOURCE_FILE: "/vault/secrets/pg_dsn" deploy: labels: traefik.enable: "true" traefik.docker.network: "cicd" traefik.http.routers.woodpecker-server.rule: "Host(`ci.sendico.io`)" traefik.http.routers.woodpecker-server.entrypoints: "websecure" traefik.http.routers.woodpecker-server.tls: "true" traefik.http.routers.woodpecker-server.tls.certresolver: "letsencrypt" traefik.http.routers.woodpecker-server.service: "woodpecker-server" traefik.http.services.woodpecker-server.loadbalancer.server.port: "8000" traefik.http.routers.woodpecker-grpc.rule: "Host(`woodpecker-grpc.sendico.io`)" traefik.http.routers.woodpecker-grpc.entrypoints: "websecure" traefik.http.routers.woodpecker-grpc.tls: "true" traefik.http.routers.woodpecker-grpc.tls.certresolver: "letsencrypt" traefik.http.routers.woodpecker-grpc.service: "woodpecker-grpc" traefik.http.services.woodpecker-grpc.loadbalancer.server.port: "9000" traefik.http.services.woodpecker-grpc.loadbalancer.server.scheme: "h2c" healthcheck: test: ["CMD", "/bin/woodpecker-server", "ping"] interval: 10s timeout: 3s retries: 10 start_period: 20s # Woodpecker Agent (creates step containers) woodpecker-agent: user: "0:0" # ensures read access to tmpfs secrets (mode 0750) image: woodpeckerci/woodpecker-agent:v3-alpine networks: [cicd] depends_on: [woodpecker-server, vault-agent-woodpecker] volumes: - /var/run/docker.sock:/var/run/docker.sock - vault_secrets:/vault/secrets:ro environment: # gRPC connection to server (overlay DNS) WOODPECKER_SERVER: "woodpecker-server:9000" # Shared secret file WOODPECKER_AGENT_SECRET_FILE: "/vault/secrets/agent_secret" # Docker backend for steps WOODPECKER_BACKEND: "docker" # Attach all step containers to a stable bridge network (created outside the stack) WOODPECKER_BACKEND_DOCKER_NETWORK: "wp-ci" # Concurrency limit WOODPECKER_MAX_WORKFLOWS: "2" healthcheck: test: ["CMD", "/bin/woodpecker-agent", "ping"] interval: 10s timeout: 3s retries: 10 start_period: 20s