Multi-instance e roteamento de tráfego
O Runner permite que a mesma app rode em múltiplas instâncias independentes — cada uma com domínio próprio, estado próprio e distribuição de tráfego controlada. Esta página cobre o modelo de instâncias, os comandos de peso e o canary automático.
Pré-requisitos
- Runner v2.30.10+
- App registrada com pelo menos uma instância configurada no
.deploy.yml traefik.mode: local(default) noconfig.ymldo servidor — obrigatório para weighted routing/canary
O que é uma instância
Uma instância é um ambiente independente dentro da mesma app. Cada instância tem:
- Domínio próprio (ex:
app.exemplo.com.br,staging.exemplo.com.br) - Estado próprio (
/opt/runner/state/<app>.ymlseparado) - Histórico de versões independente
- O mesmo
.deploy.ymlcomo fonte de configuração
Exemplo de app com duas instâncias:
# .deploy.yml
instances:
production:
domain: app.exemplo.com.br
source:
type: dist
keep_versions: 3
staging:
domain: staging.exemplo.com.br
source:
type: branch
branch: dev
keep_versions: 2A instância production e a staging rodam de forma completamente independente. Um deploy em staging não afeta production.
Variáveis de ambiente por instância
Cada instância pode sobrescrever variáveis do bloco environment: global via
environment_overrides:. A prioridade, da mais fraca pra mais forte, é:
.env.template (base do repositório)
↓
environment: (global, no .deploy.yml)
↓
environment_overrides: (por instância — maior prioridade)# .deploy.yml
environment:
DB_HOST: mysql
LOG_LEVEL: info
instances:
production:
domain: app.exemplo.com.br
environment_overrides:
DB_HOST: mysql-prod
LOG_LEVEL: warn
staging:
domain: staging.exemplo.com.br
environment_overrides:
DB_HOST: mysql-staging
LOG_LEVEL: debugCada instância recebe seu próprio .env — production fica com DB_HOST=mysql-prod,
staging com DB_HOST=mysql-staging. Secrets seguem a mesma lógica de resolução, mas veja
Secrets por instância para o isolamento adicional de
ckey/bundle quando cada instância roda num servidor diferente.
Branch por instância
Cada instância pode acompanhar uma branch (ou tipo de source) diferente:
instances:
production:
source:
type: dist # consome artefatos compilados
staging:
source:
type: branch
branch: dev # acompanha a branch dev diretamenteRegistrando cada máquina numa instância
Numa topologia multi-ambiente (produção, staging, homolog em servidores separados), cada servidor registra a app apontando pra sua própria instância:
# Na máquina de produção
runner add --repo usuario/meu-app --branch main --instance production
# Na máquina de staging
runner add --repo usuario/meu-app --branch dev --instance stagingO cron runner fetch --deploy (igual em todas as máquinas) resolve qual instância
deployar seguindo esta ordem de prioridade:
state.instance(definido via--instancenoadd/edit)default_instance_name()do.deploy.yml(primeira instância declarada)"production"(fallback)
Pra trocar a instância de uma app já registrada:
runner edit meu-app --instance homologO comando valida que a instância existe no .deploy.yml antes de salvar.
Weight-based routing
Dentro de uma instância, o Runner pode distribuir tráfego entre duas versões ao mesmo tempo. Isso é feito via Traefik weighted services — sem reinicialização de containers.
Ver distribuição atual
runner weights <project> -i <instance>Exemplo:
runner weights meu-app -i productionSaída típica durante canary:
Distribuicao de trafego (production):
v1.0.0: 90%
v1.1.0-rc1: 10%Ajustar peso de uma versão
runner weight <project> <instance> <version> <pct>O parâmetro <pct> é um inteiro de 0 a 100. O Runner recalcula o peso da outra versão automaticamente.
# Aumentar canary para 50%
runner weight meu-app production v1.1.0-rc1 50
# Saída:
# Peso atualizado:
# v1.0.0: 50%
# v1.1.0-rc1: 50%Promover uma versão para 100%
runner promote <project> -i <instance> <version>O promote faz três ações em sequência:
- Define peso 100% para a versão especificada
- Remove as outras versões do roteamento
- Limpa containers antigos (respeitando
keep_versions)
runner promote meu-app -i production v1.1.0-rc1Depois do promote, runner weights mostra apenas uma versão com 100%.
Canary auto-promotion (v1.2.0+)
O canary automático faz a progressão de pesos sem intervenção manual. O scheduler avança a cada tick configurado, desde que o healthcheck passe.
Configurar no .deploy.yml
instances:
production:
domain: app.exemplo.com.br
canary:
enabled: true
auto_promote:
enabled: true
initial_weight: 10
increment: 10
interval: 5m
final_weight: 100
health_check_before: true
abort_on:
- health_check_failed
- error_rate_above:5%Ver status do scheduler
runner canary status meu-app -i productionSaída típica:
Canary Status: meu-app (production)
Stable: v1.0.0
Canary: v1.1.0-rc1
Weight: 30%
State: running
Next: +5m -> 40%
ETA: 35m para 100%Controlar a progressão
# Pausar no peso atual (sem rollback)
runner canary pause meu-app -i production
# Retomar de onde parou
runner canary resume meu-app -i production
# Abortar e voltar 100% para a versão estável
runner canary abort meu-app -i productionO abort zera o peso do canary, restaura 100% para a versão estável e envia notificação (se configurado).
Integrar com CI/CD via sinais
O Runner aceita sinais externos de pipelines de CI para pausar ou abortar um canary antes de avançar o próximo step.
# Testes falharam — abortar canary
runner signal send meu-app --status fail --message "3 testes de integracao falharam"
# Testes passaram — liberar progressão
runner signal send meu-app --status ok --message "smoke tests passaram"Ver runner signal para a referência completa de status e actions.
Padrão típico de canary manual
# 1. Verificar versão atual
runner versions meu-app -i production
# 2. Fazer deploy da nova versão (começa com 0% do tráfego)
runner deploy meu-app --version v1.1.0-rc1
# 3. Direcionar 10% do tráfego para o canary
runner weight meu-app production v1.1.0-rc1 10
# 4. Observar logs e métricas por ~15 minutos
runner logs tail meu-app
docker logs meu-app_production_v1.1.0-rc1 --tail 100
# 5. Se OK, aumentar para 50%
runner weight meu-app production v1.1.0-rc1 50
# 6. Aguardar mais ~30 minutos para produção crítica
# 7. Promover para 100% quando confiável
runner promote meu-app -i production v1.1.0-rc1O que pode dar errado
Canary com `traefik.mode: docker_labels`
Labels Traefik por container não suportam weighted routing (elas reagem a start/stop do
container, não a mudança de peso). Se o servidor estiver em traefik.mode: docker_labels
(usado quando Traefik roda com network_mode: host), runner weight/runner promote
continuam funcionando, mas sem distribuição gradual — o tráfego vai 100% pra última versão
iniciada.
Solução: usar traefik.mode: local (default) no config.yml do servidor onde o canary
roda.
Promote antes de validar
Usar promote muito cedo leva o tráfego completo para uma versão não validada. Não há desfazer automático — é necessário um novo deploy da versão anterior.
Prática recomendada: esperar pelo menos 15 minutos em 10% e 30 minutos em 50% antes de promover em produção crítica.
Canary em mudança de schema de banco
Canary não é adequado quando a nova versão exige schema diferente do banco. As duas versões compartilham o mesmo banco — se a nova migrou a tabela, a versão antiga quebra ao receber tráfego.
Alternativa: migração em dois passos — primeiro adicione a coluna como nullable (retrocompatível), depois faça o canary, depois remova o campo antigo.
Canary em breaking change de API
Se a nova versão muda contratos de API de forma incompatível, 10% dos usuários recebem a API nova enquanto 90% recebem a antiga. Isso quebra clientes que fazem múltiplas requests na mesma sessão.
Alternativa: versionamento de API (/v1/ e /v2/) ou instância staging separada para validação.
Links relacionados
- Gerenciamento de instâncias — referência completa de
runner instances,versions,weights,weight,promote - runner signal — gate canary com sinais de CI/CD
- Rollback — recuperar após promoção incorreta (em breve)