diff --git a/docs/ops/teqo-1313-deploy.md b/docs/ops/teqo-1313-deploy.md index 11244115..63826ab2 100644 --- a/docs/ops/teqo-1313-deploy.md +++ b/docs/ops/teqo-1313-deploy.md @@ -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 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: -docker tag localhost:5000/teqo-1313: teqo-1313: # 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:-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:` 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:-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:`) 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:`), que todo build cria e o cleanup F2 preserva por image ID. Recovery do estado antigo: `docker pull localhost:5000/teqo-1313:` + `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:` 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) diff --git a/scripts/deploy-homeserver.sh b/scripts/deploy-homeserver.sh index 420ccfa2..550b34fc 100644 --- a/scripts/deploy-homeserver.sh +++ b/scripts/deploy-homeserver.sh @@ -11,11 +11,12 @@ # Flow: HEAD guard (only the current main HEAD deploys) -> flock # serialization -> workspace fetch at -> 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:` tags with pull_policy: never. +# INF13: the compose references REGISTRY-QUALIFIED tags +# (`localhost:5000/teqo-1313(-migrator):`) 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:` 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)"