docs: Betriebshandbuch §8–§13 (Zugang, Benachrichtigungen, Firewall, Zertifikat, Netzwerk, Testvorgehen), healthcheck.sh, Plan Phase 4 erledigt
ci / test (push) Successful in 27s
ci / test (push) Successful in 27s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
47ad1580ff
commit
97bbb58433
+70
-1
@@ -1,4 +1,4 @@
|
||||
# Betrieb: Skill-Lebenszyklus, Hermes, Pflege, Freischaltung
|
||||
# Betrieb: Skill-Lebenszyklus, Hermes, Pflege, Freischaltung, Proxmox-Cluster
|
||||
|
||||
## 1. Lebenszyklus eines Skills
|
||||
|
||||
@@ -141,3 +141,72 @@ Nach `zfs receive` (Replikation) liefert ein Knoten für Dateien, die dort früh
|
||||
2. Die defekte Datenbank bzw. das Verzeichnis beiseiteschieben, z. B. `mv /var/lib/docker/buildkit /var/lib/docker/buildkit.defekt-<datum>`.
|
||||
3. `systemctl start docker`, dann `docker compose -p knaster-infra --env-file /opt/knaster/infra/.env -f /opt/knaster/repo/deploy/compose/infra/docker-compose.yml up -d --force-recreate` (Volumes bleiben, kein `down -v`).
|
||||
4. Danach auf ops `ansible-playbook playbooks/monitoring.yml --limit infra`.
|
||||
|
||||
## 8. Zugang: Benutzer, Rollen, 2FA, Token (Phase 4.1/4.2)
|
||||
|
||||
Stand 13.10.2026, Quelle `sites/knaster/proxmox.yaml` (`access`), ausgerollt mit `playbooks/cluster.yml` (Rolle `pve-cluster`).
|
||||
|
||||
| Konto | Zweck | Rechte | Geheimnis liegt |
|
||||
|---|---|---|---|
|
||||
| `r.rapp@pve` | persönlicher Admin (Weboberfläche) | Gruppe `admins` = Administrator auf `/` | Passwort `PVE_ADMIN_R_RAPP_PASS` in `it/proxmox/.env`, TOTP + Recovery-Keys in `it/proxmox/tfa-r.rapp.txt` |
|
||||
| `root@pam` | Notfallzugang, SSH-Schlüssel, Ansible | alles | Passwörter `PVExx_PASS` in `.env`, Schlüssel `keys/id_ed25519_pve` |
|
||||
| `tofu@pve!ops` | OpenTofu auf ops | VM-, Storage-, Mapping-, Pool-Rechte | ops `/root/.config/knaster/tofu.env` |
|
||||
| `monitoring@pve!prom` | pve-exporter | PVEAuditor | ops `/root/.config/knaster/pve-exporter.env`, Kopie in infra |
|
||||
| `healer@pve!knaster` | Healer (SPEC-healer) | Rolle `KnasterHealer` (`VM.PowerMgmt`, `VM.Audit`) nur auf `/pool/gpu` | ops `/root/.config/knaster/healer.env` |
|
||||
|
||||
- **Anmeldung Weboberfläche:** Benutzer `r.rapp`, Realm „Proxmox VE authentication server“, danach TOTP-Code. Die Recovery-Keys gelten je einmal.
|
||||
- **TOTP einrichten:** `it/proxmox/tfa-r.rapp.txt` enthält die otpauth-URI und das Secret. In der Authenticator-App „manuell eingeben“ (Secret, 6 Stellen, 30 s) oder aus der URI einen QR-Code erzeugen.
|
||||
- **Neues Admin-Konto:** Name in `access.admin_users` eintragen, `playbooks/cluster.yml` auf ops, dann vom Laptop `platform/proxmox/scripts/pve-admin-user.sh <name>` (setzt Passwort, TOTP, Recovery-Keys; idempotent).
|
||||
- **2FA für root@pam** ist bewusst nicht gesetzt: root bleibt Notfallzugang und läuft über SSH-Schlüssel. Wenn gewünscht, gleiches Vorgehen über `pvesh create /access/tfa/root@pam` – vorher den Code in einer App haben, sonst sperrt man sich aus der Weboberfläche aus (SSH bleibt).
|
||||
- **Token rotieren:** `pveum user token remove <user> <token>`, Datei auf ops löschen, Playbook erneut (Healer) bzw. Token neu anlegen und Datei schreiben (tofu, monitoring).
|
||||
- Verloren gegangenes TOTP: `pvesh get /access/tfa/<user>` listet die Einträge, `pvesh delete /access/tfa/<user>/<id>` entfernt sie, danach das Skript erneut.
|
||||
|
||||
## 9. Benachrichtigungen (Phase 4.3)
|
||||
|
||||
Ziel `knaster-mail` (Sendmail an `ki@mygodel.de`, aus `access.mail_to`), Matcher `knaster-alles` ohne Filter (Backup, Fencing, Replikation, Paket-Updates), `default-matcher` abgeschaltet (sonst doppelt). Postfix auf den Knoten liefert direkt an die MX von mygodel.de (13.10. getestet: `250 … Queued mail for delivery`). Kein SMTP-Relay, keine Zugangsdaten.
|
||||
|
||||
- Test: `pvesh create /cluster/notifications/targets/knaster-mail/test` auf einem Knoten, Zustellung im Journal: `journalctl -u postfix --since -10min | grep status=`.
|
||||
- Landet die Mail im Spam: Absender `root@pveXX.buero-godel.local` hat kein SPF. Dann in Exchange Online eine Transportregel oder einen Connector für die Knoten-IPs anlegen.
|
||||
- Empfänger ändern: `access.mail_to` in der Site-Datei, dann `pvesh set /cluster/notifications/endpoints/sendmail/knaster-mail --mailto <adresse>` (das Playbook legt nur an, es ändert bestehende Ziele nicht).
|
||||
|
||||
## 10. Firewall (Phase 4.4)
|
||||
|
||||
Datacenter-Firewall aktiv auf allen Knoten (`/etc/pve/firewall/cluster.fw`, Vorlage `roles/pve-cluster/templates/cluster.fw.j2`). Eingehend DROP, ausgehend ACCEPT.
|
||||
|
||||
- **IPSET `admin`:** die fünf Knoten, Admin-Laptop `.151`, appsrv08 `.29`, ops `.173`, infra `.188`. Nur diese erreichen 22, 8006, 3128, 5900–5999 und 60000–60050. Alle anderen Adressen im LAN bekommen auf diesen Ports DROP, Ping aus dem LAN geht. Corosync zwischen den Knoten erlaubt Proxmox selbst.
|
||||
- **Warum eigene Regeln statt IPSET `management`:** Proxmox ergänzt `management` immer um das lokale Netz (`local_network`, hier das ganze /24). Eine Einschränkung auf einzelne Adressen wirkt deshalb nur mit ACCEPT für `+admin` und anschließendem DROP für das /24 (13.10. geprüft: aus einer GPU-VM sind 22 und 8006 zu, vom Laptop und aus infra offen).
|
||||
- **DHCP-Risiko (D5):** Laptop, ops und infra haben keine Reservierung. Wechselt eine Adresse, ist diese Quelle ausgesperrt. Rückweg: von einer noch zugelassenen Adresse (z. B. `ssh ops`, dann `ssh pve44`) die Adresse in `sites/knaster/proxmox.yaml` ändern und das Playbook laufen lassen, oder direkt `cluster.fw` bearbeiten. Letzter Rückweg: Konsole am Knoten, dort `pve-firewall stop` bzw. `enable: 0` in `cluster.fw`.
|
||||
- **Totmannschalter:** Das Playbook stellt bei jeder Änderung einen Timer (`knaster-fw-totmann`, 600 s), der `enable: 0` schreibt, und hebt ihn erst nach erfolgreicher Prüfung (SSH und 8006 zu allen Knoten von ops aus) wieder auf. Bricht der Lauf ab, geht die Firewall von selbst wieder aus.
|
||||
- Neue Verwaltungsquelle (z. B. zweiter Laptop): Eintrag unter `firewall.management`, Playbook laufen lassen.
|
||||
- Gast-Firewalls (VM/LXC) sind nicht aktiviert; die GPU-VMs schützen ihre Ports mit ufw (Abschnitt 7).
|
||||
|
||||
## 11. Zertifikat der Weboberfläche (Phase 4.6)
|
||||
|
||||
Die Knotenzertifikate stammen von der Cluster-CA (`/etc/pve/pve-root-ca.pem`, gültig bis 2036) und enthalten die IP-Adresse als SAN. Es reicht, die CA einmal auf dem Laptop als vertrauenswürdig einzutragen, dann sind `https://192.168.100.2xx:8006` für alle fünf Knoten ohne Warnung erreichbar.
|
||||
|
||||
- Kopie der CA: `it/proxmox/pve-root-ca.pem` (SHA-256 `A2:71:C0:AB:…:77:3E`, zum Abgleich `openssl x509 -in … -noout -fingerprint -sha256`).
|
||||
- Import ohne Adminrechte (Benutzerspeicher, Windows fragt einmal nach): `certutil -user -addstore Root C:\Users\r.rapp\it\proxmox\pve-root-ca.pem`. Danach Browser neu starten.
|
||||
- Kein ACME/Let's Encrypt: die Knoten haben keine öffentlichen Namen (IP-Regel, kein DNS).
|
||||
|
||||
## 12. Netzwerk-Prüfung (Stand 13.10.2026)
|
||||
|
||||
| Knoten | NIC | Treiber | Link | Bridge |
|
||||
|---|---|---|---|---|
|
||||
| pve44, pve46, pve48, pve52 | Intel onboard `nic0` | `e1000e` | 1 GBit/s | `vmbr0` → `nic0`, kein VLAN-aware |
|
||||
| pve61 | USB-NIC im Dock `enx3ce1a1c0839d` | `r8152` | 1 GBit/s | `vmbr0` → USB-NIC, ein Link-Reset seit Start |
|
||||
|
||||
- Keine `e1000e`-Hänger („Detected Hardware Unit Hang“) im Kernel-Log. Sollten sie auftreten: `ethtool -K nic0 tso off gso off` als bekannter Ausweg, dann in `/etc/network/interfaces` festhalten.
|
||||
- **VLAN:** nicht aktiviert (Global Constraint „vorerst kein VLAN“). Wenn nötig: `bridge-vlan-aware yes` und `bridge-vids 2-4094` auf `vmbr0`, `ifreload -a`; auf pve61 nur vor Ort (USB-NIC).
|
||||
- Eine zweite NIC für ein getrenntes Corosync- oder Migrationsnetz gibt es auf keinem Knoten. Migration läuft `secure` über das LAN.
|
||||
- Feste Adressen: Knoten sind statisch, Gäste und Laptop per DHCP (D5 offen, Task 0.2). Erst mit Reservierungen ist die Firewall-Liste dauerhaft stabil.
|
||||
|
||||
## 13. Testvorgehen
|
||||
|
||||
`platform/proxmox/scripts/healthcheck.sh` (Laptop oder ops, nur lesend) prüft in einem Lauf: Quorum und Stimmen, HA-Dienste, Replikation, Firewall aktiv und Regel `+admin`, Matcher, Benutzer und 2FA; je Knoten Kernel, fehlgeschlagene Dienste, Knoten-Firewall, NTP, `vmbr0`, Platz auf `/`, `tank`, Zertifikatslaufzeit, GPU-Bindung an `vfio-pci`, NIC-Hänger, Weboberfläche; dazu den Negativtest aus einer GPU-VM. Ausgabe `OK`/`FEHLER` je Prüfung, Exit 1 bei Fehlern.
|
||||
|
||||
Wann laufen lassen:
|
||||
1. Nach jedem Playbook-Lauf gegen die Knoten (`site.yml`, `cluster.yml`) und nach jedem Neustart (Abschnitt 6, Schritt 5).
|
||||
2. Vor einer Änderung an Firewall, Benutzern oder Netzwerk als Vergleichsbasis.
|
||||
3. Wöchentlich als Routine; Grafana (Abschnitt 7) deckt den Rest kontinuierlich ab.
|
||||
|
||||
Manuelle Ergänzungen, die das Skript nicht abdeckt: Anmeldung mit `r.rapp@pve` und TOTP in der Weboberfläche, Testmail (Abschnitt 9), Dock-Test an pve61 (Task 1.3, vor Ort), Wartungsmodus-Probe (Abschnitt 6).
|
||||
|
||||
@@ -128,7 +128,7 @@ Ersetzt PLAN §8 „0 Fundament“ (Teil Inventar) und IMPLEMENTATION „Gemeins
|
||||
|
||||
**Wo:** remote (DHCP-Server, vermutlich DC `.120` oder UniFi) · **Planner:** „PVE-Config: Netzwerk prüfen – Bridge, VLAN-Fähigkeit und NIC-Kompatibilität“
|
||||
|
||||
- [ ] DHCP-Bereich auslesen. Für .207, .209, .210, .212 und .214 Reservierungen auf die MACs der Knoten anlegen (MACs stehen im Healthcheck). Ebenso eine Reservierung für den Admin-Laptop (heute .151 per WLAN). Die Firewall in 4.4 lässt nur diese Adresse zu, ein Lease-Wechsel würde sonst aussperren.
|
||||
- [ ] DHCP-Bereich auslesen. **Seit 13.10. dringender:** Die Firewall (4.4) lässt nur .151 (Laptop), .173 (ops) und .188 (infra) an die Verwaltungsports; ein Lease-Wechsel sperrt die Quelle aus (BETRIEB §10). Für .207, .209, .210, .212 und .214 Reservierungen auf die MACs der Knoten anlegen (MACs stehen im Healthcheck). Ebenso eine Reservierung für den Admin-Laptop (heute .151 per WLAN). Die Firewall in 4.4 lässt nur diese Adresse zu, ein Lease-Wechsel würde sonst aussperren.
|
||||
- [ ] Gäste-Block festlegen (Vorschlag `.220–.239`) und als Ausschluss im DHCP eintragen.
|
||||
Prüfung: `ping` auf jede Adresse des Blocks → keine Antwort. DHCP-Ausschluss sichtbar.
|
||||
|
||||
@@ -304,12 +304,12 @@ Ersetzt GPU-Knoten 3 (Teil Cluster). Mit 5 Stimmen ist **kein QDevice** nötig.
|
||||
|
||||
**Wo:** remote. Jede Aufgabe hier entspricht einer Planner-Aufgabe.
|
||||
|
||||
- [ ] **4.1 Benutzer und Token** (12.10. teilweise: `tofu@pve!ops` mit engen ACLs und `monitoring@pve!prom` (PVEAuditor, Geheimnis nur auf ops `/root/.config/knaster/pve-exporter.env`) angelegt; offen: persönlicher Admin-Benutzer (Name vom Nutzer), `healer@pve!knaster`) („PVE-Config: Persönlicher Admin-Benutzer, Rollen und API-Token anlegen“): Admin-Benutzer und Gruppe, root@pam nur als Notfallzugang. Token `monitoring@pve!prom` (PVEAuditor), `healer@pve!knaster` (nur `VM.PowerMgmt` auf GPU-VMs, PLAN §3), `tofu@pve!ops`.
|
||||
- [ ] **4.2 2FA** („PVE-Config: Zwei-Faktor-Authentifizierung für Admin-Konten aktivieren“): TOTP für root@pam und Admin. Recovery-Keys offline ablegen.
|
||||
- [ ] **4.3 Benachrichtigungen** („PVE-Config: Benachrichtigungen (Notification Center) einrichten“): SMTP-Ziel Büro-Postfach, Matcher für Backup, Fencing und Updates. Testnachricht kommt an.
|
||||
- [ ] **4.4 Firewall** („PVE-Config: Firewall auf Datacenter- und Knotenebene einrichten“): IP-Set `admin` (Laptop) und `appsrv08` (.29). Zuerst Allow-Regeln für 8006, 22 und ICMP, **dann** aktivieren. Konsole als Rückfall bereithalten. Prüfung: Weboberfläche vom Laptop ok, von einem anderen Rechner gesperrt.
|
||||
- [x] **4.1 Benutzer und Token** (13.10. erledigt, Rolle `pve-cluster`/`playbooks/cluster.yml`: Gruppe `admins` (Administrator auf `/`), `r.rapp@pve` mit Passwort per `scripts/pve-admin-user.sh`, Rolle `KnasterHealer` + `healer@pve!knaster` nur auf `/pool/gpu`, Token auf ops `/root/.config/knaster/healer.env`; BETRIEB §8) (12.10. teilweise: `tofu@pve!ops` mit engen ACLs und `monitoring@pve!prom` (PVEAuditor, Geheimnis nur auf ops `/root/.config/knaster/pve-exporter.env`) angelegt; offen: persönlicher Admin-Benutzer (Name vom Nutzer), `healer@pve!knaster`) („PVE-Config: Persönlicher Admin-Benutzer, Rollen und API-Token anlegen“): Admin-Benutzer und Gruppe, root@pam nur als Notfallzugang. Token `monitoring@pve!prom` (PVEAuditor), `healer@pve!knaster` (nur `VM.PowerMgmt` auf GPU-VMs, PLAN §3), `tofu@pve!ops`.
|
||||
- [x] **4.2 2FA** (13.10.: TOTP + Recovery-Keys für `r.rapp@pve`, Datei `it/proxmox/tfa-r.rapp.txt`; root@pam bewusst ohne 2FA als Notfallzugang, BETRIEB §8) („PVE-Config: Zwei-Faktor-Authentifizierung für Admin-Konten aktivieren“): TOTP für root@pam und Admin. Recovery-Keys offline ablegen.
|
||||
- [x] **4.3 Benachrichtigungen** (13.10.: Ziel `knaster-mail` → ki@mygodel.de per Sendmail direkt an die MX, Matcher `knaster-alles`, `default-matcher` aus, Testmail zugestellt; BETRIEB §9) („PVE-Config: Benachrichtigungen (Notification Center) einrichten“): SMTP-Ziel Büro-Postfach, Matcher für Backup, Fencing und Updates. Testnachricht kommt an.
|
||||
- [x] **4.4 Firewall** (13.10.: aktiv auf allen Knoten, IPSET `admin` = Knoten + .151/.29/.173/.188, ACCEPT +admin dann DROP /24 auf 22/8006/3128/5900-5999/60000-60050 – `management` taugt nicht, Proxmox ergänzt es stets um das /24; Totmannschalter im Playbook; Negativtest aus GPU-VM bestanden; BETRIEB §10) („PVE-Config: Firewall auf Datacenter- und Knotenebene einrichten“): IP-Set `admin` (Laptop) und `appsrv08` (.29). Zuerst Allow-Regeln für 8006, 22 und ICMP, **dann** aktivieren. Konsole als Rückfall bereithalten. Prüfung: Weboberfläche vom Laptop ok, von einem anderen Rechner gesperrt.
|
||||
- [x] **4.5 Ordnung** (12.10.: Pools `gpu` = 244/246/248/252 per tofu, `infra` = 100/101 per `pveum` – beim Container würde `pool_id` in tofu ein Ersetzen erzwingen; Tags `knaster`, `gpu`, `legacy`, `infra`, `ops` per tofu/pct. LXC-Standard so umgesetzt: unprivilegiert, Debian 13.6, Nesting nur bei Docker) („PVE-Config: Ressourcenpools und Tags festlegen“, „PVE-Config: Standard für neue LXC-Container festlegen“): Pools `infra`, `gpu`, `test`. Tags `gpu`, `infra`, `test`. LXC-Standard: unprivilegiert, Debian-13-Vorlage, Nesting nur für Docker.
|
||||
- [ ] **4.6 Zertifikat** („PVE-Config: Web-GUI-Zertifikat festlegen (niedrige Priorität)“): `/etc/pve/pve-root-ca.pem` auf dem Laptop als vertrauenswürdig importieren.
|
||||
- [x] **4.6 Zertifikat** (13.10.: CA nach `it/proxmox/pve-root-ca.pem` kopiert, Knotenzertifikate tragen die IP als SAN; Import am Laptop per `certutil -user -addstore Root …`, BETRIEB §11) („PVE-Config: Web-GUI-Zertifikat festlegen (niedrige Priorität)“): `/etc/pve/pve-root-ca.pem` auf dem Laptop als vertrauenswürdig importieren.
|
||||
- [x] **4.7 Update-Routine** (12.10.: `docs/BETRIEB.md` Abschnitt 6, Wartungsmodus getestet) („PVE-Config: Update- und Neustart-Routine festlegen (rollierend, Knoten für Knoten)“): Ablauf in `docs/BETRIEB.md` eintragen (Wartungsmodus, ein Knoten nach dem anderen, GPU-VMs vorher sauber stoppen).
|
||||
|
||||
---
|
||||
@@ -418,7 +418,7 @@ Am Ende von Phase 9 wird das Betriebshandbuch abgeschlossen („PVE-Config: Betr
|
||||
| Planner-Aufgabe (exakter Titel) | Im Plan | Planner-Aktion nach Freigabe |
|
||||
|---|---|---|
|
||||
| Proxmox: pve48 root-Passwort klären und SSH-Schlüssel nachtragen | Task 0.1 | bleibt |
|
||||
| PVE-Config: Netzwerk prüfen – Bridge, VLAN-Fähigkeit und NIC-Kompatibilität | Task 0.2 (D5), VLAN später | bleibt, Beschreibung ergänzen |
|
||||
| PVE-Config: Netzwerk prüfen – Bridge, VLAN-Fähigkeit und NIC-Kompatibilität | Task 0.2 (D5), VLAN später | 13.10. geprüft (BETRIEB §12: e1000e/r8152, 1 GBit, kein VLAN-aware, keine Hänger), erledigt; Reservierungen bleiben in 0.2 |
|
||||
| Proxmox: Konfiguration aller Knoten durcharbeiten | aufgeteilt auf 0.1, 1.1–1.3 | schließen mit Verweis auf diesen Plan |
|
||||
| PVE-Config: Erst-Update aller Knoten (apt full-upgrade) | Task 1.1 | bleibt |
|
||||
| Proxmox: Speicher aller Knoten richtig konfigurieren | D1, Task 1.2 | bleibt |
|
||||
@@ -439,7 +439,7 @@ Am Ende von Phase 9 wird das Betriebshandbuch abgeschlossen („PVE-Config: Betr
|
||||
| Proxmox: pve61 (Surface) zeigt das Grafana-Dashboard als Kiosk | Tasks 1.3, 5.3 | bleibt |
|
||||
| LLM-Worker: direkte Inferenz-Schnittstelle für LiteLLM (zusätzlich zum Job-Poll), Tunnel, Registry, Fallback-Kette | Task 6.4 | bleibt, Beschreibung: Registry v2 + knaster-Brücke |
|
||||
| Proxmox: GRP als Testservice in einen LXC-Container umziehen | Phase 8 | bleibt |
|
||||
| PVE-Config: Betriebshandbuch und Testvorgehen anlegen | Phase 9 (`docs/BETRIEB.md`) | bleibt |
|
||||
| PVE-Config: Betriebshandbuch und Testvorgehen anlegen | Phase 9 (`docs/BETRIEB.md`) | 13.10. erledigt: §8–§13 und `scripts/healthcheck.sh` |
|
||||
| P1–P8 (NEX-Aufgaben) | Parallelspur | bleiben |
|
||||
|
||||
**Neu angelegt** (nur Schritte ohne bestehende Aufgabe, keine Duplikate):
|
||||
|
||||
@@ -21,3 +21,20 @@ ssh pve44 'uname -r; pveversion; systemctl --failed --no-legend; ip -br a show v
|
||||
```
|
||||
|
||||
Dazu Adressen, IDs und IOMMU-Gruppen der Karten mit dem Stand vor dem Neustart vergleichen. Die Site-Dateien verwenden `0000:01:00` und `0000:02:00`.
|
||||
|
||||
## pve-admin-user.sh
|
||||
|
||||
Schließt ein persönliches Admin-Konto ab, das `playbooks/cluster.yml` angelegt hat: Passwort (in `.env` als `PVE_ADMIN_<NAME>_PASS`), TOTP und Recovery-Keys (`it/proxmox/tfa-<name>.txt`). Läuft auf dem Laptop, idempotent. Details: `docs/BETRIEB.md` Abschnitt 8.
|
||||
|
||||
```bash
|
||||
platform/proxmox/scripts/pve-admin-user.sh r.rapp
|
||||
```
|
||||
|
||||
## healthcheck.sh
|
||||
|
||||
Testvorgehen für den Cluster (`docs/BETRIEB.md` Abschnitt 13): Quorum, HA, Replikation, Firewall, Benutzer, je Knoten Dienste, Zeit, Netz, Speicher, Zertifikat, GPU-Bindung, Weboberfläche, dazu der Firewall-Negativtest aus einer GPU-VM. Nur lesend, Exit 1 bei Fehlern.
|
||||
|
||||
```bash
|
||||
platform/proxmox/scripts/healthcheck.sh # alle Knoten
|
||||
platform/proxmox/scripts/healthcheck.sh pve44 # einzelner Knoten
|
||||
```
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
# Testvorgehen für den Cluster knaster (docs/BETRIEB.md, Abschnitt 13). Läuft auf dem Admin-Laptop
|
||||
# (Git-Bash) oder auf ops, nur lesend. Jede Zeile ist eine Prüfung mit OK/FEHLER, Exit 1 bei Fehlern.
|
||||
#
|
||||
# platform/proxmox/scripts/healthcheck.sh # alle Knoten
|
||||
# platform/proxmox/scripts/healthcheck.sh pve44 pve52
|
||||
set -uo pipefail
|
||||
nodes=("$@"); [ ${#nodes[@]} -gt 0 ] || nodes=(pve44 pve46 pve48 pve52 pve61)
|
||||
fail=0
|
||||
ok() { printf ' OK %s\n' "$1"; }
|
||||
bad() { printf ' FEHLER %s\n' "$1"; fail=1; }
|
||||
check() { local msg=$1; shift; if "$@" >/dev/null 2>&1; then ok "$msg"; else bad "$msg"; fi; }
|
||||
r() { ssh -T -o BatchMode=yes -o ConnectTimeout=8 "$@"; }
|
||||
|
||||
echo "== Cluster (über ${nodes[0]})"
|
||||
status=$(r "${nodes[0]}" pvecm status 2>/dev/null)
|
||||
grep -q 'Quorate: *Yes' <<<"$status" && ok "Quorum vorhanden" || bad "kein Quorum"
|
||||
votes=$(awk '/^Total votes/ {print $3}' <<<"$status"); expected=$(awk '/^Expected votes/ {print $3}' <<<"$status")
|
||||
[ -n "$votes" ] && [ "$votes" = "$expected" ] && ok "alle Knoten im Cluster ($votes/$expected)" || bad "Knoten fehlen ($votes/$expected)"
|
||||
ha=$(r "${nodes[0]}" ha-manager status 2>/dev/null)
|
||||
grep -q 'quorum OK' <<<"$ha" && ok "HA-Manager: Quorum OK" || bad "HA-Manager meldet kein Quorum"
|
||||
grep -E '^service' <<<"$ha" | grep -vq 'started' && bad "HA-Dienst nicht gestartet: $(grep -E '^service' <<<"$ha" | grep -v started | tr '\n' ';')" || ok "HA-Dienste gestartet"
|
||||
repl=$(r "${nodes[0]}" pvesr status 2>/dev/null | tail -n +2)
|
||||
[ -n "$repl" ] && { grep -vqE ' OK$' <<<"$repl" && bad "Replikation mit Fehler: $(grep -vE ' OK$' <<<"$repl" | tr '\n' ';')" || ok "Replikation: alle Jobs OK"; }
|
||||
fw=$(r "${nodes[0]}" cat /etc/pve/firewall/cluster.fw 2>/dev/null)
|
||||
grep -q '^enable: 1' <<<"$fw" && ok "Datacenter-Firewall aktiv" || bad "Datacenter-Firewall nicht aktiv"
|
||||
grep -q 'IN ACCEPT -source +admin' <<<"$fw" && ok "Firewall: Regel für +admin vorhanden" || bad "Firewall: Regel für +admin fehlt"
|
||||
matchers=$(r "${nodes[0]}" pvesh get /cluster/notifications/matchers --output-format json 2>/dev/null)
|
||||
grep -q '"name":"knaster-alles"' <<<"$matchers" && ok "Benachrichtigung: Matcher knaster-alles" || bad "Benachrichtigung: Matcher knaster-alles fehlt"
|
||||
users=$(r "${nodes[0]}" pveum user list --output-format json 2>/dev/null)
|
||||
for u in r.rapp@pve healer@pve tofu@pve monitoring@pve; do grep -q "\"userid\":\"$u\"" <<<"$users" && ok "Benutzer $u" || bad "Benutzer $u fehlt"; done
|
||||
tfa=$(r "${nodes[0]}" pvesh get /access/tfa/r.rapp@pve --output-format json 2>/dev/null)
|
||||
grep -q '"type":"totp"' <<<"$tfa" && ok "2FA (TOTP) für r.rapp@pve" || bad "2FA für r.rapp@pve fehlt"
|
||||
|
||||
for n in "${nodes[@]}"; do
|
||||
echo "== $n"
|
||||
out=$(r "$n" 'echo "kernel=$(uname -r)"; echo "failed=$(systemctl --failed --no-legend | wc -l)"; echo "fw=$(pve-firewall status)"; echo "ntp=$(timedatectl show -p NTPSynchronized --value)"; echo "vmbr0=$(ip -br a show vmbr0 | awk "{print \$2}")"; echo "root=$(df --output=pcent / | tail -1 | tr -d " %")"; echo "zpool=$(zpool list -H -o health tank 2>/dev/null || echo none)"; echo "cert=$(openssl x509 -in /etc/pve/local/pve-ssl.pem -noout -checkend 2592000 >/dev/null && echo ok || echo laeuft-ab)"; echo "gpu=$(lspci -nnk -d 10de: 2>/dev/null | grep -c "in use: vfio-pci")"; echo "gpus=$(lspci -n -d 10de: 2>/dev/null | wc -l)"; echo "hang=$(dmesg 2>/dev/null | grep -ci "unit hang")"' 2>/dev/null) || { bad "nicht erreichbar per SSH"; continue; }
|
||||
v() { awk -F= -v k="$1" '$1==k {print $2}' <<<"$out"; }
|
||||
ok "erreichbar, Kernel $(v kernel)"
|
||||
[ "$(v failed)" = 0 ] && ok "keine fehlgeschlagenen Dienste" || bad "$(v failed) fehlgeschlagene Dienste (systemctl --failed)"
|
||||
[[ "$(v fw)" == *enabled/running* ]] && ok "Knoten-Firewall läuft" || bad "Knoten-Firewall: $(v fw)"
|
||||
[ "$(v ntp)" = yes ] && ok "Zeit per NTP synchron" || bad "Zeit nicht synchron"
|
||||
[ "$(v vmbr0)" = UP ] && ok "vmbr0 UP" || bad "vmbr0 nicht UP"
|
||||
[ "$(v root)" -lt 85 ] && ok "Systemplatte $(v root) % belegt" || bad "Systemplatte $(v root) % belegt"
|
||||
case "$(v zpool)" in none) ok "kein ZFS-Pool (erwartet auf pve46/pve61)";; ONLINE) ok "zpool tank ONLINE";; *) bad "zpool tank: $(v zpool)";; esac
|
||||
[ "$(v cert)" = ok ] && ok "Knotenzertifikat länger als 30 Tage gültig" || bad "Knotenzertifikat läuft in 30 Tagen ab"
|
||||
if [ "$(v gpus)" -gt 0 ]; then [ "$(v gpu)" = "$(v gpus)" ] && ok "alle $(v gpus) NVIDIA-Funktionen an vfio-pci" || bad "nur $(v gpu) von $(v gpus) NVIDIA-Funktionen an vfio-pci"; fi
|
||||
[ "$(v hang)" = 0 ] && ok "keine NIC-Hänger (e1000e/r8152)" || bad "$(v hang) NIC-Hänger im Kernel-Log"
|
||||
ip=$(ssh -G "$n" | awk '$1=="hostname"{print $2}')
|
||||
check "Weboberfläche https://$ip:8006 antwortet" bash -c "curl -sk -m 6 -o /dev/null -w '%{http_code}' https://$ip:8006/ | grep -q 200"
|
||||
done
|
||||
|
||||
echo "== Firewall-Negativtest (aus GPU-VM 246 auf pve46, nicht in +admin)"
|
||||
neg=$(r pve46 'qm guest exec 246 --timeout 15 -- bash -c "curl -sk -m 4 -o /dev/null -w %{http_code} https://192.168.100.210:8006/ || echo blockiert"' 2>/dev/null)
|
||||
grep -q blockiert <<<"$neg" && ok "VM erreicht 8006 nicht" || bad "VM erreicht 8006 (Firewall wirkt nicht)"
|
||||
|
||||
[ $fail = 0 ] && echo "ERGEBNIS: alles OK" || { echo "ERGEBNIS: Fehler, siehe oben"; exit 1; }
|
||||
Reference in New Issue
Block a user