Pular para conteúdo

0022 — Self-deploy do central pelo próprio /api/ci/deploy

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-08-31 · Decidido em: 2026-08-31

Contexto

A 0021 (adoção do control-plane, ADR central 0026) fechou o deploy da frota pelo POST /api/ci/deploy, mas recusava o deploy do próprio central (self_deploy_refused, 409) — a "exceção de bootstrap": o central deployaria a si mesmo direto na API do Coolify a partir do seu build-deploy.yml, sem passar pelo endpoint, "pra não depender de si mesmo no ar".

Ao migrar o central pra CI 100% GitHub (ADR central 0027, pipeline.yml), essa exceção não se sustenta: a API /api/v1 do Coolify é restrita ao IP da casa, e o runner do GitHub tem IP arbitrário → o build-deploy.yml não alcança a API direta; a ponte SSH que contornava isso foi removida (0026). A cláusula "deploya direto na API" ficou inexequível.

Decisão

O central se deploya pelo próprio /api/ci/deploy, como qualquer app da frota. A guarda self_deploy_refused é removida.

  • O job deploy do pipeline.yml do central faz POST /api/ci/deploy {target, image} ao próprio central (image = fonte.xadm.biz/xadm/central-backend:<target>-amd64, a âncora de resolução — 0021), byte-idêntico ao job da frota.
  • O central-atual (no ar, dentro da casa) recebe o POST, resolve o próprio recurso Coolify (a linha entra no app_deploy_targets pelo reconcile on-boot — o DeployReconcileService não tem self-skip) e chama a API do Coolify localmente (IP da casa — sem o bloqueio do runner). O Coolify faz rolling deploy health-gated: a imagem nova sobe, passa no health → substitui; falha → a anterior segue no ar.
  • Não há auto-referência travante: o central-atual está no ar no disparo, e a chamada ao Coolify enfileira e retorna antes do swap do container. O image é a âncora (0021), app_id não resolve.

Alternativas descartadas

  • Manter "deploya direto na API do Coolify" (0021/0026) — inexequível do runner GitHub (API IP-restrita), e a ponte SSH que a viabilizava foi removida.
  • Webhook de deploy do Coolify por-alvo (secret no repo) — resolve o IP, mas adiciona um mecanismo e secrets novos onde o /api/ci/deploy já existe e alcança o Coolify de dentro da casa. Preterido — mais superfície por zero ganho.
  • Coolify auto-pull no push — menos controle do momento, sem auditoria; fica como reserva.

Consequências

  • Reverte a guarda self_deploy_refused do DeployService (o central.self.slug some — era usado só nela). O caso de teste do 409 vira "self-deploy resolve e enfileira".
  • Break-glass: o central fora do ar não se autodeploya (não há quem receba o POST) → deploy manual pela UI/API do Coolify (de dentro da casa). É cenário de incidente, no runbook — o caminho normal (central-atual no ar) cobre todo release.
  • Emenda à 0021 (a §Decisão "guarda bootstrap" e a §Consequências "self-deploy 409" ficam corrigidas in-place apontando pra cá) e handoff feedback à ADR central 0026 (que ainda diz "sem auto-referência" / "API direta" — as duas quebradas; a casa deve inverter: self-deploy pelo /api/ci/deploy + break-glass).
  • Sem migration nova, sem novo endpoint — só a remoção da guarda + o job deploy do pipeline.yml.