fix(deploy): compose referencia a tag qualificada do registry; F2 preserva por image ID (INF13)
O compose do stack referenciava a tag local bare teqo-1313:<sha>, que é uma segunda ref que nada recria se perdida (achado INF8 24/08: só restava a ref do registry e o 'compose up -d' falhou com No such image). Agora: - swap escreve sempre localhost:5000/teqo-1313(-migrator):<sha> (sed idempotente aceita ambas as formas); os docker tag bare somem (sem consumidor); - rollback do runbook simplifica (docker pull basta, sem dance de tag); - limpeza pós-deploy (INF3/F2) preserva TODAS as tags da imagem em uso pelo IMAGE ID do container, imune a drift de label do compose. Runbook docs/ops/teqo-1313-deploy.md atualizado (fluxo, rollback, tabela de falhas com o achado). Issue de referência (tracker infra-solla): git.solla.dev/fsolla/infra-solla#24
This commit is contained in:
parent
ae79eb507c
commit
ddd58a01d1
2 changed files with 45 additions and 35 deletions
|
|
@ -22,15 +22,17 @@ homeserver, o job `verify` (hosted) roda a suíte **full** (incl. e2e full).
|
|||
== SHA do job, senão "stale run" skip) → `flock` (serializa) → guard
|
||||
"already deployed" (revision do container rodando) → **build do migrator**
|
||||
(o estágio migrator não roda `next build` — builda mesmo contra o schema
|
||||
antigo; BuildKit, secrets do `~/stack/teqo-1313.env`) → push/tag do
|
||||
migrator em `localhost:5000` → swap dos tags de imagem no
|
||||
`~/stack/docker-compose.yml` (backup antes) → **migrations**
|
||||
antigo; BuildKit, secrets do `~/stack/teqo-1313.env`) → push do migrator em
|
||||
`localhost:5000` (tag **qualificada de registry** — INF13: a única ref que o
|
||||
compose referencia) → swap dos tags de imagem no
|
||||
`~/stack/docker-compose.yml` (backup antes; sed idempotente aceita as formas
|
||||
antiga e qualificada e escreve sempre a qualificada) → **migrations**
|
||||
(`docker compose --profile maintenance run --rm teqo-1313-migrate </dev/null`,
|
||||
já com a imagem do SHA novo) → **build do runner** (contra o banco JÁ
|
||||
migrado — o `next build` da geração estática lê o schema novo, OPS66;
|
||||
`--network host` com proxy socat `teqo-1313-build-proxy` na `stack_default`
|
||||
para alcançar o `postgres`; o proxy é criado idempotentemente pelo script)
|
||||
→ push/tag do runner → `docker compose up -d teqo-1313` → healthcheck →
|
||||
→ push do runner (tag qualificada de registry) → `docker compose up -d teqo-1313` → healthcheck →
|
||||
smoke (`/`, `/campanha/login`, `/admin`, barreira 307, WebAuthn
|
||||
login-options, `api/revalidate` com o secret real).
|
||||
5. Falha = job vermelho; nada é publicado pela metade (rollback automático
|
||||
|
|
@ -103,9 +105,9 @@ cd ~/stack
|
|||
# o backup do deploy que falhou é o compose com os tags antigos
|
||||
ls docker-compose.yml.pre-* # escolha o anterior ao deploy ruim
|
||||
cp docker-compose.yml.pre-<sha-anterior> docker-compose.yml
|
||||
# 2. puxar do registry (a imagem antiga já não fica local após a limpeza):
|
||||
# 2. puxar do registry (a imagem antiga já não fica local após a limpeza;
|
||||
# o compose referencia a tag qualificada — INF13 — e o pull basta):
|
||||
docker pull localhost:5000/teqo-1313:<sha-anterior>
|
||||
docker tag localhost:5000/teqo-1313:<sha-anterior> teqo-1313:<sha-anterior>
|
||||
# 3. subir:
|
||||
docker compose up -d teqo-1313
|
||||
```
|
||||
|
|
@ -121,19 +123,20 @@ a correção se re-mergeia e o próximo deploy completo publica.
|
|||
|
||||
## Falhas conhecidas
|
||||
|
||||
| Sintoma | Causa | Tratamento |
|
||||
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Job verde sem deploy ("stale run") | Push mais novo venceu; o dispatch apontava um SHA que não é mais o HEAD do main do GitHub | Nada a fazer — dispatch novo no main atual |
|
||||
| Job verde sem deploy ("already deployed") | O container rodando já tem a revision do SHA do job (ex.: `workflow_dispatch` duplicado da mesma HEAD) | Nada a fazer — o site já roda esse SHA. Forçar rebuild da MESMA HEAD não é suportado via dispatch: edite o tag da imagem no compose (`image: teqo-1313:<sha>-rebuild`) e `docker compose up -d`, ou espere um commit novo |
|
||||
| Job `deploy` nunca roda / runner offline | Runner self-hosted do homeserver não instalado ou parado (passo manual do cutover OPS71) | Instalar/religar o runner (labels `self-hosted`, `homeserver`); os PRs e o `verify` não dependem dele — só o deploy |
|
||||
| Deploy dispara mas o job `verify` falha | Regressão real na suíte full | Corrigir e re-dispatchar — o homeserver nunca é tocado |
|
||||
| Deploy para logo após o migrate ("Done." e nada mais, EXIT=0) | `docker compose run` anexa stdin por padrão — o container consome o resto do script; o bash chega a EOF e termina sem rodar o rollout | O script já usa `< /dev/null` no `run --rm` do migrate (não remover); sintoma visto 2026-08-17 no primeiro deploy |
|
||||
| Build falha: `network mode "stack_default" not supported by buildkit` | BuildKit (drivers docker e docker-container) recusa rede bridge custom no `--network` | O script builda com `--network host` + proxy socat `teqo-1313-build-proxy` (na `stack_default`, publicado em 127.0.0.1:5433, criado idempotentemente com `restart: unless-stopped`) + `DATABASE_URL` reescrita para o loopback |
|
||||
| Build OOM no homeserver | Laptop 8c/16GB com o stack ativo (~12GB livres medidos) | Re-dispatch; se recorrente, item futuro: build na workstation com túnel |
|
||||
| Build do runner falha: `relation "..." does not exist` no `next build` | Migration nova criou tabela lida em geração estática. Pré-OPS66 a ordem era build→migrate e o deploy morria aqui para sempre (incidente 2026-08-18, S2) | Pós-OPS66 não deve ocorrer: migrate roda antes do build do runner. Se reaparecer, confira no log se o passo migrate rodou; recovery manual: `docker build --target migrator` + `docker run --rm --network stack_default --env-file ~/stack/teqo-1313.env localhost:5000/teqo-1313-migrator:<sha>` e re-dispatch do workflow |
|
||||
| Workspace clone sem o SHA novo | O workspace antigo apontava para o Forgejo local (pré-OPS71) e o fetch não achou o SHA | O script agora re-aponta `origin` para `TEQO_REPO_URL` (idempotente) antes do fetch — se ainda falhar, `git -C ~/teqo-deploy remote -v` e corrigir manualmente |
|
||||
| Migrate falha | Drift/erro de schema | Job vermelho; site segue no container antigo; corrigir e re-mergear |
|
||||
| Smoke falha pós-up | Regressão de runtime | Rollback automático (restore + `up -d`) + job vermelho; investigar |
|
||||
| Sintoma | Causa | Tratamento |
|
||||
| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Job verde sem deploy ("stale run") | Push mais novo venceu; o dispatch apontava um SHA que não é mais o HEAD do main do GitHub | Nada a fazer — dispatch novo no main atual |
|
||||
| Job verde sem deploy ("already deployed") | O container rodando já tem a revision do SHA do job (ex.: `workflow_dispatch` duplicado da mesma HEAD) | Nada a fazer — o site já roda esse SHA. Forçar rebuild da MESMA HEAD não é suportado via dispatch: edite o tag da imagem no compose (`image: localhost:5000/teqo-1313:<sha>-rebuild`) e `docker compose up -d`, ou espere um commit novo |
|
||||
| Job `deploy` nunca roda / runner offline | Runner self-hosted do homeserver não instalado ou parado (passo manual do cutover OPS71) | Instalar/religar o runner (labels `self-hosted`, `homeserver`); os PRs e o `verify` não dependem dele — só o deploy |
|
||||
| Deploy dispara mas o job `verify` falha | Regressão real na suíte full | Corrigir e re-dispatchar — o homeserver nunca é tocado |
|
||||
| `No such image` ao recriar o container fora de deploy (ex.: `compose up -d` pós-reboot/migração) | O compose referenciava uma tag local bare (`teqo-1313:<sha>`) que desapareceu sem recriação (achado INF8/INF13, 24/08: só restava a ref do registry) | Corrigido no INF13: o compose referencia a tag **qualificada** (`localhost:5000/teqo-1313:<sha>`), que todo build cria e o cleanup F2 preserva por image ID. Recovery do estado antigo: `docker pull localhost:5000/teqo-1313:<sha>` + `docker compose up -d` |
|
||||
| Deploy para logo após o migrate ("Done." e nada mais, EXIT=0) | `docker compose run` anexa stdin por padrão — o container consome o resto do script; o bash chega a EOF e termina sem rodar o rollout | O script já usa `< /dev/null` no `run --rm` do migrate (não remover); sintoma visto 2026-08-17 no primeiro deploy |
|
||||
| Build falha: `network mode "stack_default" not supported by buildkit` | BuildKit (drivers docker e docker-container) recusa rede bridge custom no `--network` | O script builda com `--network host` + proxy socat `teqo-1313-build-proxy` (na `stack_default`, publicado em 127.0.0.1:5433, criado idempotentemente com `restart: unless-stopped`) + `DATABASE_URL` reescrita para o loopback |
|
||||
| Build OOM no homeserver | Laptop 8c/16GB com o stack ativo (~12GB livres medidos) | Re-dispatch; se recorrente, item futuro: build na workstation com túnel |
|
||||
| Build do runner falha: `relation "..." does not exist` no `next build` | Migration nova criou tabela lida em geração estática. Pré-OPS66 a ordem era build→migrate e o deploy morria aqui para sempre (incidente 2026-08-18, S2) | Pós-OPS66 não deve ocorrer: migrate roda antes do build do runner. Se reaparecer, confira no log se o passo migrate rodou; recovery manual: `docker build --target migrator` + `docker run --rm --network stack_default --env-file ~/stack/teqo-1313.env localhost:5000/teqo-1313-migrator:<sha>` e re-dispatch do workflow |
|
||||
| Workspace clone sem o SHA novo | O workspace antigo apontava para o Forgejo local (pré-OPS71) e o fetch não achou o SHA | O script agora re-aponta `origin` para `TEQO_REPO_URL` (idempotente) antes do fetch — se ainda falhar, `git -C ~/teqo-deploy remote -v` e corrigir manualmente |
|
||||
| Migrate falha | Drift/erro de schema | Job vermelho; site segue no container antigo; corrigir e re-mergear |
|
||||
| Smoke falha pós-up | Regressão de runtime | Rollback automático (restore + `up -d`) + job vermelho; investigar |
|
||||
|
||||
## Backup passivo no Forgejo (OPS76-FOLLOWUP, 2026-08-21)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,11 +11,12 @@
|
|||
# Flow: HEAD guard (only the current main HEAD deploys) -> flock
|
||||
# serialization -> workspace fetch at <sha> -> docker login (local registry)
|
||||
# -> build of the MIGRATOR stage (it never runs `next build`, so it builds
|
||||
# even against the old schema) -> push/tag of the migrator -> compose
|
||||
# image-tag swap (with backup) -> migrate via the maintenance service
|
||||
# even against the old schema) -> push of the migrator (registry-qualified
|
||||
# tag — INF13: the ONLY ref the compose references) -> compose image-tag swap
|
||||
# (with backup) -> migrate via the maintenance service
|
||||
# (BEFORE the runner build — static generation reads the NEW schema, OPS66)
|
||||
# -> build of the runner stage (BuildKit secrets, compose network) ->
|
||||
# push/tag -> compose up -> healthcheck wait -> smoke. Any failure after the
|
||||
# push -> compose up -> healthcheck wait -> smoke. Any failure after the
|
||||
# swap rolls back to the previous compose + image; failures before it leave
|
||||
# the running site untouched and the job red.
|
||||
#
|
||||
|
|
@ -151,9 +152,13 @@ cd "$WORKSPACE_DIR"
|
|||
# and therefore needs the migrations applied first (OPS66).
|
||||
build_image migrator "localhost:5000/teqo-1313-migrator:$SHA"
|
||||
|
||||
# The compose references bare `teqo-1313:<sha>` tags with pull_policy: never.
|
||||
# INF13: the compose references REGISTRY-QUALIFIED tags
|
||||
# (`localhost:5000/teqo-1313(-migrator):<sha>`) with pull_policy: never — the
|
||||
# exact name every build produces, so the ref the compose needs can never go
|
||||
# missing (the old bare `teqo-1313:<sha>` alias was a second local-only ref
|
||||
# that nothing recreated once lost — homeserver incident 24/08, `No such
|
||||
# image` on recreate).
|
||||
docker push "localhost:5000/teqo-1313-migrator:$SHA"
|
||||
docker tag "localhost:5000/teqo-1313-migrator:$SHA" "teqo-1313-migrator:$SHA"
|
||||
|
||||
# --- compose swap (backup first; failures from here roll back) ----------
|
||||
|
||||
|
|
@ -161,12 +166,12 @@ compose="$STACK_DIR/docker-compose.yml"
|
|||
backup="$compose.pre-$SHA"
|
||||
cp "$compose" "$backup"
|
||||
sed -i -E \
|
||||
-e "s|image: teqo-1313-migrator:[0-9a-f]+|image: teqo-1313-migrator:$SHA|g" \
|
||||
-e "s|image: teqo-1313:[0-9a-f]+|image: teqo-1313:$SHA|g" \
|
||||
-e "s|image: (localhost:5000/)?teqo-1313-migrator:[0-9a-f]+|image: localhost:5000/teqo-1313-migrator:$SHA|g" \
|
||||
-e "s|image: (localhost:5000/)?teqo-1313:[0-9a-f]+|image: localhost:5000/teqo-1313:$SHA|g" \
|
||||
-e "s|org.opencontainers.image.revision: [0-9a-f]+|org.opencontainers.image.revision: $SHA|g" \
|
||||
"$compose"
|
||||
grep -q "image: teqo-1313:$SHA" "$compose" || fatal "compose swap failed (runner image)"
|
||||
grep -q "image: teqo-1313-migrator:$SHA" "$compose" || fatal "compose swap failed (migrator image)"
|
||||
grep -q "image: localhost:5000/teqo-1313:$SHA" "$compose" || fatal "compose swap failed (runner image)"
|
||||
grep -q "image: localhost:5000/teqo-1313-migrator:$SHA" "$compose" || fatal "compose swap failed (migrator image)"
|
||||
|
||||
rollback() {
|
||||
trap - ERR
|
||||
|
|
@ -197,7 +202,6 @@ cd "$WORKSPACE_DIR"
|
|||
say "building runner"
|
||||
build_image runner "localhost:5000/teqo-1313:$SHA"
|
||||
docker push "localhost:5000/teqo-1313:$SHA"
|
||||
docker tag "localhost:5000/teqo-1313:$SHA" "teqo-1313:$SHA"
|
||||
|
||||
# --- rollout ------------------------------------------------------------
|
||||
|
||||
|
|
@ -236,20 +240,23 @@ echo "$body" | grep -q '"revalidated":true' || smoke_fail "POST /api/revalidate
|
|||
# antigas). Best-effort e APÓS o smoke: falha de limpeza nunca falha um
|
||||
# deploy verde. O registry localhost:5000 preserva as imagens (rollback
|
||||
# intacto — runbook teqo-1313-deploy.md); removemos só as tags LOCAIS.
|
||||
# Fail-closed: sem revision no container, não remove nada além do cache.
|
||||
# INF13: a preservação é pelo IMAGE ID do container em uso (`{{.Image}}`),
|
||||
# não por comparação tag×label do compose — imune a drift de label/recriação
|
||||
# manual; TODAS as tags da imagem rodando sobrevivem, as demais são removidas.
|
||||
# Fail-closed: container sem image ID não remove nada além do cache.
|
||||
|
||||
say "post-deploy cleanup: build cache + tags locais antigas"
|
||||
docker builder prune -f >/dev/null 2>&1 || true
|
||||
|
||||
in_use="$(docker inspect -f '{{index .Config.Labels "org.opencontainers.image.revision"}}' teqo-1313 2>/dev/null || true)"
|
||||
if [ -n "$in_use" ]; then
|
||||
in_use_id="$(docker inspect -f '{{.Image}}' teqo-1313 2>/dev/null || true)"
|
||||
if [ -n "$in_use_id" ]; then
|
||||
for img in $(docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^(localhost:5000/)?teqo-1313(-migrator)?:' || true); do
|
||||
tag="${img##*:}"
|
||||
[ "$tag" = "$in_use" ] && continue
|
||||
img_id="$(docker image inspect -f '{{.Id}}' "$img" 2>/dev/null || true)"
|
||||
[ -n "$img_id" ] && [ "$img_id" = "$in_use_id" ] && continue
|
||||
docker rmi "$img" >/dev/null 2>&1 || true
|
||||
done
|
||||
else
|
||||
say "cleanup: container sem revision — mantendo imagens locais"
|
||||
say "cleanup: container sem image ID — mantendo imagens locais"
|
||||
fi
|
||||
|
||||
say "deploy of $SHA complete: $(docker inspect -f '{{.Image}}' teqo-1313)"
|
||||
|
|
|
|||
Loading…
Reference in a new issue