Referencia .deploy.yml
O .deploy.yml e o arquivo de configuracao central que define como sua aplicacao sera deployada.
Modos de Deploy (v1.2.3+)
O Runner opera em dois modos exclusivos, determinados pela presenca de image: ou build::
Tem image: ? -> MODO IMAGE (sem build, monta source via volume)
Tem build: ? -> MODO BUILD (docker build com Dockerfile do repo)
Ambos? -> Erro
Nenhum? -> ErroModo IMAGE
Usa uma imagem pre-construida do registry. O Runner monta o codigo fonte via volume.
project: meu-site
image: caddy:2-alpine
port: 80- NAO faz build
- Monta source:
src/{instance}/current:/app:ro - Auto-mount de
data/,logs/,keys/ - Health check:
curl/wget
Modo BUILD
Faz docker build usando o Dockerfile que esta no repositorio.
project: meu-app
build:
dockerfile: Dockerfile
context: .
port: 80- Faz
docker buildcom o Dockerfile do repo - Codigo embedded na imagem (COPY no Dockerfile)
- Auto-mount de
data/,logs/,keys/(NAO monta source) - Health check:
bash /dev/tcp
Tabela Comparativa
| Modo IMAGE | Modo BUILD | |
|---|---|---|
| Config | image: xxx |
build: |
| Build? | NAO | SIM (docker build) |
| Codigo | Volume mount (:ro) |
Embedded na imagem |
| Dockerfile no repo | Nao precisa | OBRIGATORIO |
| Source mount | src/inst/current:/app:ro |
Nenhum |
| Persistent volumes | data/, logs/, keys/ |
data/, logs/, keys/ |
| Health check | curl/wget |
bash /dev/tcp |
Retrocompatibilidade
Campos legacy usados em manifestos v1 (relacionados ao modo de deploy ou ao
"tipo" da app) ainda sao aceitos pelo parser apenas para nao quebrar manifestos
antigos — emitem warning e nao influenciam o modo escolhido. O modo deriva
exclusivamente da presenca de image: (modo IMAGE) ou da presenca de build:
(modo BUILD).
Para a tabela completa de campos deprecados e seus substitutos canonicos
(incluindo o alias dockerfile em image_mode, o campo app_type e o
type: de topo), consulte Recursos Deprecados.
Sintaxe inline em `environment` / `secrets` / `build_args`
Valores em environment:, secrets: e build.args: aceitam uma micro-sintaxe
processada pelo modulo env_wizard do runner deploy. O wizard resolve
cada placeholder na primeira execucao, persiste o valor final em
.env/.secrets, e a partir dai o valor fica literal — sem reprocessamento
em deploys subsequentes.
| Sintaxe | Significado | Resolvido por |
|---|---|---|
valor literal |
Valor hardcoded, copiado tal qual | parse direto |
"{{::Label}}" |
Pergunta no terminal na 1a execucao | runner deploy (env_wizard) |
"{{::Label?default}}" |
Pergunta com default se a resposta vier vazia | runner deploy (env_wizard) |
"{RANDOM}" |
Gera 32 chars [A-Za-z0-9] uma vez |
runner deploy (env_wizard) |
"{GENERATE:hex:N}" |
Gera N chars hexadecimais uma vez | runner deploy (env_wizard) |
${ENV_VAR} |
Variavel compose-spec resolvida em multiplas fontes (v2.26.9+) | runner deploy em build.args, e runner wizard em environment: |
Importante: essa sintaxe e processada somente pelo
runner deploy(modulo env_wizard) na primeira execucao. Edicao direta do.deploy.ymlfora do wizard exige rodarrunner deploypara reprocessar — caso contrario, o valor fica literal no.enve o placeholder nunca e expandido.
`${VAR}` em `build.args` — v2.26.9+ semantics
build.args tem ciclo de vida diferente de environment:/secrets: porque
sao consumidos em build time (docker build) e nao em runtime. v2.26.9 + v2.26.10
trazem 2 camadas pra cobrir todos os fluxos de origem do valor:
1. Wizard-time bake-in (runner wizard --from-compose):
Quando o shell env tem a variavel setada, o wizard substitui no manifest:
export VITE_SUPABASE_URL=https://x.supabase.co
runner wizard --from-compose --path .
# manifest gerado: args: { VITE_SUPABASE_URL: "https://x.supabase.co" }Se o shell env nao tem a variavel, o wizard preserva o literal ${VAR} no manifest (v2.26.10+) — antes virava string vazia, causando silent miscompile em bundles Vite/Next/CRA.
2. Deploy-time runtime expansion (runner deploy):
No momento do docker build, o runner re-processa cada valor de build.args resolvendo ${VAR} contra (em ordem de precedencia):
.secretsdo app (runner secrets set).envdo app (runner env set)- Shell env de quem rodou o
runner deploy
Isso permite o fluxo post-wizard: gerar manifest, registrar app, setar valores via runner env set, e ter os valores no build sem precisar re-rodar wizard:
# Apos wizard, manifest tem `args: { VITE_SUPABASE_URL: "${VITE_SUPABASE_URL}" }` (literal)
runner env set <app> --key VITE_SUPABASE_URL --value "https://x.supabase.co"
runner deploy <app> --force # --force pra invalidar docker layer cache
# docker build --build-arg VITE_SUPABASE_URL=https://x.supabase.co ✓Precedencia completa em build.args:
{{::Var}}(runner-specific syntax) — resolve via.env/.secrets/prompts.${VAR}(compose-spec) — resolve via.secrets > .env > shell env.- Literal — passthrough.
Exemplo:
environment:
FLASK_ENV: production # literal
BASE_DOMAIN: "{{::Domain?app.example.com}}" # prompt com default
REGION: "${AWS_REGION}" # do shell
secrets:
DB_PASSWORD: "{RANDOM}" # gerada uma vez
JWT_SECRET: "{GENERATE:hex:64}" # 64 chars hex
SMTP_PASSWORD: "{{::SMTP password}}" # promptEstrutura Completa
# ============================================
# IDENTIFICACAO
# ============================================
project: meu-projeto # Nome do projeto (obrigatorio)
system: front # Descritor livre (front, sys, api, worker, scanner, ...) — cosmetico desde v2
# ============================================
# MODO DE DEPLOY (escolher um)
# ============================================
# Opcao A: Modo IMAGE (imagem pronta)
image: registry.local/base-sys:1.0
# Opcao B: Modo BUILD (Dockerfile do repo)
build:
dockerfile: Dockerfile # Default: "Dockerfile"
context: . # Default: "."
port: 8000 # Porta interna
# ============================================
# PORTAS (v2.0.1 — deploy sem Traefik)
# ============================================
ports:
- "80:80" # host:container
- "10.108.0.4:80:80" # ip:host:container (bind na VPC)
# ============================================
# CONFIG TEMPLATES (v2.0.0 — Helm-style)
# ============================================
config_templates:
values_dir: config # Default: "config"
templates_dir: templates # Default: "templates"
# ============================================
# REDES E VOLUMES
# ============================================
networks:
- public # Network do Traefik (obrigatoria)
- mysql # Se usar MySQL
- redis # Se usar Redis
volumes:
- logs:/app/logs:rw # Formato: nome:mount:mode
- certs:/app/certs:ro
# ============================================
# VARIAVEIS DE AMBIENTE
# ============================================
environment:
PYTHONPATH: /app/src
FLASK_ENV: production
DEBUG: "false"
LOG_LEVEL: info
# ============================================
# HEALTH CHECK (tres modos mutuamente exclusivos)
# ============================================
# Prioridade: cmd > tcp > path
#
# Modo HTTP (default) — GET no path indicado
healthcheck:
path: /health # Endpoint HTTP
interval: 10s
timeout: 5s
retries: 3
#
# Modo TCP — sondagem de porta (servicos nao-HTTP)
# healthcheck:
# tcp: 25 # Considera healthy se a porta aceita conexao
#
# Modo CMD — exec dentro do container (use o binario que voce ja tem)
# healthcheck:
# cmd: ["/app/bin/healthcheck", "--strict"]
#
# Modo EXIT — CLI tools/scanners (sem container permanente)
# healthcheck:
# mode: exit
#
# Importante: se o seu Dockerfile ja declara HEALTHCHECK, o runner respeita
# essa declaracao e nao injeta nada por cima.
# ============================================
# GITHUB (DEPRECATED na v2.16.0+)
# ============================================
# A partir da v2.16.0, repo/branch vivem no state file (manifesto do runner)
# em /opt/runner/state/{app}.yml. O `runner add --repo X --branch Y` salva
# direto no state — nao precisa do `github:` no .deploy.yml.
#
# Migration silenciosa: apps existentes com `github:` no .deploy.yml tem o
# valor copiado pro state na primeira execucao, com warning de deprecated.
# A leitura compat continua funcionando, mas o campo sera removido em uma
# major futura.
#
# github:
# repo: usuario/meu-repo # DEPRECATED — agora vem de runner add --repo
# user: usuario # DEPRECATED
# ============================================
# VERSAO
# ============================================
version:
source: file # file | git-tag | git-commit
file: package.json # Arquivo que contem a versao
field: version # Campo dentro do arquivo
# ============================================
# DEPENDENCIAS ENTRE APPS (opcional)
# ============================================
# Lista de outros projetos registrados que devem estar deployados (e
# saudaveis) antes deste. Consumido pelo `runner deploy --all` para
# topologicamente ordenar a sequencia. Cycles sao detectados e abortam
# o deploy. Deps que apontam para projetos nao registrados localmente
# emitem warning mas nao bloqueiam.
depends_on:
- inboxer-mta # MTA precisa estar healthy antes do SYS subir
- inboxer-redis
# ============================================
# ENV SYNC (v2.23.18 — controle de soberania)
# ============================================
# Controla se .env/.secrets sao regenerados a partir do secrets.enc
# remoto quando o hash muda durante deploy.
#
# remote (default): remoto soberano — hash diferente = regenera .env/.secrets
# skip: local soberano — nunca sobrescreve .env/.secrets por mudanca remota
env_sync: remote
# ============================================
# INSTANCIAS
# ============================================
instances:
production:
domain: app.projeto.com.br
source:
type: dist # Usa branch dist
keep_versions: 3 # Manter ultimas 3 versoes
canary: # Configuracao de canary (v1.2.0)
enabled: true
auto_promote:
enabled: true
initial_weight: 10
increment: 10
interval: 5m
final_weight: 100
staging:
domain: staging.projeto.com.br
source:
type: branch
branch: develop # Usa branch develop
keep_versions: 2
release:
domain: release.projeto.com.br
source:
type: tag # Usa tags Git (v1.2.0)
tag_pattern: "v*" # Padrao glob para filtrar tags
hotfix:
source:
type: local # Usa diretorio local (v1.2.0)
path: /builds/hotfix/
canary:
source:
type: image # Usa imagem Docker pronta (v1.2.0)
image: ghcr.io/org/app:canary
pr:
domain_pattern: "pr-${PR_NUMBER}.staging.projeto.com.br"
source:
type: pr # Usa refs/pull/N/head
ephemeral: true # Instancia temporaria
ttl_hours: 48 # Auto-destruicao apos 48h
mcp:
domain: app.projeto.com.br
path_prefix: /mcp # Co-hospeda em app.projeto.com.br/mcp (v2.22.0+)
source:
type: dist
keep_versions: 3
# ============================================
# STAGING (configuracao global)
# ============================================
staging:
enabled: true
domain_template: "pr-${PR_NUMBER}.staging.${DOMAIN}"
container_template: "staging_${PROJECT}_pr${PR_NUMBER}"
max_instances: 3
ttl_hours: 48
# ============================================
# NOTIFICACOES
# ============================================
notify:
channels:
- integration: telegram # Referencia config.yml
chat_id: "-123456789"
events:
- deploy_started
- deploy_success
- deploy_failure
- integration: flare
events:
- deploy_success
# ============================================
# ROUTING MODE (obrigatorio para canary)
# ============================================
routing_mode: traefik_dynamic # traefik_dynamic | traefik_labels | noneCampos Detalhados
Identificacao
| Campo | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
project |
string | Sim | Nome do projeto. Usado no container name, Traefik config, labels e diretorio |
system |
string | Nao | Identificador do subtipo (front, sys, api, worker). Usado como label de display e no atalho CLI runner deploy project/system |
type |
string | Nao | DEPRECATED — cosmetico; o modo agora deriva da presenca de build: ou image:. Mantido para compatibilidade com manifestos antigos. |
O campo system e cosmético — nao afeta build, routing ou container name. Serve para:
- Atalho CLI:
runner deploy sweepapex/front(resolveproject=sweepapex+system=front) - Display nos logs:
sweepapex/front deployed - Organizacao quando um projeto tem multiplos repos (front, sys, worker)
Modo de Deploy
| Campo | Tipo | Default | Descricao |
|---|---|---|---|
image |
string | - | Imagem Docker (define modo IMAGE) |
build |
object | - | Config de build (define modo BUILD) |
build.dockerfile |
string | Dockerfile |
Caminho do Dockerfile |
build.context |
string | . |
Contexto de build |
build.args |
map | {} |
Build args injetados como --build-arg KEY=VAL. v2.20.0+; v2.21.0+ suporta interpolação {{::Var}} resolvida de .env/.secrets |
port |
integer | - | Porta interna do container |
image_mode |
string | bind-mount |
Deprecated — prefira image: ou build:. Aceita bind-mount, self-contained, e o alias dockerfile (que vira self-contained com warning de depreciacao). |
Regra: image e build sao mutuamente exclusivos. Usar apenas um.
Build Args (v2.20.0+)
build.args permite injetar variáveis em build time via --build-arg. Em v2.21.0+, valores suportam interpolação {{::Var}} resolvida de .env e .secrets da app.
build:
context: .
dockerfile: Dockerfile
args:
BUILD_ENV: production # literal
VITE_API_URL: "{{::API_URL}}" # interpola de .env/.secrets (v2.21.0+)
VITE_DEFAULT_DOMAIN: "{{::DOMAIN?app.example.com}}" # com defaultOrder de resolução: .secrets primeiro (mais específico), .env fallback. Suporta {{::Key?default}}. Se a var não resolve, erro instrutivo aponta pra runner env set.
Ports (v2.0.1)
Mapeamento de portas do host para o container. Usado em deploys sem Traefik (servidores backend acessiveis via proxy externo pela VPC).
ports:
- "80:80" # Todas as interfaces
- "10.108.0.4:80:80" # Bind no IP da VPC (recomendado)
- "127.0.0.1:8080:80" # Bind no localhost| Formato | Exemplo | Resultado |
|---|---|---|
host:container |
"80:80" |
Todas as interfaces |
ip:host:container |
"10.108.0.4:80:80" |
Bind no IP especifico |
Quando ports esta configurado e a instancia nao tem domain, o runner:
- Pula a geracao de Traefik config
- Para o container antigo antes de iniciar o novo (stop-then-start, ~5s downtime)
- Mapeia
-pnodocker run
Config Templates (v2.0.0)
Configuracao opcional para renderizacao de config files Helm-style via Tera.
config_templates:
values_dir: config # Default: "config"
templates_dir: templates # Default: "templates"Quando presente e o repo tem templates/*.tpl, o runner renderiza templates automaticamente durante o deploy (Phase 1.3). Ver `runner config` para gerenciar valores.
Networks
Lista de redes Docker para conectar o container.
networks:
- public # Obrigatoria para Traefik
- mysql # Se usar MySQL
- redis # Se usar Redis
- mongo # Se usar MongoDBProject-scoping de networks user-defined (v2.26.3+) — quando runner wizard --from-compose gera multiplos manifests do mesmo project_prefix, networks user-defined (que nao sao reserved/shared) ganham prefixo automaticamente:
| Compose | Manifest gerado | Por que |
|---|---|---|
networks: [meet] (project_prefix=meet) |
networks: [meet_meet] |
App-local, compartilhada entre apps do mesmo prefix |
networks: [mysql] |
networks: [mysql] |
Shared infra, mesma network entre projetos diferentes |
networks: [public] |
networks: [public] |
Reservada (Traefik) |
Network reservadas (passam unchanged): public, bridge, host, none, default.
Network compartilhadas pre-instaladas (passam unchanged): mysql, redis, postgres, postgresql, mongo, mongodb, elasticsearch, clickhouse, rabbitmq, kafka, nats.
Wizard tambem popula network_aliases: com o service-name original em cada network project-scoped. Resultado: sibling apps resolvem-se por nome curto (livekit:7880), igual docker compose.
Hosts (v2.20.0+)
DNS aliases injetados como --add-host KEY:VAL no docker run. Map (não array) — last-wins em duplicatas.
hosts:
host.docker.internal: host-gateway # resolve em Linux Docker
internal-api: 10.0.0.5
cache-server: 10.0.0.10Útil pra:
host.docker.internalem Linux Docker (não funciona por default sem--add-host=host.docker.internal:host-gateway)- Aliases pra serviços internos sem depender de DNS externo
- Override temporário de hosts pra debug
Volumes
Lista de volumes no formato host:container:mode (bind) ou nome:mount:mode (named).
volumes:
- logs:/app/logs:rw
- certs:/app/certs:ro
- data:/app/data:rw
- ./livekit.prod.yaml:/etc/livekit.yaml:ro # bind relativoResolucao de path relativo (v2.26.2+) — paths relativos como ./X agora seguem semantica docker-compose:
| Cenario | Resolve para |
|---|---|
Arquivo X existe em src/<instance>/<version>/X (vindo do repo) |
src/<instance>/<version>/X |
| Caso contrario | <app_dir>/X (state runtime: ./data, ./logs, etc.) |
Pre-v2.26.2, todos os relatives bateram em <app_dir>/X o que quebrou config-file binds (livekit.prod.yaml, nginx.conf, etc.) — o arquivo nunca existia ali.
Source Dir
source_dir: . # default explicito = repo root (v2.26.2+)
source_dir: dist # subdir do repo (build output, etc.)
source_dir: auto # heuristica antiga (tenta dist/build/out/public/guides/content/docs)Default (v2.26.2+) — quando source_dir esta ausente ou e null, o runner usa pull/ inteiro como source. Matches docker-compose (relative paths in volumes: resolvem ao dir do compose file).
source_dir: auto — opt-in pra heuristica antiga. Util para projetos front-static cujo build vai pra dist/ ou similar e o operador prefere nao declarar explicitamente.
Pre-v2.26.2, image-mode apps com source_dir: null rodavam auto-detect automaticamente e podiam escolher subdir errado (e.g. docs/ em repo com markdown na pasta).
Environment
HashMap de variaveis de ambiente. Suporta valores fixos, gerados e prompts interativos (Env Wizard).
environment:
FLASK_ENV: production # valor fixo
BASE_DOMAIN: "{{::Domain?projeto.com.br}}" # prompt com default
DB_NAME: "{{::Database name}}" # prompt sem defaultPrecedencia (v2.26.3+) — chaves presentes em .env ou .secrets (estado local do operador) sobrescrevem environment: do manifest. Manifest vale como default; operador override em prod ganha. Use runner env set <app> <KEY> <VALUE> pra setar overrides sem editar/commitar o .deploy.yml.
Pre-v2.26.3, manifest sempre ganhava — runner env set era no-op para qualquer chave declarada no manifest.
Secrets
HashMap de variaveis sensiveis. Escritas em .secrets (permissao 600) em vez de .env.
secrets:
DB_PASSWORD: "{RANDOM}" # gera automaticamente
JWT_SECRET: "${GENERATE:hex:64}" # hex 64 chars
SMTP_PASSWORD: "{{::SMTP Password}}" # prompt ao operadorConsulte o guia completo de classificação automática de env/secrets para sintaxe detalhada e exemplos.
Env Sync (v2.23.18)
Controla se .env/.secrets sao regenerados a partir do secrets.enc remoto quando o hash muda.
env_sync: remote # default — remoto soberano
env_sync: skip # local soberano| Campo | Tipo | Default | Descricao |
|---|---|---|---|
env_sync |
string | remote |
remote: regenera .env/.secrets se secrets.enc remoto mudou. skip: nunca sobrescreve locais. |
Quando omitido, herda o valor de env_sync_default do config.yml global.
Resources (v2.24.0)
Limites de recursos via flags do docker run. Todos os campos opcionais — ausente = sem flag, comportamento idêntico a versões anteriores.
resources:
memory: 512m # --memory
memory_swap: 1g # --memory-swap
memory_reservation: 256m # --memory-reservation (soft limit)
cpus: "1.5" # --cpus
cpu_shares: 1024 # --cpu-shares (peso relativo)
cpuset: "0-1" # --cpuset-cpus (pinning)
pids_limit: 100 # --pids-limit (anti fork-bomb)
shm_size: 64m # --shm-size (default 64m; chrome/puppeteer geralmente precisa 256m+)
ulimits:
nofile: 65536 # --ulimit nofile=65536
nproc: 4096 # --ulimit nproc=4096Security (v2.24.0)
Hardening via flags do docker run. Defaults preservam comportamento atual.
security:
user: "1000:1000" # --user UID[:GID]. Recomenda nao-root.
read_only: true # --read-only (root FS imutavel; combine com tmpfs)
no_new_privileges: true # --security-opt no-new-privileges:true
cap_add: [NET_ADMIN] # --cap-add (Linux capabilities)
cap_drop: [ALL] # --cap-drop
security_opts: # --security-opt (raw)
- "seccomp=unconfined"
- "apparmor=docker-default"Logging (v2.24.0)
Driver de log e opções (rotação, etc).
logging:
driver: json-file # --log-driver (json-file | journald | syslog | local | none)
options: # --log-opt key=value (em ordem alfabetica)
max-size: 10m
max-file: "3"Recomenda-se max-size: 10m, max-file: 3 em produção pra prevenir explosão de disco.
Lifecycle (v2.24.0)
Controle de inicialização, entrypoint, comando e shutdown.
init: false # --init (default false). PID 1 = tini para reap de zombies.
entrypoint: ["/app/start", "--config", "/etc/app.yml"] # --entrypoint + args após image
command: ["--bind", "0.0.0.0", "--port", "8080"] # CMD (args após entrypoint). v2.26.3+
stop_signal: SIGTERM # --stop-signal (default SIGTERM)
stop_grace_period: 30s # --stop-timeout em segundos antes de SIGKILL
pull_policy: missing # --pull (always | missing | never). Ausente = daemon default.command: (v2.26.3+) — override do CMD da imagem. Aceita array ou shell-string (splittada em whitespace). Quando ambos entrypoint: e command: estao setados, o runner monta a chamada como docker run --entrypoint <EP> IMAGE <CMD...>. Wizard --from-compose traduz compose.services.X.command automaticamente. Paths com espaco exigem array form (sem suporte a quoted segments na string form).
# Array form (preferido pra paths com espaco)
command:
- --config
- /etc/livekit.yaml
- --bind
- 0.0.0.0
# Shell form (split por whitespace)
command: --config /etc/livekit.yaml --bind 0.0.0.0Network avançado (v2.24.0)
hostname: app-prod-1 # --hostname interno do container
dns: ["1.1.1.1", "8.8.8.8"] # --dns servidores customizados
expose: [8080, 9090] # --expose (portas internas sem publish)
network_aliases:
public: [app-prod, legacy] # --network-alias (advisory em multi-network)Storage / Hardware (v2.24.0)
tmpfs: ["/tmp:size=64m", "/run"] # --tmpfs (otimo com read_only: true)
devices: ["/dev/snd", "/dev/dri"] # --device (passthrough de dispositivos)
gpus: "all" # --gpus (requer nvidia-container-toolkit)
platform: "linux/arm64" # --platform (cross-arch testing)Health Check
O healthcheck opera em 3 camadas (cascata de decisao):
- Layer 1: HEALTHCHECK no Dockerfile (sempre vence)
- Layer 2:
modeavancado (v2.27.0+) — runner faz probe de fora - Layer 3:
path/tcp/cmd— probe dentro do container
| Campo | Tipo | Default | Descricao |
|---|---|---|---|
path |
string | /health |
Modo HTTP (Layer 3): endpoint testado via curl/wget (image mode) ou bash /dev/tcp (build mode). Deve comecar com /. |
tcp |
integer | - | Modo TCP (Layer 3): porta interna para sondagem. Use para servicos nao-HTTP (SMTP, Redis, ...). |
cmd |
array of strings | - | Modo CMD (Layer 3): comando exec rodado dentro do container. Use quando a imagem ja tem um binario de healthcheck. Ex: cmd: ["/app/bin/check", "--strict"]. |
mode |
string | - | Estrategia avancada (Layer 2). Valores: exit, external_http, external_tcp, container_state, skip_check. Ver tabela abaixo. |
stable_seconds |
integer | 10 |
Usado com mode: container_state. Janela de estabilidade (container deve ficar Running sem OOM). |
start_period |
string | 30s |
Grace period antes do Docker/runner comecar a rodar checks. Aumente para containers lentos (multi-stage builds, JVMs). |
interval |
string | 10s |
Intervalo entre checks |
timeout |
string | 5s |
Timeout do check |
retries |
integer | 3 |
Tentativas antes de unhealthy (usado em Layer 3, ignorado em Layer 2) |
Modos Avancados (Layer 2) — v2.27.0+
| Modo | Descricao | Uso |
|---|---|---|
exit |
CLI tools que nao ficam rodando. fetch --deploy skipa, runner deploy valida com docker run --rm. |
Scanners, CLI tools |
external_http |
Runner faz HTTP GET ao http://<container_ip>:<port><path> do host. Funciona em qualquer imagem (scratch, distroless). |
Containers sem ferramentas internas |
external_tcp |
Runner faz TCP connect ao <container_ip>:<tcp> do host. Requer campo tcp: preenchido. |
Servicos sem HTTP (Redis, MySQL) |
container_state |
Runner observa docker inspect — container saudavel apos stable_seconds com Running==true, sem OOM, sem RestartCount incrementado. |
Apps que nao expõem nada inspecionavel |
skip_check |
Escape hatch: runner declara OK sem validacao. Emite evento HealthSkipped (Warning) no canal de notificacoes. |
Risco aceitavel explicitamente |
Heranca de HEALTHCHECK do Dockerfile: se a imagem base (ou a imagem buildada
pelo seu Dockerfile) ja declara um HEALTHCHECK, o runner respeita essa
declaracao e nao injeta nenhum --health-cmd por cima (Layer 1 sempre vence).
Isso permite que projetos com Dockerfile customizado tenham controle total da
estrategia de health. Use runner deploy -V para ver qual comando sera
efetivamente usado.
Depends On
Lista de projetos que devem ser deployados antes deste quando voce roda
runner deploy --all. Os nomes referem-se ao campo project: de outros apps
registrados localmente.
depends_on:
- inboxer-mta
- inboxer-redisComportamento:
- O runner faz topological sort e deploya na ordem correta.
- Cycles (
a -> b -> a) sao detectados e abortam o--allcom mensagem listando os projetos envolvidos. - Deps que apontam para projetos nao registrados localmente emitem warning e sao silenciosamente ignoradas — util quando o dep roda em outro servidor.
- Se uma dep falhar durante o
--all, seus dependentes sao automaticamente pulados (com log) ao inves de tentar deployar sem a base.
Version
| Campo | Tipo | Descricao |
|---|---|---|
source |
string | Fonte da versao |
file |
string | Arquivo com a versao |
field |
string | Campo no arquivo |
Valores de source:
file- Extrai de arquivo (package.json, version.json)git-tag- Usa tag Git mais recentegit-commit- Usa hash do commit
Instances
Cada instancia define um ambiente de deploy.
| Campo | Tipo | Descricao |
|---|---|---|
domain |
string | Dominio da instancia |
domain_pattern |
string | Padrao de dominio (para PRs) |
path_prefix |
string | URL prefix para co-hospedar no mesmo domain de outro app (v2.22.0+) |
source.type |
string | Tipo de fonte |
source.branch |
string | Nome da branch (se type=branch) |
source.tag_pattern |
string | Padrao de tags (se type=tag) |
source.path |
string | Caminho local (se type=local) |
source.image |
string | Imagem Docker (se type=image) |
keep_versions |
integer | Quantas versoes manter |
ephemeral |
boolean | Se e instancia temporaria |
ttl_hours |
integer | TTL em horas (para ephemeral) |
environment_overrides |
map | Variaveis de ambiente especificas desta instancia (sobrescreve environment) |
canary |
object | Configuracao de canary |
config |
object | Resolucao de secrets por instancia (v2.44.0+) — ver Config por Instancia |
Tipos de source (v1.2.0):
| Tipo | Descricao | Campos |
|---|---|---|
dist |
Branch dist (artifacts compilados) | - |
branch |
Branch especifica | branch |
pr |
Pull Request (refs/pull/N/head) | - |
tag |
Tag Git especifica | tag_pattern |
local |
Diretorio local | path |
image |
Imagem Docker pronta | image |
Path Prefix (v2.22.0+)
Permite co-hospedar dois apps no mesmo domain, cada um servindo um sub-caminho. Quando path_prefix: esta definido, o runner gera a regra Traefik:
Host(`{domain}`) && PathPrefix(`{path_prefix}`)com priority: 100 — vence o router catch-all do app vizinho que serve a raiz do mesmo host.
instances:
production:
domain: wizard.runnerci.com
path_prefix: /mcp
source:
type: dist
keep_versions: 3Caso de uso real: o frontend wizard serve wizard.runnerci.com/ e o servidor MCP wizard-mcp serve wizard.runnerci.com/mcp/* — ambos como containers separados sob o mesmo dominio.
Comportamento:
- Campo vazio ou omitido → regra Traefik fica apenas
Host()(comportamento legacy, sem priority) - Whitespace-only e tratado como ausente
- Todos os tres caminhos de geracao Traefik (single-version, canary, snippet externo) honram o prefix
Config por Instancia (v2.44.0+)
Opcional. So e necessario quando o bundle de secrets da instancia nao segue a convencao de nome, ou (fora de escopo nesta versao) para vault.
instances:
production:
domain: app.com.br
config:
source: bundle # default (zero-dependencia)
bundle: secrets.production.enc # opcional; omitido = convencao| Campo | Tipo | Default | Descricao |
|---|---|---|---|
source |
string | bundle |
Origem da resolucao de secrets desta instancia |
bundle |
string | convencao (secrets.<instancia>.enc) |
Path do arquivo .enc, se diferente da convencao |
Sem esse bloco, o runner resolve por convencao de nome — nao precisa declarar nada. A ordem completa de failover (bundle explicito → secrets.<instancia>.enc → secrets.enc legado) e detalhada em Secrets por Instancia.
source: vault existe no schema mas ainda retorna erro loud no deploy — resolucao via vault esta fora de escopo nesta versao. Use source: bundle.
Estruture os arquivos por-instancia com `runner set-ckey`.
Canary Config (v1.2.0)
Configuracao de canary deployment por instancia:
instances:
production:
canary:
enabled: true
auto_promote:
enabled: true
initial_weight: 10 # Peso inicial do canary
increment: 10 # Incremento por step
interval: 5m # Intervalo entre steps
final_weight: 100 # Peso final (promocao completa)
health_check_before: true
abort_on:
- health_check_failed
- error_rate_above:5%
- latency_p99_above:500msCampos de auto_promote:
| Campo | Tipo | Default | Descricao |
|---|---|---|---|
enabled |
boolean | false |
Habilitar promocao automatica |
initial_weight |
integer | 10 |
Peso inicial |
increment |
integer | 10 |
Incremento por step |
interval |
string | 5m |
Intervalo entre steps |
final_weight |
integer | 100 |
Peso final |
health_check_before |
boolean | true |
Verificar health antes de cada step |
Condicoes de abort:
health_check_failed- Health check falhouerror_rate_above:X%- Taxa de erro acima de X%latency_p99_above:Xms- Latencia p99 acima de X ms
Instance Depends_on (v2.21.0+)
Cross-app health checks por instance: app A só inicia depois que app B está pronto. Diferente do top-level depends_on: (que ordena runner deploy --all), o instances.<inst>.depends_on: é checado em cada start_container e bloqueia o spin-up até o dep estar healthy.
instances:
production:
domain: app.example.com
source: { type: branch, branch: main }
keep_versions: 3
depends_on:
- app: meu-livekit
condition: healthy # healthy | started
timeout: 300s # opcional, default 300s
- app: meu-redis
instance: production # opcional, default = mesma instance
condition: started| Campo | Tipo | Default | Descricao |
|---|---|---|---|
app |
string | - | Slug do app dependência (obrigatório) |
instance |
string | mesma instance | Instance específica do dep |
condition |
enum | healthy |
healthy (Health.Status=healthy) ou started (running) |
timeout |
string | "300s" |
Max wait — 300s / 5m / 1h |
Comportamento: runner polla docker inspect por cada dep até condition met OR timeout. Bypass via --insecure.
Erro de timeout:
ERROR dependency_timeout: meu-livekit/production not ready after 300s (condition=Healthy)Routing Mode
| Valor | Canary | Descricao |
|---|---|---|
traefik_dynamic |
Sim | Arquivos YAML dinamicos (obrigatorio para canary) |
traefik_labels |
Nao | Labels nos containers |
none |
Nao | Sem routing (workers) |
Importante: Se canary.enabled: true, routing_mode DEVE ser traefik_dynamic.
Staging
Configuracao global de staging.
| Campo | Tipo | Default | Descricao |
|---|---|---|---|
enabled |
boolean | false |
Habilitar staging |
domain_template |
string | - | Template de dominio |
container_template |
string | - | Template de container |
max_instances |
integer | 3 |
Max stagings por projeto |
ttl_hours |
integer | 48 |
TTL padrao |
Variaveis de template:
${PR_NUMBER}- Numero da PR${PROJECT}- Nome do projeto${BRANCH}- Nome da branch${DOMAIN}- Dominio base${INSTANCE}- Nome da instancia (v2.0.0)${DATETIME}- Timestamp (YYYYmmdd-HHMMSS)${HASH}- 6 caracteres de UUID${RANDOM}- 6 caracteres alfanumericos
Notify (v1.2.0)
Configuracao de notificacoes por aplicacao:
notify:
channels:
- integration: telegram # Referencia integrations do config.yml
chat_id: "-123456789" # Override per-app
events:
- deploy_started
- deploy_success
- deploy_failure
- integration: flare
events:
- deploy_success
- integration: slack
channel: "#deploys"
events: all # Todos os eventosEventos disponiveis:
deploy_starteddeploy_successdeploy_failurerollback_startedrollback_successcanary_weight_changedcanary_promotedinstance_destroyedhealth_check_failedall(todos os eventos)
Exemplos por Tipo
Frontend estatico — Modo IMAGE (Caddy)
project: meu-app
image: caddy:2-alpine
port: 80
networks:
- public
healthcheck:
path: /
interval: 30s
github:
repo: usuario/meu-app-front
version:
source: file
file: package.json
field: version
instances:
production:
domain: app.meusite.com.br
source:
type: dist
keep_versions: 3Backend Flask — Modo BUILD com Canary
project: meu-api
build:
dockerfile: Dockerfile
port: 8000
routing_mode: traefik_dynamic # Obrigatorio para canary
networks:
- public
- mysql
- redis
environment:
PYTHONPATH: /app/src
FLASK_ENV: production
healthcheck:
path: /health
interval: 10s
timeout: 5s
retries: 3
github:
repo: usuario/meu-api-sys
version:
source: file
file: version.json
field: version
instances:
production:
domain: sys.meusite.com.br
source:
type: dist
keep_versions: 3
canary:
enabled: true
auto_promote:
enabled: true
initial_weight: 10
increment: 10
interval: 5m
abort_on:
- health_check_failed
- error_rate_above:5%Documentacao — Modo IMAGE (PimDocs)
project: runner-docs
image: leonardoborlot/pimdocs:latest
port: 4321
networks:
- public
healthcheck:
path: /
interval: 30s
instances:
production:
domain: docs.runner.ccs.systems
source:
type: distApp PHP — Modo BUILD com multi-stage
project: meu-laravel
build:
dockerfile: docker/Dockerfile.prod
context: .
port: 80
networks:
- public
- mysql
volumes:
- storage:/app/storage:rw
healthcheck:
path: /health
instances:
production:
domain: app.meusite.com.br
source:
type: dist
keep_versions: 3Deploy de Tags (Releases)
project: meu-app
port: 8000
networks:
- public
instances:
release:
domain: app.meusite.com.br
source:
type: tag
tag_pattern: "v*" # v1.0.0, v1.1.0, etc
keep_versions: 5Deploy de Imagem Docker
project: meu-app
port: 8000
networks:
- public
instances:
canary:
domain: canary.meusite.com.br
source:
type: image
image: ghcr.io/usuario/meu-app:canaryDeploy Local (Hotfix)
project: meu-app
port: 8000
networks:
- public
instances:
hotfix:
domain: hotfix.meusite.com.br
source:
type: local
path: /builds/emergency/CLI Tool / Scanner — Modo Exit
project: meu-scanner
build:
dockerfile: Dockerfile
healthcheck:
mode: exit # Sem container permanente
github:
repo: usuario/meu-scanner
version:
source: git-commit
instances:
production:
source:
type: distCom Staging de PRs
project: meu-app
port: 8000
networks:
- public
instances:
production:
domain: app.meusite.com.br
source:
type: dist
keep_versions: 3
staging:
domain: staging.meusite.com.br
source:
type: branch
branch: develop
pr:
domain_pattern: "pr-${PR_NUMBER}.staging.meusite.com.br"
source:
type: pr
ephemeral: true
ttl_hours: 48
staging:
enabled: true
max_instances: 5
ttl_hours: 48Deploy sem Traefik — Port-only (v2.0.1)
Para servidores backend sem Traefik local, acessiveis via proxy externo pela VPC:
project: meu-backend
build:
dockerfile: Dockerfile
port: 80
ports:
- "10.108.0.5:80:80" # Bind na interface VPC
networks:
- mysql
environment:
DB_HOST: 10.108.0.3
REDIS_HOST: 10.108.0.3
healthcheck:
path: /health
interval: 30s
instances:
production:
# SEM domain → runner pula Traefik, usa apenas ports
source:
type: branch
branch: dev
keep_versions: 3Frontend Vite com `build.args` interpolados (v2.21.0+)
Frontends que precisam injetar variáveis em build time (Vite, Next.js, Angular). Os valores em build.args interpolam de .env/.secrets da app:
project: meu-frontend
build:
context: .
dockerfile: Dockerfile
args:
VITE_API_URL: "{{::API_URL}}"
VITE_PUBLIC_DOMAIN: "{{::DOMAIN?app.example.com}}"
BUILD_ENV: production
port: 80
networks:
- public
healthcheck:
mode: http
path: /
interval: 30s
instances:
production:
domain: app.example.com
source:
type: branch
branch: main
keep_versions: 3Valores das vars (API_URL, DOMAIN) são gerenciados via runner env set <app> --key API_URL --value ... (ou wizard inicial). Resolução: .secrets primeiro, .env fallback, default opcional via ?default.
Multi-app com `depends_on:` cross-app (v2.21.0+)
App agent que precisa esperar LiveKit + Redis ficarem prontos antes de subir. Cada dep é polled via docker inspect até condition (healthy/started) ou timeout:
# meu-agent/.deploy.yml (depende de meu-livekit + meu-redis)
project: meu-agent
build:
context: .
dockerfile: Dockerfile
port: 8000
networks:
- public
environment:
LIVEKIT_URL: "ws://meu-livekit-prod:7880"
REDIS_HOST: "meu-redis-prod"
instances:
production:
domain: agent.example.com
source: { type: branch, branch: main }
keep_versions: 3
depends_on:
- app: meu-livekit
condition: healthy
timeout: 300s
- app: meu-redis
condition: started
timeout: 60sSe meu-livekit ou meu-redis não atingir condition no timeout, o deploy falha com dependency_timeout: <app>/<instance> not ready after Ns. Bypass: --insecure.
Multi-Ambiente com Environment Overrides (v1.5.0)
project: meu-app
build:
dockerfile: Dockerfile
port: 8000
environment:
DB_HOST: mysql
LOG_LEVEL: info
instances:
production:
domain: app.meusite.com.br
source:
type: dist
environment_overrides:
DB_HOST: mysql-prod
DB_NAME: app_prod
staging:
domain: staging.meusite.com.br
source:
type: branch
branch: dev
environment_overrides:
DB_HOST: mysql-staging
DB_NAME: app_stagingExemplo Minimo
O menor .deploy.yml funcional:
# Modo IMAGE (imagem pronta)
project: meu-app
image: caddy:2-alpine
port: 80
instances:
production:
domain: app.meusite.com.br
source:
type: dist# Modo BUILD (com Dockerfile no repo)
project: meu-app
build:
dockerfile: Dockerfile
port: 80
instances:
production:
domain: app.meusite.com.br
source:
type: distValidacao
Valide seu arquivo com:
runner validate --file /caminho/.deploy.ymlGerando Template
Gere um template completo com:
runner generate-config > .deploy.yml