mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-14 08:53:11 +00:00
177 lines
18 KiB
Markdown
177 lines
18 KiB
Markdown
# Runbook: deploy do site 1313 no homeserver (OPS53 + OPS71 — dispatch manual)
|
|
|
|
O deploy de produção é uma **action manual** (`workflow_dispatch` no GitHub
|
|
Actions, `.github/workflows/deploy.yml`): mergir em `main` **não** publica
|
|
nada. O operador dispara o deploy quando decide publicar; antes de tocar o
|
|
homeserver, o job `verify` (hosted) roda a suíte **full** (incl. e2e full).
|
|
|
|
## Gatilho e fluxo
|
|
|
|
1. GitHub → Actions → **Deploy (manual)** → Run workflow (ref: `main`).
|
|
2. Job `verify` (hosted `ubuntu-latest`, ~50 min): suíte full sem skips —
|
|
check-test-locations → lint → format → typecheck → knip → cycles → unit →
|
|
int (migrate+seed nos services) → build → e2e full.
|
|
3. Se `verify` verde, o job `deploy` (`needs: [verify]`,
|
|
`runs-on: [self-hosted, homeserver]`) roda no **runner do GitHub instalado
|
|
no homeserver** e executa `scripts/deploy-homeserver.sh <sha>` **localmente**
|
|
(sem SSH; o runner conecta outbound ao GitHub — funciona atrás do
|
|
Cloudflare tunnel; o hosted nunca toca o homeserver; o self-hosted não
|
|
conta minutos hosted).
|
|
4. O script, no **homeserver**: guarda de HEAD (`git ls-remote` de
|
|
`TEQO_REPO_URL` — default `https://github.com/fsolla/teqo.git`, público —
|
|
== 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**
|
|
(`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 →
|
|
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
|
|
após o swap).
|
|
|
|
**Primeiro deploy (verificação ao vivo):** depois do cutover OPS71, dispare o
|
|
deploy manual e confira no log do job `deploy` o `set-url` do workspace
|
|
(origem Forgejo → GitHub), o `deployed_sha` lido do container e o guard
|
|
"already deployed" num segundo dispatch do mesmo SHA.
|
|
|
|
## Onde roda cada coisa
|
|
|
|
| Máquina | Papel |
|
|
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
| **GitHub hosted** (ubuntu) | CI de PR (`ci-pr.yml`, job `checks`) e job `verify` do `deploy.yml` (suíte full). Nunca toca o homeserver. |
|
|
| **homeserver** (8c/16GB) | todo o stack (`~/stack/docker-compose.yml`): postgres `teqo_1313`, forgejo, registry `localhost:5000`, cloudflared, `teqo-1313` na 127.0.0.1:1313; **runner self-hosted do GitHub** (labels `self-hosted`, `homeserver`; instalado 2026-08-19 — Issue #113 OPS71-INFRA; `~/actions-runner` v2.336.0, systemd user `actions.runner.fsolla-teqo.teqo-1313-runner.service` — `systemctl --user status/restart`); workspace `~/teqo-deploy` (clone de `github.com/fsolla/teqo`, público) |
|
|
| **workstation** | dev/agentes apenas — o runner do Forgejo foi **desligado** no cutover (o schedule do `ci.yml` antigo não tem mais razão; religar é reversível) |
|
|
|
|
Segredos **não** ficam no GitHub: o script sourceia `~/stack/teqo-1313.env` e
|
|
`~/stack/.env` (chmod 600) no próprio homeserver. O repo GitHub é público — o
|
|
clone do workspace não precisa de credencial. No GitHub ficam apenas os
|
|
secrets de integração: `FORGEJO_API_TOKEN` (flips pós-merge) e
|
|
`CURSOR_API_KEY` (archive helper, dormente).
|
|
|
|
## Cutover OPS71 (passos manuais, ordem)
|
|
|
|
1. Remotes locais (config compartilhada pelos worktrees):
|
|
`git remote set-url origin git@github.com:fsolla/teqo.git` e
|
|
`git remote add forgejo ssh://git@192.168.15.142:2222/fsolla/teqo.git`
|
|
(ou `https://git.solla.dev/fsolla/teqo.git`) — o repo Forgejo congela em
|
|
main; o tracker (Issues) segue vivo por API.
|
|
2. GitHub repo: secrets `FORGEJO_API_TOKEN` + `CURSOR_API_KEY`
|
|
(Settings → Secrets and variables → Actions) e **`Allow auto-merge`**
|
|
(Settings → General → Pull Requests; ou `PATCH /repos/...` com
|
|
`allow_auto_merge: true`). Repo é público: em Settings → Actions →
|
|
General, defina fork PR workflows como não executar (ou exigir aprovação).
|
|
3. PAT local: criar token GitHub com escopo `repo` e exportar `GITHUB_TOKEN`
|
|
(para `node scripts/github-pr.mjs` e `pnpm configure:branch-protection`).
|
|
4. `GITHUB_TOKEN=… pnpm configure:branch-protection` — required check
|
|
`CI (PR) / checks` (literal de match: `checks` — o GitHub casa pelo nome do
|
|
check-run; a UI exibe workflow/job; pin PR #742), 0 reviews,
|
|
`enforce_admins: true`. **Antes do primeiro push** (senão o PR mergearia
|
|
sem required check).
|
|
5. **Desligar o runner do Forgejo** na workstation (ex.:
|
|
`systemctl --user stop forgejo-runner`) — após o primeiro PR GitHub
|
|
validado; para o schedule do `ci.yml` antigo.
|
|
6. Instalar o runner self-hosted do GitHub no homeserver (labels
|
|
`self-hosted` + `homeserver`; usuário com docker + acesso a `~/stack`;
|
|
registrar em infra-solla: `STATE.md`).
|
|
7. Push do PR do OPS71 → CI verde → auto-merge → flip da Issue no Forgejo →
|
|
deploy manual de validação.
|
|
|
|
Rollback do cutover (se o GitHub falhar cedo): religar o runner do Forgejo e
|
|
abrir PRs no Forgejo a partir do main congelado — os workflows de
|
|
`.forgejo/workflows/` foram removidos na OPS71 Fase 2, mas restauram do git
|
|
history (`git revert` do PR da remoção, ou clone do main congelado do Forgejo)
|
|
— remotes: `git remote set-url origin ssh://git@192.168.15.142:2222/fsolla/teqo.git`.
|
|
|
|
## Rollback (do deploy)
|
|
|
|
A imagem anterior **não** fica mais local após a limpeza pós-deploy (INF3/F2:
|
|
`docker builder prune` + remoção das tags locais antigas, exceto o SHA em uso)
|
|
— o registry `localhost:5000` **nunca deleta** e é a fonte do rollback. O
|
|
compose anterior fica em `~/stack/docker-compose.yml.pre-<sha-do-deploy-que-falhou>`.
|
|
|
|
```bash
|
|
ssh homeserver
|
|
cd ~/stack
|
|
# 1. apontar o compose de volta para o SHA anterior (o que estava rodando):
|
|
# 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):
|
|
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
|
|
```
|
|
|
|
**Caveat:** uma migration de schema aplicada no passo de migrate **não** é
|
|
desfeita pelo rollback (Payload é append-only). Código velho sobre schema novo
|
|
pode se comportar mal — o caminho primário minimiza essa janela (migrate só
|
|
roda após migrator build+push+swap ok; rollout só após runner build ok). Desde
|
|
o OPS66 o migrate roda **antes** do build do runner (o build precisa do schema
|
|
novo): um build do runner que falhe depois do migrate deixa o banco à frente
|
|
do código — migrations são append-only e revisadas antes do deploy (checklist);
|
|
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 |
|
|
|
|
## Backup passivo no Forgejo (OPS76-FOLLOWUP, 2026-08-21)
|
|
|
|
O GitHub é a única fonte (main, branches, PRs, CI, tracker). O Forgejo mantém
|
|
um **backup passivo** via **pull mirror nativo**: o repo `teqo-backup` no
|
|
Forgejo (`https://git.solla.dev/fsolla/teqo-backup`) espelha o GitHub
|
|
automaticamente — **não serve push, não recebe PRs, é somente leitura**.
|
|
|
|
- **Repo:** `fsolla/teqo-backup` no Forgejo (`mirror: true`), criado via
|
|
`POST /api/v1/repos/migrate` com `clone_addr=https://github.com/fsolla/teqo.git`,
|
|
`service=github`, `mirror=true`, intervalo **8h** (`mirror_interval`).
|
|
- **Automação:** o próprio Forgejo sincroniza no intervalo (sem workflow).
|
|
Force sync manual: `POST /api/v1/repos/fsolla/teqo-backup/mirror-sync`
|
|
(o "Synchronize now" da UI).
|
|
- **Cobertura:** espelha todas as branches (54/54 verificadas) e tags; o
|
|
histórico do mirror reflete o do GitHub (que é a convergência OPS75 +
|
|
OPS76). Não espelha issues/PRs/labels (GitHub é o tracker).
|
|
- **Validação:** `git ls-remote` do `teqo-backup` deve retornar o mesmo SHA
|
|
de `refs/heads/main` do GitHub; conferir em `mirror_updated` o último sync.
|
|
- **O repo `fsolla/teqo` original do Forgejo** fica **congelado** no ponto da
|
|
convergência (OPS75) — arquivo histórico, sem mais uso.
|
|
|
|
## Segurança (decisão deliberada)
|
|
|
|
- O job `deploy` usa `runs-on: [self-hosted, homeserver]` — executa como o
|
|
usuário do runner no homeserver. Está **apenas** no `deploy.yml`
|
|
(dispatch manual), nunca no `ci-pr.yml`; o hosted (`verify`) não tem acesso
|
|
ao homeserver e o self-hosted não recebe secrets de produção (as envs vivem
|
|
no próprio homeserver). `main` só anda por PR mergeado com CI verde; o
|
|
deploy só roda com `verify` full verde. Fork-PRs não rodam CI (same-repo
|
|
gate + setting do repo).
|
|
- Segredos nunca ecoados: sem `set -x`, senhas via `--password-stdin` /
|
|
build-secrets; envs só no homeserver.
|
|
|
|
## Referências
|
|
|
|
- `scripts/deploy-homeserver.sh` — o script (fonte da verdade do fluxo)
|
|
- `.github/workflows/deploy.yml` — verify → deploy
|
|
- `docs/plans/ops53-ci-deploy-homeserver*.md` — intenção e decisões (era Forgejo)
|
|
- `docs/plans/ops71-ci-github-actions-tracker-forgejo*.md` — o cutover
|
|
- infra-solla: `STATE.md`, `plano-infra-final.md` §"Arquitetura de deploy"
|