docs(deploy): bake Stage 18 prod-deploy decisions into the live docs
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 16s
CI / ui (pull_request) Successful in 57s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m8s

- ARCHITECTURE §13 prod bullet -> the realized mechanism: registry transport,
  two-host, rolling + auto-rollback, migration maintenance window, node_exporter,
  the undersized launch; the contour paragraph notes node_exporter + the
  telegram-local profile.
- deploy/README gains a prod rollout runbook (how to run, migrations/restore, cert
  rotation, sizing/monitoring, the full PROD_ set) + node_exporter row, the
  telegram-local profile note, and the soft AWG_CONF note.
- PLAN Stage 18 records the resolved open details and the remaining live cutover
  (pending erudit-game.ru DNS); the tracker reads 'machinery built; cutover pending DNS'.
- PRERELEASE TX/AG note the prod wiring is built.
This commit is contained in:
Ilia Denisov
2026-06-22 00:30:30 +02:00
parent 171b71b7e0
commit 3d9ba3ac3d
4 changed files with 104 additions and 30 deletions
+23 -13
View File
@@ -51,7 +51,7 @@ independent (see ARCHITECTURE §9.1).
| 15 | Dual Telegram bots & language-gated variants | **done** |
| 16 | Deploy infra & test contour (Dockerfiles, gateway static UI, compose, observability) | **done** |
| 17 | Test-contour verification & defect fixes | **done** |
| 18 | Prod contour deploy (SSH export/import, manual after merge) | todo |
| 18 | Prod contour deploy (registry, two-host, rolling + auto-rollback; manual after merge) | machinery built; first cutover pending DNS |
| 19 | User feedback (in-app submit + attachment, admin review/reply, account roles) | **done** |
Scaffolding is incremental: `go.work` lists only existing modules; each stage
@@ -413,18 +413,28 @@ raw list is kept here as the record of what the first contour run surfaced.
"что-то пошло не так". при этом "new -> эрудит" работает. Попробуй посмотреть в логах сейчас, может что-то есть. Или как-то иначе проанализируй, или давай вместе будем смотреть, если не получится.
### Stage 18 — Prod contour deploy
Scope: the **production contour** on a remote host over SSH. Deploy by **container export/import**
(`docker save``scp`/ssh → `docker load``docker compose up` on the remote), the SSH key + host IP
in Gitea secrets; **strictly manual** (`workflow_dispatch`) after `development` is merged to `master`
(the Stage 16 branch model: `feature/* → development → master`, merge gated green). Two-contour config
uses **`TEST_`/`PROD_` secret/variable prefixes** — Gitea 1.26 has no deployment environments (verified:
the `environments` API 404s), so a flat prefixed namespace is the convention.
Reuses the Stage 16 `deploy/docker-compose.yml` as-is, mapping the **`PROD_`** set onto the same
unprefixed compose vars. **No host caddy on prod**, so the contour's own caddy terminates TLS — set
`CADDY_SITE_ADDRESS` to the prod domain so caddy does its own ACME (the Caddyfile is already
parameterised for this; the test contour leaves it `:80` behind the host caddy).
Open details (re-interview): export/import vs a registry trade-off; prod domain/cert source (ACME vs a
provided cert) at the contour caddy; prod VPN; rollback.
Scope: the **production contour** on **two remote hosts** over SSH — main (full stack, `erudit-game.ru`)
and tg (the bot only). Resolved open details (re-interviewed):
- **Transport: a registry** (not export/import) — build + push to `docker.iliadenisov.ru`, the hosts pull by tag.
- **Cert: ACME** at the contour caddy (`CADDY_SITE_ADDRESS=erudit-game.ru www.erudit-game.ru`, no host caddy).
- **No prod VPN** — the bot host has native Bot API egress (verified `api.telegram.org` → 200).
- **Rollback** — rolling per-service deploy (least → most dependent), health-gated, auto-rollback to the
previous image tag; a maintenance window + consistent `pg_dump` only on a schema migration
(expand-contract keeps the auto-rollback image-only; the dump is a manual safety net).
**Strictly manual** (`workflow_dispatch` from `master`, `confirm=deploy`) after `development → master`
is merged green. `TEST_`/`PROD_` prefixed Gitea secrets/variables (Gitea 1.26 has no deployment
environments — the `environments` API 404s). Hosts are provisioned by **`deploy/ansible/`** (docker, a
non-sudo `deploy` user with the CI key, key-only sshd, ufw, fail2ban). The main host is **launch-sized**
(2 vCPU / 1.9 GiB): `docker-compose.prod.yml` trims the R7 limits (`GOMAXPROCS=2`, smaller caps, 7d
Prometheus retention) and adds `node_exporter` for host-memory monitoring (launch undersized, resize at
Selectel reactively). `vpn`+`bot` are gated to a `telegram-local` compose profile (test only); the prod
bot runs standalone from `docker-compose.bot.yml`. `GATEWAY_ABUSE_BAN_ENABLED=true`.
**Built:** `deploy/ansible/` (both hosts provisioned + verified), the compose split + `node_exporter`,
`.gitea/workflows/prod-deploy.yaml` + `deploy/prod-deploy.sh`, the full `PROD_` secret/variable set.
**Remaining (acceptance):** the **first live cutover** — waits on the `erudit-game.ru` DNS delegation
(`A`/`www` → the main host) that ACME requires; then run the workflow and verify the public site end-to-end.
### Stage 19 — User feedback *(done)*
A user→operator feedback channel, sequenced after the numbered stages but shipped **before** the Stage 18