All checks were successful
CD / Deploy to Test (push) Successful in 12s
CD / Smoke tests against Test (push) Successful in 1m15s
CD / Promote to Int (push) Successful in 12s
CI / Lint, typecheck, test (push) Successful in 6m19s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 8m13s
CI / Import/export fidelity gate (push) Successful in 54s
CI / Lint, typecheck, test (pull_request) Successful in 6m20s
CI / Build container images (pull_request) Successful in 1m12s
CI / Auth e2e pack (pull_request) Successful in 8m24s
CI / Import/export fidelity gate (pull_request) Successful in 58s
CD / Build and push images (push) Successful in 22s
Adds docs/operations/update-runbook.md (obtain, verify by digest, back up, apply, verify, roll back) with the migration behaviour stated explicitly: a failed migration rolls back its own transaction but is recorded in _prisma_migrations and blocks every further migrate deploy (P3009) — including a re-deployed old image — until migrate resolve --rolled-back; semantically irreversible migrations have exactly one way back, the pre-update backup set. No rolling updates on a compose stage. Rehearsed in the isolated environment of #220: regular update to a v2 image set, then a deliberate failed-update (P3018 division by zero, schema change proven rolled back) with image-rollback-alone shown insufficient and the documented recovery executed. Protocol: docs/vs-nfd/98-update-rollback-protokoll.md. ADR 0024 decisions 5+6 recorded as executed; operations handbook and restore runbook updated; plan checkbox P1-3 ticked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AUtYMxwTCMHG9mVHnwbFg8
78 lines
4.4 KiB
Markdown
78 lines
4.4 KiB
Markdown
# Update-/Rollback-Protokoll — Probe in der isolierten Umgebung (Issue #221)
|
|
|
|
Nachweis für Maßnahmenplan P1-3 (ADR 0024): der Update-Pfad inklusive
|
|
Migrationen und geprobtem Fehlschlag-Rollback, ausgeführt in derselben
|
|
netzisolierten Umgebung wie der Isolationslauf
|
|
(`97-isolationslauf-protokoll.md` — Compose-Projekt `dorfteich-isolated`,
|
|
alle Netze `internal: true`, kein Egress-Pfad). Belegstufe: **live
|
|
verifiziert**. Die daraus destillierte Prozedur steht in
|
|
`docs/operations/update-runbook.md`.
|
|
|
|
- **Datum:** 2026-07-31
|
|
- **Ausgangsstand („v1"):** Images `dorfteich-iso-*:isolated`
|
|
(`main@a758c9d`, backup mit #288-Fix aus `4f6596e`), Instanz mit
|
|
Inhalt aus dem Isolationslauf.
|
|
- **Update-Ziel („v2"):** Images `dorfteich-iso-*:isolated-v2`, gebaut
|
|
aus dem Kettenstand `ccffcaa` (#288 + #220) — als Stellvertreter eines
|
|
regulären Release-Bundles; die Beschaffung/Digest-Prüfung eines echten
|
|
Bundles ist das Mirror-Verfahren (#218, `95-mirror-protokoll.md`) und
|
|
wurde dort bereits nachgewiesen.
|
|
- **Fehlschlag-Kandidat („bad"):** api-Image mit einer absichtlich
|
|
fehlschlagenden Migration
|
|
(`20260731230000_deliberately_failing_update`: `ALTER TABLE` +
|
|
`SELECT 1/0`), nur für die Probe gebaut, nie committet.
|
|
|
|
## Phase A — reguläres Update
|
|
|
|
| Schritt | Ergebnis |
|
|
| ------------------- | --------------------------------------------------------------------------------------------- |
|
|
| Pre-Update-Backup | ✅ Set `20260731-150833` über die Admin-API erzeugt und in der Set-Liste bestätigt |
|
|
| `TAG` → v2, `up -d` | ✅ alle vier eigenen Services zusammen ersetzt (Ausfallfenster Sekunden, kein Rolling Update) |
|
|
| Migrationen | ✅ migrate-on-start läuft durch (dieses „Release" enthält keine neuen Migrationen) |
|
|
| `/readyz` | ✅ vollständig grün |
|
|
| Inhalt | ✅ Seite „Isolationstest Seite" unverändert vorhanden |
|
|
|
|
## Phase B — geprobter Fehlschlag + Rollback
|
|
|
|
1. **Bad-Update einspielen** (`TAG` → bad, `up -d`): api scheitert beim
|
|
Boot in `migrate deploy` — **P3018**, `ERROR: division by zero` bei
|
|
`20260731230000_deliberately_failing_update`; Container geht in den
|
|
Restart-Loop, jeder Folge-Boot meldet **P3009** („migrate found
|
|
failed migrations").
|
|
2. **Datenbank-Zustand geprüft:** die Migration steht als `failed` in
|
|
`_prisma_migrations` (Logs erfasst), aber `broken_column` existiert
|
|
**nicht** — die per-Migration-Transaktion hat den Schema-Eingriff
|
|
zurückgerollt. Genau das dokumentierte Verhalten.
|
|
3. **Image-Rollback allein reicht nicht** (bewusst vorgeführt): `TAG`
|
|
zurück auf v2, `up -d` — der alte Stand scheitert weiter mit
|
|
**P3009** („The 20260731230000_deliberately_failing_update migration
|
|
started at 2026-07-31 15:10:50 UTC failed").
|
|
4. **Recovery wie im Runbook:**
|
|
`migrate resolve --rolled-back 20260731230000_deliberately_failing_update`
|
|
(im api-Image ausgeführt) → „marked as rolled back" → api-Neustart:
|
|
`/readyz` vollständig grün, Inhalt unverändert, Migrations-Row trägt
|
|
`rolled_back_at`.
|
|
5. **Alternativer Weg zurück** (für semantisch irreversible, aber
|
|
erfolgreich gelaufene Migrationen): Restore des Pre-Update-Sets — der
|
|
Restore-Pfad selbst ist im Isolationslauf verifiziert
|
|
(`97-isolationslauf-protokoll.md`, Fix #288).
|
|
|
|
## Versions-Skew (Akzeptanzkriterium)
|
|
|
|
Ein Compose-Stage kennt **kein Rolling Update**: `docker compose up -d`
|
|
ersetzt web/api/collab/backup zusammen; Mischbetrieb alter und neuer
|
|
Versionen ist kein unterstützter Betriebszustand und dauert nur die
|
|
Container-Ersetzung selbst (Sekunden). Für VS-Zonen heißt das: Update im
|
|
angekündigten Wartungsfenster; die Migrationen wendet ausschließlich der
|
|
neue api-Container beim Start an (`MIGRATE_ON_START`).
|
|
|
|
## Rückfluss
|
|
|
|
- **`docs/operations/update-runbook.md`** — die Prozedur (Beschaffen,
|
|
Prüfen, Sichern, Einspielen, Verifizieren, Rollback) inkl. explizitem
|
|
Migrationsverhalten; aus dieser Probe destilliert.
|
|
- **`docs/operations/restore-runbook.md`** — Querverweis: Restore als
|
|
einziger Weg zurück nach irreversiblen Migrationen.
|
|
- **#229** — Betriebshandbuch §1 (Airgap) und §2 (Update/Rollback)
|
|
verweisen auf Runbook und dieses Protokoll.
|