docs: gate 5 for the k3s patch, an ADR for the flags, and an AAR for what it broke
The jump itself did exactly what gate 2 predicted: 278 high findings down to 89, fifteen criticals to none, every component on the version the release ships. The two flags I nearly forgot both earned their place — ingresses still publish the public address, and the API certificate kept it. What was expensive was not the version. A restart of the control plane tests everything that leans on it, and two things did not come back on their own: kube-state-metrics sat in crashloop, and alloy's log tailers died while logging 'will retry'. Twelve minutes without cluster logs, and nothing said so. That same window emptied the metric the scan target set is derived from. The query succeeded with zero rows, which counted as success, so the set fell from 54 to 12 and the next round deleted 42 reports — while coverage read 1.0. Three rules I wrote the day before all stayed quiet, each for a defensible reason. The gap sat exactly between them. The stolperstein page for that failure class is marked harvested, and it is not: the rule the framework took from it does not cover either case here. Both are recorded there with what a future formulation would have to say instead.
This commit is contained in:
@@ -84,13 +84,11 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md).
|
||||
| [0072](docs/issues/0072-gitops-34-dsgvo-datenschutz-compliance-konkretisieren.md) | low | open | DSGVO/Datenschutz-Compliance konkretisieren |
|
||||
|
||||
|
||||
## Active design docs (1)
|
||||
## Active design docs (0)
|
||||
|
||||
| Design | Gate | Title |
|
||||
|---|---|---|
|
||||
| [2026-08-22-k3s-patch-1-34-10](docs/design/2026-08-22-k3s-patch-1-34-10.md) | gate-4 | Design: k3s v1.34.6 → v1.34.10 — die mitgelieferten Komponenten nachziehen |
|
||||
_none active_
|
||||
|
||||
## ADRs (27)
|
||||
## ADRs (28)
|
||||
|
||||
| ADR | Status | Title |
|
||||
|---|---|---|
|
||||
@@ -121,8 +119,9 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md).
|
||||
| [0025](docs/adr/0025-egress-ausnahmen-als-cidr-ausser-hinter-cdn.md) | accepted | ADR-0025: Egress-Ausnahmen werden als CIDR gepinnt — außer hinter einem CDN |
|
||||
| [0026](docs/adr/0026-pruefziele-werden-abgeleitet-nicht-gepflegt.md) | accepted | ADR-0026: Prüfziele werden abgeleitet, nicht gepflegt — und das Ausbleiben der Herleitung alarmiert |
|
||||
| [0027](docs/adr/0027-zuletzt-eigener-meilenstein.md) | accepted | ADR-0027: „Zuletzt" wird ein eigener Meilenstein (M6) |
|
||||
| [0028](docs/adr/0028-ingress-bleibt-k3s-verwaltet-flags-gestrichen.md) | accepted | ADR-0028: Der Ingress bleibt vorerst k3s-verwaltet — die drei nie wirksamen Flags werden gestrichen |
|
||||
|
||||
## Open AARs (10)
|
||||
## Open AARs (11)
|
||||
|
||||
- [AAR — Alle geplanten Prüfungen waren dauerhaft rot und meldeten damit nichts mehr](docs/aar/2026-08-18-alle-pruefungen-dauerhaft-rot.md)
|
||||
- [AAR — Nach der Freischaltung sendete Safari ungefiltert weiter](docs/aar/2026-08-18-safari-sendete-ungefiltert.md)
|
||||
@@ -134,6 +133,7 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md).
|
||||
- [AAR: Deploy der abgeleiteten CVE-Zielmenge (#0106)](docs/aar/2026-08-21-cve-zielmenge-deploy.md)
|
||||
- [AAR: Die Anmeldung brach nach dem ESS-Sprung — eine Netzregel von heute Morgen](docs/aar/2026-08-21-mas-haproxy-netzregel.md)
|
||||
- [AAR: Die Ausrollstrecke stand eine Stunde — der Push-Spiegel kam nicht durch](docs/aar/2026-08-21-spiegel-ausfall.md)
|
||||
- [AAR: 42 Scan-Berichte gelöscht, und das Dashboard meldete dafür „vollständig"](docs/aar/2026-08-23-zielmenge-eingebrochen.md)
|
||||
|
||||
## Fehlerklassen (18)
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
type: aar
|
||||
status: open
|
||||
date: 2026-08-23
|
||||
related:
|
||||
- "docs/design/done/2026-08-22-k3s-patch-1-34-10.md"
|
||||
- "docs/adr/0026-pruefziele-werden-abgeleitet-nicht-gepflegt.md"
|
||||
- "docs/issues/0106-cve-scan-deckt-nur-die-haelfte-zielliste-ist-handgepflegt.md"
|
||||
---
|
||||
|
||||
# AAR: 42 Scan-Berichte gelöscht, und das Dashboard meldete dafür „vollständig"
|
||||
|
||||
**Schwere:** MEDIUM (kein Dienstausfall; die Schwachstellen-Sicht war blind und
|
||||
sah dabei perfekt aus) · **Dauer:** ~00:20 bis ~00:40 · **Ursache:** eigener
|
||||
Entwurfsfehler in Code vom Vortag
|
||||
|
||||
## What was planned / expected
|
||||
|
||||
Nach dem k3s-Patch sollte eine Scan-Runde die neuen Fassungen aufnehmen und die
|
||||
alten Berichte abräumen. Erwartet: Zielmenge bleibt 54, sechs `rancher/*`-Ziele
|
||||
tauschen ihre Fassung, `cve_targets_orphaned` steigt kurz und fällt wieder.
|
||||
|
||||
## What happened
|
||||
|
||||
Der k3s-Neustart nahm kube-state-metrics und Alloys Log-Tailer mit. Beide kamen
|
||||
**nicht von selbst zurück** — ksm hing im CrashLoop, Alloy protokollierte
|
||||
`"tailer stopped; will retry"` und lieferte danach nichts mehr. Damit war
|
||||
`kube_pod_container_info` in Prometheus für rund zwölf Minuten **leer**.
|
||||
|
||||
Genau in dieses Fenster fiel die stündliche Herleitung der Zielmenge.
|
||||
|
||||
```
|
||||
Cluster-Quelle: 39 Ziele -> 0 (Abfrage erfolgreich, null Zeilen)
|
||||
Betriebs-Host: 12 Ziele -> 12
|
||||
Registry: 7 Ziele -> 0
|
||||
Soll gesamt: 54 -> 12
|
||||
```
|
||||
|
||||
Der Exporter schrieb `targets.txt` mit 12 Zeilen. Die Scan-Runde las die Datei
|
||||
und **löschte jeden Bericht, dessen Ziel nicht mehr darin stand — 42 Stück.**
|
||||
|
||||
Danach meldete die Anlage:
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| `cve_target_coverage_ratio` | **1,0** |
|
||||
| `cve_targets_missing` | **0** |
|
||||
| `cve_targets_orphaned` | **0** |
|
||||
| `cve_critical_offen` | **0** |
|
||||
| CRITICAL / HIGH | 99 / 1392 → **9 / 286** |
|
||||
|
||||
⚠️ **Die Zahlen sahen makellos aus, weil die Daten weg waren.**
|
||||
|
||||
Behoben durch Neustart des Exporters (Zielmenge zurück auf 54, mit den neuen
|
||||
k3s-Fassungen) und eine zweite Scan-Runde. Verloren sind nur die
|
||||
Erstfund-Zeitstempel der 42 Ziele.
|
||||
|
||||
## Why the difference
|
||||
|
||||
**Routing-Klasse: spec issue.** Der Code tat, was er sollte; was er sollte, war
|
||||
falsch gedacht.
|
||||
|
||||
Die Herleitung kennt zwei Ausgänge — Erfolg und Ausnahme. **Sie kennt den
|
||||
dritten nicht: erfolgreich und leer.** Eine PromQL-Abfrage gegen eine Datenbank
|
||||
ohne Daten ist kein Fehler; sie liefert null Zeilen und HTTP 200.
|
||||
|
||||
Und die drei Absicherungen, die ich am Vortag genau gegen „still schrumpfende
|
||||
Zielmenge" gebaut hatte, greifen alle daneben — jede aus einem für sich
|
||||
vertretbaren Grund:
|
||||
|
||||
| Regel | warum sie schwieg |
|
||||
|---|---|
|
||||
| `CveTargetsNoneDesired` | prüft die **Gesamtzahl** auf 0. Sie war 12. |
|
||||
| `CveTargetSourceStale` | prüft den **Zeitstempel**. Ein leerer Erfolg erneuert ihn. |
|
||||
| Wache `brauchbar` | prüft die **Vereinigung** auf „nicht leer", nicht jede Quelle. |
|
||||
|
||||
Die Lücke saß exakt zwischen den dreien. Alle drei zusammen decken „alles weg"
|
||||
und „nichts mehr gehört" ab — **nicht** „zwei von drei Quellen liefern nichts,
|
||||
und das gilt als Erfolg".
|
||||
|
||||
⚠️ **Der zweite Fehler ist der ältere:** Auch bei einer echten Ausnahme setzte
|
||||
die Herleitung die Ziele der Quelle auf `set()`. Ein Prometheus-Ausfall hätte
|
||||
also denselben Schaden angerichtet — nur wäre dann wenigstens der Zeitstempel
|
||||
gealtert.
|
||||
|
||||
## Learnings
|
||||
|
||||
- ⚠️ **„Erfolgreich" und „brauchbar" sind zwei verschiedene Aussagen.** Bei
|
||||
jeder Abfrage, deren Ergebnis eine Menge ist, gehört die leere Menge
|
||||
ausdrücklich behandelt — und zwar mit der Frage „hat diese Quelle vorher
|
||||
schon einmal geliefert?".
|
||||
- **Absicherungen, die einzeln richtig sind, lassen zusammen eine Lücke.** Drei
|
||||
Regeln gegen dieselbe Gefahr sind kein Beweis, dass die Gefahr abgedeckt ist.
|
||||
Was fehlt, ist der Fall dazwischen — und den findet man nicht durch Nachdenken
|
||||
über die Regeln, sondern durch das Ereignis.
|
||||
- ⚠️ **Ein Werkzeug, das Zustand löscht, braucht eine strengere Eingangsprüfung
|
||||
als eines, das nur meldet.** Der Scanner löscht Berichte anhand einer Liste,
|
||||
die er nicht selbst verantwortet. Ein Einbruch dieser Liste hätte ihn stutzig
|
||||
machen müssen, nicht nur den Exporter.
|
||||
- **Der Schaden wäre ohne Nachmessen unbemerkt geblieben.** Ich habe ihn nur
|
||||
gesehen, weil ich nach dem k3s-Sprung die Zielmenge von Hand geprüft habe.
|
||||
Ein Blick aufs Dashboard hätte „alles grün" gezeigt.
|
||||
|
||||
## Actions
|
||||
|
||||
- [x] **Leerer Erfolg gilt als Ausfall**, wenn die Quelle vorher geliefert hat:
|
||||
alter Stand bleibt, Zeitstempel altert, `CveTargetSourceStale` greift
|
||||
(`9a3b1d1`).
|
||||
- [x] **Eine Ausnahme verliert die Ziele der Quelle nicht mehr** — vorher
|
||||
`set()`, jetzt der letzte bekannte Stand.
|
||||
- [x] **Fünfte Regel `CveZielmengeEingebrochen`**: Rückgang um mehr als 40 %
|
||||
gegenüber 24 h. Feuert bewusst auch bei gewolltem Rückbau.
|
||||
- [x] Fünf Zusicherungen gegen die echte `herleiten()`, drei Sabotagen fahren
|
||||
sie rot.
|
||||
- [ ] **Offen:** Der Fix ist **nicht ausgerollt**. Auf dem Host läuft weiter die
|
||||
Fassung, die einen leeren Erfolg für einen Erfolg hält.
|
||||
- [ ] **Offen:** Nichts meldet, wenn kube-state-metrics oder Alloys Tailer nach
|
||||
einem Neustart nicht zurückkommen. Zwölf Minuten ohne Cluster-Logs sind
|
||||
niemandem aufgefallen — auch das gehört gemeldet, und zwar unabhängig von
|
||||
der CVE-Kette.
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
type: adr
|
||||
id: "0028"
|
||||
status: accepted
|
||||
date: 2026-08-23
|
||||
supersedes: null
|
||||
superseded_by: null
|
||||
related:
|
||||
- "docs/design/done/2026-08-22-k3s-patch-1-34-10.md"
|
||||
- "docs/issues/0110-haertung-lebt-auf-dem-host-das-repo-weiss-nichts-davon.md"
|
||||
---
|
||||
|
||||
# ADR-0028: Der Ingress bleibt vorerst k3s-verwaltet — die drei nie wirksamen Flags werden gestrichen
|
||||
|
||||
## Kontext
|
||||
|
||||
Die systemd-Unit des Clusters trug seit der Installation am 2026-04-21
|
||||
unverändert diese Startzeile:
|
||||
|
||||
```
|
||||
/usr/local/bin/k3s server server --disable=traefik --disable=servicelb --node-ip=10.0.0.2
|
||||
```
|
||||
|
||||
⚠️ **`server` steht zweimal.** Das zweite ist ein Positionsargument; alles
|
||||
danach wird nicht mehr als Flag gelesen. Vier Monate lang hat also **keines**
|
||||
der drei Flags gewirkt. Belegt am laufenden System, nicht hergeleitet:
|
||||
|
||||
| Beleg | Wert |
|
||||
|---|---|
|
||||
| `k3s.io/node-args` | `["server","server","--disable","traefik","--disable","servicelb","--node-ip","10.0.0.2"]` |
|
||||
| `k3s.io/internal-ip` | `49.13.132.245` — die **öffentliche** Adresse |
|
||||
| `server/manifests/` | enthält `traefik.yaml`, geschrieben beim letzten Start |
|
||||
| Cluster | Traefik **und** `svclb-traefik` laufen |
|
||||
|
||||
Aufgefallen ist das beim Vorbereiten des Patches auf v1.34.10, weil das
|
||||
Installationsskript die Unit **neu schreibt**. Damit stand die Frage nicht mehr
|
||||
offen: Was in der neuen Zeile steht, wird beim nächsten Start wirksam — und
|
||||
zwar sofort und vollständig.
|
||||
|
||||
## Optionen
|
||||
|
||||
**A — Die Flags streichen, den Ist-Zustand zur Absicht machen.** Traefik und
|
||||
servicelb bleiben k3s-verwaltet; `--node-ip` wird bewusst gesetzt, weil es ein
|
||||
echter Parameter ist und der Knoten sonst weiter seine öffentliche Adresse als
|
||||
`InternalIP` führt.
|
||||
|
||||
**B — Die Flags wirksam machen.** Setzt voraus, dass vorher ein Ersatz für den
|
||||
Ingress bereitsteht. Ohne den heißt „wirksam" schlicht: **kein eingehender
|
||||
Verkehr mehr**, `axion1337.chat` und `wiki.axion1337.chat` inbegriffen.
|
||||
|
||||
**C — Die kaputte Zeile wörtlich erhalten.** Das Installationsskript müsste
|
||||
daran gehindert werden, und der nächste Mensch stolpert genauso.
|
||||
|
||||
## Entscheidung
|
||||
|
||||
**A**, mit zwei Ergänzungen, die beim Ausarbeiten dazukamen:
|
||||
|
||||
```
|
||||
k3s server --node-ip=10.0.0.2 --node-external-ip=49.13.132.245 --tls-san=49.13.132.245
|
||||
```
|
||||
|
||||
- ⚠️ **`--node-external-ip`**, weil `servicelb` die Knoten-Adresse
|
||||
veröffentlicht: der Traefik-Dienst **und jeder Ingress** trugen bis dahin
|
||||
`49.13.132.245`. Ohne dieses Flag stünde dort künftig `10.0.0.2`.
|
||||
- ⚠️ **`--tls-san`**, weil die SANs des API-Zertifikats `10.0.0.2` nicht
|
||||
enthielten. Beim Adresswechsel wird es neu erzeugt; ohne das Flag kann die
|
||||
öffentliche Adresse herausfallen — und die Kubeconfig zeigt genau dorthin.
|
||||
|
||||
Beide waren in der ersten Fassung dieser Entscheidung **nicht** enthalten und
|
||||
kamen erst durch Nachsehen dazu. Das gehört hierhin, weil es zeigt, dass
|
||||
„einen Parameter setzen" bei k3s selten nur einen Parameter betrifft.
|
||||
|
||||
## Konsequenzen
|
||||
|
||||
- Der Ingress gehört **k3s**, nicht dem Repo. Wer ihn ändern will, ändert
|
||||
k3s-Vorgaben oder legt eine `HelmChartConfig` an — heute existiert keine.
|
||||
- Der Knoten führt endlich eine private `InternalIP` und eine öffentliche
|
||||
`ExternalIP`. Die öffentliche **IPv6** verliert dabei ihre Rolle als
|
||||
`InternalIP`; die Pod-Netze sind ohnehin IPv4-only.
|
||||
- ⚠️ **Option B bleibt der nachhaltigere Weg und ist nicht verworfen, sondern
|
||||
vertagt.** Traefik unter Flux wäre im Repo statt in einem Binary — genau die
|
||||
Richtung, in die dieses Projekt sonst geht. Es braucht einen eigenen Zuschnitt
|
||||
mit eigenem Ausfallfenster, nicht eine Zeile in einem Patch-Upgrade. Wer das
|
||||
angeht, setzt danach `--disable=traefik --disable=servicelb` — und dann sind
|
||||
sie zum ersten Mal wirklich gemeint.
|
||||
- ⚠️ **Die Unit liegt weiterhin in keinem Repository.** Diese Entscheidung
|
||||
beschreibt sie, sie versioniert sie nicht. Das ist der Cluster-Anteil von
|
||||
[#0110](../issues/0110-haertung-lebt-auf-dem-host-das-repo-weiss-nichts-davon.md).
|
||||
|
||||
## Warum das aufgeschrieben wird
|
||||
|
||||
Ohne diesen Eintrag schreibt der nächste Mensch die Flags aus guter Absicht
|
||||
zurück — sie sahen ja vernünftig aus. Und die vier Monate, in denen sie nichts
|
||||
taten, sind kein Argument gegen sie, sondern gegen die Annahme, eine
|
||||
Konfigurationsdatei beschreibe den Zustand, den sie beschreibt.
|
||||
+54
-2
@@ -1,6 +1,6 @@
|
||||
---
|
||||
type: design
|
||||
status: gate-4
|
||||
status: done
|
||||
date: 2026-08-22
|
||||
size: L
|
||||
related:
|
||||
@@ -280,7 +280,7 @@ Helm-Wert, keine Zeile in einem Repo.
|
||||
|
||||
⚠️ **Und das ist selbst ein Befund.** Die gesamte Konfiguration dieses Clusters
|
||||
steht in einer Unit auf einem Host und in **keinem** Repository. Genau die
|
||||
Lücke, die [#0110](../issues/0110-haertung-lebt-auf-dem-host-das-repo-weiss-nichts-davon.md)
|
||||
Lücke, die [#0110](../../issues/0110-haertung-lebt-auf-dem-host-das-repo-weiss-nichts-davon.md)
|
||||
für den Betriebs-Stack beschreibt — hier trifft sie den Cluster selbst.
|
||||
|
||||
**Neue ExecStart-Zeile:**
|
||||
@@ -362,3 +362,55 @@ wird bewusst gesetzt." Mit Beleg, warum die Flags vier Monate lang nichts taten
|
||||
— sonst schreibt der Nächste sie aus guter Absicht zurück.
|
||||
|
||||
> **STOP — wartet auf Gate-3/4-Freigabe.**
|
||||
|
||||
## Gate 5 — Abnahme
|
||||
|
||||
Durchgeführt 2026-08-23, 00:11:44 CEST. Der Dienst war von der Sicherung bis
|
||||
zum Start unten; alle Container waren binnen ~70 s wieder oben.
|
||||
|
||||
| | Kriterium | Ergebnis |
|
||||
|---|---|---|
|
||||
| 1 | v1.34.10+k3s1, sechs Komponenten auf den mitgelieferten Fassungen | ✅ alle sechs, dazu containerd 2.2.2 → **2.2.5-k3s2** |
|
||||
| 2 | −15 CRITICAL, **−189 HIGH** auf den Komponenten; die sechs Einträge entfernt | ✅ **278 → 89 HIGH, 15 → 0 CRITICAL**, exakt die Vorhersage; Einträge entfernt |
|
||||
| 3 | Plattform vollständig oben | ✅ nur der `concierge-bot`, der schon 13 Tage vorher an einem fehlenden Secret hing |
|
||||
| 4 | Ingress von außen mit gültigem Zertifikat | ✅ sechs Hosts, alle TLS-verify 0; `_matrix/client/versions` 200, MAS-OIDC 200 |
|
||||
| 5 | NetworkPolicies passen noch | ✅ sie verweisen auf `kube-system` per Label — unberührt |
|
||||
| 6 | Rückweg vor dem Start hergestellt | ✅ Binary, Unit und 60-MB-`db` geprüft vorhanden |
|
||||
|
||||
**Die zwei nachgezogenen Flags haben getan, wofür sie da waren:** Der
|
||||
Traefik-Dienst und jeder Ingress veröffentlichen weiterhin `49.13.132.245`
|
||||
(`--node-external-ip`), und die Zertifikats-SANs tragen jetzt **beide**
|
||||
Adressen, `kubectl` von außen antwortet `ok` (`--tls-san`).
|
||||
|
||||
### ⚠️ Zwei Bauteile kamen nicht von selbst zurück
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **kube-state-metrics** | CrashLoop — startete, während die API noch nicht da war, und blieb im Backoff. Pod neu → läuft. |
|
||||
| **Alloys Log-Tailer** | ⚠️ **Zwölf Minuten ohne Cluster-Logs.** Das Protokoll sagte `"tailer stopped; will retry"` und lieferte danach nichts mehr. Pod neu → Logs 1 s alt. |
|
||||
|
||||
Beide fielen nur auf, weil nachgemessen wurde. Nichts hat gemeldet, dass die
|
||||
Log-Strecke des gesamten Clusters stillstand — der Betriebs-Host lieferte
|
||||
weiter, also sah die Überwachung lebendig aus.
|
||||
|
||||
### ⚠️ Und ein Vorfall, den dieser Sprung ausgelöst hat
|
||||
|
||||
Ebendieses Fenster ohne Cluster-Metriken traf die stündliche Herleitung der
|
||||
Scan-Zielmenge. Die Abfrage lief **erfolgreich und leer** durch, die Zielmenge
|
||||
fiel von 54 auf 12, und die folgende Scan-Runde löschte **42 Berichte** —
|
||||
während das Dashboard Deckung **1,0** meldete. Eigener AAR:
|
||||
`docs/aar/2026-08-23-zielmenge-eingebrochen.md`. Behoben, abgesichert, und der
|
||||
Fix wartet auf das Ausrollen.
|
||||
|
||||
**Das ist die eigentliche Lehre dieses Vorhabens.** Der Fassungssprung selbst
|
||||
war so unspektakulär wie geplant. Teuer war, was ein Neustart in den *anderen*
|
||||
Bauteilen auslöst — und dass zwei davon ihr eigenes Scheitern als „retry"
|
||||
protokollieren.
|
||||
|
||||
### Was noch aussteht
|
||||
|
||||
- Der Fix an der Herleitung ist gepusht (`9a3b1d1`), aber **nicht ausgerollt**.
|
||||
- Nichts meldet, wenn die Cluster-Log-Strecke stillsteht.
|
||||
- Option B aus [ADR-0028](../../adr/0028-ingress-bleibt-k3s-verwaltet-flags-gestrichen.md)
|
||||
— Traefik unter Flux — bleibt der nachhaltigere Weg und ist vertagt, nicht
|
||||
verworfen.
|
||||
@@ -2,9 +2,9 @@
|
||||
type: ledger
|
||||
date: 2026-08-22
|
||||
size: L
|
||||
status: open
|
||||
status: closed
|
||||
related:
|
||||
- "docs/design/2026-08-22-k3s-patch-1-34-10.md"
|
||||
- "docs/design/done/2026-08-22-k3s-patch-1-34-10.md"
|
||||
- "docs/issues/0051-cve-remediation-pass.md"
|
||||
---
|
||||
|
||||
@@ -17,11 +17,18 @@ related:
|
||||
| 1 | bf2d87a | sorb | DONE | Umfang, sechs Abnahmekriterien, zwei offene Entscheidungen (Ausfallzeit, Traefik-Chart-Major); ⚠️ korrigiert die eigene Aussage „grosses Vorhaben" — es ist ein Patch auf der eigenen Minor-Reihe. |
|
||||
| 2 | 1d0d5f1 | sorb | DONE_WITH_CONCERNS | Fassungen gepinnt, Traefik-Major gerendert (identisch), Ausfallzeit aus der Historie gemessen (~70 s); ⚠️ Fund: drei k3s-Flags sind seit der Installation unwirksam, und das Installationsskript schreibt die Unit neu. |
|
||||
| 3+4 | 3e55a42 | sorb | DONE | Eine Datei, sechs Slices; ExecStart um `--node-external-ip` und `--tls-san` ergaenzt, weil `--node-ip` allein die veroeffentlichte Adresse und das API-Zertifikat mitreisst. |
|
||||
| 5 | PENDING | sorb | DONE_WITH_CONCERNS | Alle sechs Kriterien erfuellt, 278 -> 89 HIGH und 15 -> 0 CRITICAL exakt wie vorhergesagt; ⚠️ der Neustart hat zwei Bauteile lahmgelegt und einen Vorfall an der Scan-Zielmenge ausgeloest. |
|
||||
|
||||
## Slices
|
||||
|
||||
| slice | commit | status | note |
|
||||
|---|---|---|---|
|
||||
| 0 Vorher-Bild | — | DONE | Knoten, Pods, SANs, Ingress-Antworten, CVE-Zahlen festgehalten; Images vorgezogen. |
|
||||
| 1 Sicherung | — | DONE | Binary, Unit und 60-MB-`db` bei gestopptem Dienst; unabhaengig nachgesehen, nicht auf Zuruf geglaubt. |
|
||||
| 2 Installation | — | DONE | Mit `SKIP_START`; die geschriebene Unit gelesen: `server` einmal, kein `--disable`, drei Flags. |
|
||||
| 3 Start | — | DONE | 00:11:44, alle Container binnen ~70 s oben. |
|
||||
| 4 Abnahme | — | DONE_WITH_CONCERNS | Sechs Kriterien erfuellt; ⚠️ ksm im CrashLoop und Alloys Tailer tot, beide von Hand nachgestartet. |
|
||||
| 5 Nacharbeit | 9a3b1d1 | DONE | Sechs `rancher/*`-Entscheidungen entfernt; Herleitung gegen leere Antworten gehaertet, fuenfte Alarmregel. |
|
||||
|
||||
## Ladder
|
||||
|
||||
@@ -37,6 +44,8 @@ related:
|
||||
| wie lange ein k3s-Neustart wirklich kostet, statt „einige Minuten" zu schaetzen | der Neustart vom 2026-08-01 steht in den Container-Startzeiten: 19:37:06 Dienst, 19:38:14 letzter Container | reused: die eigene Historie als Messung — ~70 s statt einer Vermutung, und kein Pod-Objekt wurde neu erzeugt | |
|
||||
| was der Adresswechsel sonst anfasst, statt nur an die Kubeconfig zu denken | `servicelb` veroeffentlicht die Knoten-Adresse: der Traefik-Dienst UND jeder Ingress tragen heute 49.13.132.245 — ohne `--node-external-ip` stuende dort kuenftig 10.0.0.2 | built: die ExecStart-Zeile traegt jetzt drei Flags statt einem; der Fund kam aus dem Nachsehen, nicht aus dem Nachdenken | |
|
||||
| ob Alloy oder cert-manager an der Knoten-Adresse haengen | Alloy scrapt ausschliesslich `role = "pod"`, kein Kubelet, keine Knoten-Rolle; cert-manager loest HTTP01 ueber den oeffentlichen Namen | reused: die eigene Konfiguration als Pruefmassstab — zwei vermutete Risiken sind damit gegenstandslos, statt sie vorsorglich zu behandeln | |
|
||||
| warum die Zielmenge nach dem Sprung auf 12 stand, statt es fuer einen Uebergang zu halten | die Cluster-Abfrage war ERFOLGREICH und LEER — ksm und Alloy waren beim Neustart ausgefallen; der leere Erfolg erneuerte den Zeitstempel und keine der drei Regeln schlug an | built: leerer Erfolg gilt als Ausfall, Ausnahme verliert die Ziele nicht mehr, fuenfte Regel auf den Einbruch der Gesamtmenge | 9a3b1d1 |
|
||||
| ob Alloys „will retry" tatsaechlich retried | nein — zwoelf Minuten ohne eine einzige Cluster-Logzeile, waehrend der Betriebs-Host weiterlieferte und alles lebendig aussah | reused: Loki als Messpunkt statt des Protokolltextes; ein Bauteil, das sein Scheitern als „retry" meldet, ist von einem gesunden nicht zu unterscheiden | |
|
||||
| ob die Unit ueberhaupt das tut, was sie sagt | NEIN: `server` steht zweimal in ExecStart, alles danach wird als Positionsargument gelesen. `k3s.io/node-args` fuehrt die Flags, `k3s.io/internal-ip` zeigt die oeffentliche Adresse, `traefik.yaml` ist ausgerollt | built: nichts — aber der Fund bestimmt das ganze Vorhaben: das Installationsskript schreibt die Unit neu, und dann werden drei seit vier Monaten stille Flags scharf | |
|
||||
|
||||
## Notes
|
||||
@@ -54,3 +63,16 @@ eine gar nicht erst gestellte Frage.
|
||||
|
||||
**Kein Issue dahinter** — sorb hat den Posten aus einer Liste gewaehlt. Ob er
|
||||
einen bekommt, entscheidet sorb; ohne Zustimmung wird keiner angelegt.
|
||||
|
||||
⚠️ **Der Sprung selbst war unspektakulaer; teuer war, was ein Neustart in den
|
||||
ANDEREN Bauteilen ausloest.** kube-state-metrics blieb im CrashLoop haengen,
|
||||
Alloys Log-Tailer starben und meldeten das als „will retry", und die
|
||||
Scan-Zielmenge brach ein, weil eine leere Antwort als Erfolg zaehlte. Keines
|
||||
dieser drei Dinge stand in der Risikoliste von Gate 1 oder Gate 2 — dort stand
|
||||
der Traefik-Chart-Major, und der war ein Nicht-Ereignis.
|
||||
|
||||
**Die Lehre ist nicht „mehr Risiken auflisten".** Sie ist: Ein Neustart der
|
||||
Steuerebene prueft alles, was sich auf sie stuetzt — und was dabei nicht von
|
||||
selbst zurueckkommt, meldet sich in aller Regel nicht.
|
||||
|
||||
Eigener AAR zum Vorfall: `docs/aar/2026-08-23-zielmenge-eingebrochen.md`.
|
||||
|
||||
@@ -28,6 +28,33 @@ verschiedenen Werkzeugen. Deshalb steht sie hier und nicht in einzelnen Issues.
|
||||
|
||||
## Die belegten Vorkommen
|
||||
|
||||
### Nachtrag 2026-08-23 — zwei neue Vorkommen an einem Abend
|
||||
|
||||
⚠️ **Diese Seite ist als „geerntet" markiert. Sie ist es nicht.** Die Regel, die
|
||||
das Rahmenwerk daraus gemacht hat („eine Prüfung schuldet den Beweis, dass sie
|
||||
rot werden kann"), deckt die beiden folgenden Fälle **nicht** ab — beide
|
||||
Prüfungen *konnten* rot werden und waren es nachweislich schon. Sie schwiegen
|
||||
trotzdem.
|
||||
|
||||
**1. Der leere Erfolg.** Eine PromQL-Abfrage gegen eine Datenbank ohne Daten
|
||||
liefert HTTP 200 und null Zeilen. Die Herleitung der Scan-Ziele kannte nur
|
||||
„Erfolg" und „Ausnahme" — der dritte Ausgang fehlte. Ergebnis: Zielmenge 54 → 12,
|
||||
**42 gelöschte Berichte**, Dashboard meldet Deckung 1,0.
|
||||
Siehe `docs/aar/2026-08-23-zielmenge-eingebrochen.md`.
|
||||
|
||||
**2. „will retry" ohne retry.** Alloys Log-Tailer verloren beim k3s-Neustart die
|
||||
Verbindung zur API, protokollierten `"tailer stopped; will retry"` — und
|
||||
lieferten danach nichts mehr. Zwölf Minuten ohne Cluster-Logs, ohne dass etwas
|
||||
gemeldet hätte. Ein Bauteil, das sein eigenes Scheitern als Wiederholungsversuch
|
||||
beschreibt, ist von einem gesunden **am Protokoll nicht zu unterscheiden**.
|
||||
|
||||
**Was beide Fälle gemeinsam haben und die geerntete Regel nicht trifft:** Nicht
|
||||
die Prüfung war blind, sondern **ihre Eingangsdaten waren leer und das galt als
|
||||
gültig**. Die nächste Iteration braucht dafür eine eigene Formulierung — etwa:
|
||||
*Wer aus einer Menge ableitet, behandelt die leere Menge ausdrücklich; „nichts
|
||||
gefunden" und „nicht nachgesehen" sind verschiedene Ergebnisse.*
|
||||
|
||||
|
||||
| Wo | Was meldete Erfolg | Was tatsächlich geschah |
|
||||
|---|---|---|
|
||||
| LiveKit `setProcessor` | Prozessor geladen, 23 MB Modell aktiv | `sender?.replaceTrack` übersprang den Tausch stumm — das rohe Mikrofon blieb auf der Leitung |
|
||||
|
||||
Reference in New Issue
Block a user