Encoding/CT-101: PVE-Host-NFS konvergiert, Berechtigungsmodell entschieden, Verifikation dokumentiert.

- pve_nfs_export: NFSv4-only via /etc/nfs.conf ([nfsd] vers2/vers3=n; Debian-13-Unit
  startet nfsd ohne EnvironmentFile, RPCNFSDARGS wirkungslos), Restart-Handler,
  selbstheilende nfsd-Versionspruefung; verify-production um Export-Root- und
  Versions-Assertions erweitert
- Autorisierte Konvergenz auf dem PVE-Host: Export-Root 100000:970 2775,
  /proc/fs/nfsd/versions -3 +4 +4.1 +4.2, verify ok=17 changed=0, Idempotenz changed=0
- Berechtigungsmodell (Betreiberentscheidung 30.10.2026): Mode 2777 auf input/- und
  output/-Baum der Pipeline (LXC-idmap-Diskrepanz guest-root vs. UID 982/983:970)
- GNENC-000/001/002, GNAI-017/018/019 auf NFS-auf-PVE-Host-Stand gebracht;
  CT-101-Verifikation ok=47 changed=0 dokumentiert; AGENTS.md-Seccomp-Hinweis korrigiert

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-10-30 19:54:42 +01:00
parent 6a1eff7392
commit 88b063a234
11 changed files with 259 additions and 72 deletions
@@ -1,8 +1,8 @@
# Video-Encoding – Dokumentationsindex und Projektstand
**Dokumenten-ID:** GNENC-000-DOC
**Stand:** 2026-10-19
**Status:** Planungsabschluss; Pipeline geplant, Implementierung noch nicht begonnen
**Stand:** 2026-10-30
**Status:** Planungsabschluss; externe Abhängigkeiten (CT-101, PVE-Host-NFS) umgesetzt; Implementierung auf ghostnet-ki noch nicht begonnen
## Dokumente
@@ -23,9 +23,16 @@ beschrieben.
(ProtonVPN), jDownloader2 (Download), Encoding-Worker (HandBrakeCLI +
ffmpeg); Handover ausschließlich über das Filesystem, In-Progress-Schutz
über Work-Ordner und atomares `mv`.
- Speicherort: CT-101 (Samba/NAS, 10.0.0.9) — NFS-Export
`/media/datenhdd3/Encoding`, gemountet auf `/var/lib/ghostnet-encoding`
(ghostnet-ki hat nur eine 2-TB-NVMe; die Medienbibliothek liegt auf CT-101).
- Speicherort: PVE-Host-Medienverbund `/media/datenhdd3` (per LXC-Mount auch
in CT-101 sichtbar) — NFS-Export `10.0.0.2:/media/datenhdd3/Encoding`,
gemountet auf `/var/lib/ghostnet-encoding` (ghostnet-ki hat nur eine
2-TB-NVMe; die Medienbibliothek liegt auf dem PVE-Host/CT-101).
- CT-101 per Ansible adoptiert und PVE-Host-NFS umgesetzt (GNAI-019);
Verifikation 30.10.2026: CT-101 `verify-production` `ok=47 changed=0`;
PVE-Host nach autorisierter Konvergenz: Export-Root `100000:970 2775`,
NFSv4-only wirksam (`-3`), `verify-production` `ok=17 changed=0`,
Idempotenz `changed=0`. Berechtigungsmodell entschieden: Mode 2777 auf den
SMB-berührten Verzeichnissen (GNENC-002 Abschnitt 4).
- Verzeichnislayout: `input/<Profil>/*.dlc`, `jd/`, `queue/<Profil>/<Release>/`,
`work/`, `output/<Profil>/<Release>/` + `output/_failed/`, `state/jobs/` +
`state/system.json`.
@@ -64,10 +71,12 @@ beschrieben.
## Noch offen
1. Feinjustierung der Ressourcenlimits nach einem repräsentativen Encoding-Test
1. NFSv4.2-Mount-Abnahme von `ghostnet-ki` gegen `10.0.0.2` (inkl.
Schreib-/Lesetest als UID 982/983 und mv-Simulation als `ghost` über SMB)
— mit der Encoding-Implementierung.
2. Feinjustierung der Ressourcenlimits nach einem repräsentativen Encoding-Test
unter gleichzeitiger Inferenzlast.
2. Rootless-TUN-Verifizierung für den VPN-Sidecar auf dem Host.
3. Implementierung: CT-101 (NFS-Export, Shares `[Encode]`/`[Encode-In]`,
Gruppe `gn-media`/GID-Abgleich — GNAI-017), Konten `gn-download`/
`gn-dashboard`, NFS-Mount, Image-Bauten, Quadlet-Units (inkl. VPN-Sidecar),
Skripte, Monitoring-Bereich (Collector, Dashboard).
3. Rootless-TUN-Verifizierung für den VPN-Sidecar auf dem Host.
4. Implementierung auf ghostnet-ki: Konten `gn-download`/`gn-dashboard`,
NFS-Mount, Image-Bauten, Quadlet-Units (inkl. VPN-Sidecar), Skripte,
Monitoring-Bereich (Collector, Dashboard).
@@ -2,8 +2,8 @@
**Dokumenten-ID:** GNENC-001-PLAN
**Titel:** CPU-basiertes Video-Encoding auf dem KI-Server
**Stand:** 2026-10-19
**Status:** Finaler Plan nach Planungsabschluss am 19.10.2026; die operative Pipeline ist in GNENC-002 spezifiziert, das host-weite Monitoring in GNMON-001
**Stand:** 2026-10-30
**Status:** Finaler Plan nach Planungsabschluss am 19.10.2026; externe Abhängigkeiten (CT-101, PVE-Host-NFS) umgesetzt (GNAI-019); die operative Pipeline ist in GNENC-002 spezifiziert, das host-weite Monitoring in GNMON-001
## 1. Zweck und Abgrenzung
@@ -40,10 +40,10 @@ beschrieben.
| Download-Stufe | jDownloader2-Container (`jlesage/jdownloader-2`, gepinnter Digest) liest `.dlc` aus `input/<Profil>/`; Event-Scripter verschiebt den Release-Ordner atomar in die Queue | Betreiberentscheidung 19.10.2026 |
| VPN | der gesamte jDownloader2-Verkehr läuft über einen ProtonVPN-WireGuard-Tunnel: gluetun-Sidecar (`qmcgaw/gluetun`, gepinnt) unter `gn-download`, JD2 teilt dessen Netzwerk-Namespace, Kill Switch aktiv (kein Traffic ohne Tunnel); WireGuard-Credentials server-lokal in `/etc/ghostnet-download/vpn.env`, nicht in git | Betreiberentscheidung 19.10.2026 |
| Anwendung | Worker-Image als Eigenbau auf Basis des gepinnten HandBrake-Images `linuxserver/handbrake:1.11.2-ls48` (`sha256:fda92bd1…48a3c7`) mit python3 und ffmpeg; die Digests von Worker- und VPN-Image werden nach dem Bau gepinnt | Betreiberentscheidung 19.10.2026 |
| Speicherort | Pipeline-Daten liegen auf CT-101 (Samba/NAS, 10.0.0.9): dort liegen die Medienbibliothek und der Plattenverbund; ghostnet-ki selbst hat nur eine 2-TB-NVMe (OS + LLM) | Betreiberentscheidung 19.10.2026 |
| Ein-/Ausgabe | NFS-Export `/media/datenhdd3/Encoding` von CT-101 (10.0.0.9), gemountet auf `/var/lib/ghostnet-encoding`; Verzeichnislayout `input/`, `jd/`, `queue/`, `work/`, `output/`, `state/` | Betreiberentscheidung 19.10.2026; Server, IP und Export-Pfad festgelegt |
| Speicherort | Pipeline-Daten liegen auf dem PVE-Host-Medienverbund (`/media/datenhdd3`; per LXC-Mount auch in CT-101 sichtbar): dort liegt die Medienbibliothek; ghostnet-ki selbst hat nur eine 2-TB-NVMe (OS + LLM) | Betreiberentscheidung 19.10.2026; NFS seit 30.10.2026 auf dem PVE-Host (GNAI-019 Entscheidung 2) |
| Ein-/Ausgabe | NFS-Export `10.0.0.2:/media/datenhdd3/Encoding` (PVE-Host, Rolle `pve_nfs_export`, NFSv4-only, nur für 10.0.0.90, `root_squash`), gemountet auf `/var/lib/ghostnet-encoding`; Verzeichnislayout `input/`, `jd/`, `queue/`, `work/`, `output/`, `state/` | Betreiberentscheidung 19.10.2026; Umsetzung GNAI-019 (Revision 30.10.2026); Mount-Abnahme durch das Encoding-Ansible ausstehend |
| Abholung | fertige Outputs per SMB über CT-101: Share `[Encode]` (`output/`, RW für `ghost`, lesend für `daidalaw`/`debugofen`) — Entnahme per `mv` in die Bibliotheks-Shares räumt `output/` auf; optionaler Clean-Job löscht Dateien nach 30 Tagen aus `output/`; kein smbd auf `ghostnet-ki` | Betreiberentscheidung 19.10.2026 |
| Samba-Integration (CT-101) | CT-101 wird ins Infrastructure-Repository aufgenommen (GNAI-017): NFS-Export nur für 10.0.0.90, Shares `[Encode]`/`[Encode-In]`, Gruppe `gn-media` (GID 970) auf CT-101 mit `ghost` als Mitglied (UID/GID-Abgleich); `.dlc`-Drop über `[Encode-In]` | Betreiberentscheidung 19.10.2026; GNAI-017 |
| Samba-Integration (CT-101) | CT-101 ist per Ansible adoptiert (GNAI-019; verifiziert 30.10.2026, `ok=47 changed=0`): Shares `[Encode]`/`[Encode-In]`/`[Encoding]`, Gruppe `gn-media` (GID 970) mit `ghost` als Mitglied; `.dlc`-Drop über `[Encode-In]`. NFS liegt nicht auf CT-101 (PVE-Host); die guest-seitige GID 970 gleicht die Host-GID 970 wegen des LXC-idmap nicht ab — Berechtigungsmodell: Mode 2777 auf den SMB-berührten Verzeichnissen (Betreiberentscheidung 30.10.2026, GNENC-002 Abschnitt 4) | Betreiberentscheidung 19.10.2026; GNAI-017/GNAI-019 |
| Profile | drei versionierte HandBrake-Presets (SVT-AV1 10-bit, MKV, Audio-Passthrough) unter `llm-server/encoding/profiles/`; Auswahl über gleichnamige Ordner unter `input/` bzw. `queue/` | Betreiberentscheidung 19.10.2026; Presets versioniert |
| Warteschlange | dateibasiert: `.dlc`-Drop in `input/<Profilname>/`, jDownloader2 befüllt `queue/<Profilname>/<Release>/`, der Worker arbeitet die Queue mit genau einem gleichzeitigen Encode ab | Betreiberentscheidung 19.10.2026 |
| Filter | Nicht-Video-Dateien und Dateien < 100 MB werden ignoriert; alle übrigen Videodateien eines Releases werden encodet (keine Hauptdatei-Auswahl) | Betreiberentscheidung 19.10.2026 |
@@ -65,7 +65,7 @@ flowchart LR
ENC[gn-encoding\nrootless Podman]
DL[gn-download\nrootless Podman]
DASH[gn-dashboard\nrootless Podman]
NAS[CT-101 Samba/NFS\n10.0.0.9]
NAS[PVE-Host NFS 10.0.0.2\nCT-101 SMB 10.0.0.9]
GPU[beide GPUs]
CPU[CPU / I-O Budget]
TIMER[nächtliche Fensterlogik\nim Worker]
@@ -233,18 +233,28 @@ anschließend in den rootless Store von `gn-encoding` gezogen; der Pull
bestätigte den Manifest-Digest.
Am 19.10.2026 wurde die Planung abgeschlossen (Abschnitte 2 und 7). Die
Implementierungsphase baut als Nächstes auf: der NFS-Export und die Shares
`[Encode]`/`[Encode-In]` auf CT-101 (GNAI-017), die Konten `gn-download` und
`gn-dashboard` samt Gruppe `gn-media` (GID 970, auch auf CT-101), der NFS-Mount
auf ghostnet-ki, die Image-Bauten mit Digest-Pinning (Worker, VPN-Sidecar,
Dashboard), die Quadlet-Units für jDownloader2, VPN-Sidecar, Worker und
Dashboard, der host-seitige Metrics-Collector sowie die Skripte aus `scripts/`.
Die Rolle `video_encoding` stellt bis dahin sicher, dass weder Quadlet-Dateien
noch Container für `gn-encoding` existieren.
externen Abhängigkeiten sind umgesetzt: CT-101 ist per Ansible adoptiert
(GNAI-019, verifiziert 30.10.2026), der NFS-Export läuft auf dem PVE-Host
(Rolle `pve_nfs_export`); der PVE-Host ist konvergiert (Export-Root
`100000:970 2775`, NFSv4-only wirksam, `verify-production` `ok=17 changed=0`,
Idempotenz `changed=0`; autorisierter Lauf 30.10.2026). Das
Berechtigungsmodell für die SMB-Schreibpfade ist entschieden (Mode 2777,
GNENC-002 Abschnitt 4); offener Restpunkt ist die NFSv4.2-Mount-Abnahme von
ghostnet-ki. Die Implementierungsphase auf
ghostnet-ki baut als Nächstes auf: die Konten `gn-download` und `gn-dashboard`
samt Gruppe `gn-media` (GID 970), den NFS-Mount von `10.0.0.2`, die
Image-Bauten mit Digest-Pinning (Worker, VPN-Sidecar, Dashboard), die
Quadlet-Units für jDownloader2, VPN-Sidecar, Worker und Dashboard, den
host-seitigen Metrics-Collector sowie die Skripte aus `scripts/`. Die Rolle
`video_encoding` stellt bis dahin sicher, dass weder Quadlet-Dateien noch
Container für `gn-encoding` existieren.
## 7. Offene Entscheidungen
1. Feinjustierung der Ressourcenlimits nach einem repräsentativen Encoding-Test
unter gleichzeitiger Inferenzlast (Abschnitt 4).
Diese Werte werden nicht vorab in Playbooks angenommen.
Diese Werte werden nicht vorab in Playbooks angenommen. Die am 30.10.2026
offenen Punkte Berechtigungsmodell (Mode 2777, GNENC-002 Abschnitt 4) und
PVE-Host-Konvergenz (GNAI-017 Abschnitt 6.9) sind entschieden beziehungsweise
erledigt.
@@ -2,11 +2,11 @@
**Dokumenten-ID:** GNENC-002-PLAN
**Titel:** Encoding-Pipeline: Komponenten, Konten, Verzeichnislayout und Datenfluss
**Stand:** 2026-10-19
**Status:** Finaler Plan nach Betreiberentscheidungen vom 19.10.2026
**Stand:** 2026-10-30
**Status:** Finaler Plan nach Betreiberentscheidungen vom 19.10.2026; externe Abhängigkeiten umgesetzt (GNAI-019)
**Vorgänger:** [GNENC-001-PLAN_Architecture.md](GNENC-001-PLAN_Architecture.md)
**Monitoring:** [GNMON-001-PLAN_Architecture.md](../monitoring/GNMON-001-PLAN_Architecture.md)
**Samba/NFS (CT-101):** [GNAI-017-PLAN_Samba-NFS-Export.md](../../proxmox-server/lxc/ct-101-samba/GNAI-017-PLAN_Samba-NFS-Export.md)
**Samba/NFS:** [GNAI-017](../../proxmox-server/lxc/ct-101-samba/GNAI-017-PLAN_Samba-NFS-Export.md), [GNAI-019](../../proxmox-server/lxc/ct-101-samba/GNAI-019-DEC_Ansible-Migration.md) — SMB auf CT-101, Kernel-NFS auf dem PVE-Host
## 1. Architekturprinzip
@@ -38,28 +38,35 @@ Dashboard und Metrics-Collector werden im Monitoring-Bereich betrieben
| `gn-dashboard` | 984 | 624288–689823 | `/var/lib/ghostnet-dashboard` | `/etc/ghostnet-dashboard` | `gn-media` (nur lesend) |
Gruppe `gn-media`: gemeinsame Gruppe der drei Konten für die Übergabe-
Verzeichnisse und den lesenden Zugriff auf `state/`; GID 970, auf `ghostnet-ki`
und CT-101 identisch angelegt (GNAI-017). Alle Konten sind gesperrt
(Passwort `!`, Shell `/usr/sbin/nologin`, Linger aktiv).
Verzeichnisse und den lesenden Zugriff auf `state/`; GID 970. Alle Konten sind
gesperrt (Passwort `!`, Shell `/usr/sbin/nologin`, Linger aktiv).
**Anmerkung 30.10.2026 (LXC-idmap):** Die guest-seitige Gruppe `gn-media`
(GID 970) in CT-101 erscheint auf dem Host als GID 100970 und gleicht die
reale Host-GID 970 der Pipeline nicht ab — die Gruppen-Alignment wirkt nur
innerhalb von ghostnet-ki. Die SMB-Schreibpfade aus CT-101 laufen über
guest-root (Host-UID 100000, da `admin users` Dateioperationen als root
ausführt); siehe Abschnitt 11.
## 4. Verzeichnislayout
```text
/var/lib/ghostnet-encoding/ (NFS-Mount: 10.0.0.9:/media/datenhdd3/Encoding, CT-101)
├── input/<Profil>/ gn-media 2770 Drop-Ziel, nur .dlc
├── jd/ gn-download JD2-Arbeitsverzeichnis
/var/lib/ghostnet-encoding/ (NFS-Mount: 10.0.0.2:/media/datenhdd3/Encoding, PVE-Host)
├── input/ gn-media 2777 SMB-Drop ([Encode-In])
│ └── <Profil>/ gn-media 2777 nur .dlc
├── jd/ gn-media 2770 JD2-Arbeitsverzeichnis (gn-download)
│ ├── <Release>/ Download + Entpacken
│ ├── dlc_done/ erfolgreich abgearbeitete .dlc
│ └── failed/ .dlc mit Download-Fehler
├── queue/<Profil>/<Release>/ gn-media 2770 Roh-Queue, atomar befüllt
├── work/<Release>/ gn-encoding 0750 Encode-Ziele in Arbeit
├── output/
│ ├── <Profil>/<Release>/ gn-encoding Erfolge bis Abholung
│ └── _failed/<Release>/ gn-encoding Quarantäne
└── state/
├── jobs/<job_id>.json gn-encoding Status pro Videodatei
├── tmp/ gn-encoding atomare Schreib-Zwischenlage
└── system.json Collector Systemmetriken (Monitoring)
├── output/ gn-media 2777 Abholung ([Encode])
│ ├── <Profil>/<Release>/ gn-media 2777 Erfolge bis Abholung
│ └── _failed/<Release>/ gn-media 2777 Quarantäne
└── state/ gn-media 2750 Status (Dashboard liest)
├── jobs/<job_id>.json gn-encoding 0750 Status pro Videodatei
├── tmp/ gn-encoding 0750 atomare Schreib-Zwischenlage
└── system.json Collector 0644 Systemmetriken (Monitoring)
```
`state/` ist `gn-encoding:gn-media` mit Mode `2750`, damit `gn-dashboard` lesen
@@ -71,8 +78,12 @@ Handover-Regeln:
- Übergabe immer per atomarem `mv` innerhalb des Mounts; Work-Dateien liegen
nie in Übergabe-Ordnern.
- `input/`, `jd/`, `queue/` mit Mode `2770` (setgid), damit neue Dateien die
Gruppe `gn-media` erben.
- `jd/`, `queue/` mit Mode `2770` (setgid); `state/` mit `2750` (setgid).
- `input/` (inkl. Profil-Ordner) und der gesamte `output/`-Baum (inkl.
Release- und `_failed/`-Verzeichnisse, vom Worker angelegt) mit Mode
`2777` (setgid) — Welt-Schreibrecht für den SMB-Schreibpfad aus CT-101
(Betreiberentscheidung 30.10.2026, siehe unten). Neue Dateien erben die
Gruppe `gn-media`.
- jDownloader2 läuft mit `UMASK=022`, damit der Worker die Dateien lesen kann.
- Der Worker löscht Quelldateien und geleerte Release-Ordner aus `queue/`;
Löschrechte folgen aus dem Schreibrecht der Gruppe am Verzeichnis (kein
@@ -80,6 +91,18 @@ Handover-Regeln:
- `work/` wird pro Lauf geleert; `state/tmp/` dient nur atomaren
Schreibzugriffen.
**Berechtigungsmodell (Betreiberentscheidung 30.10.2026):** Die SMB-Zugriffe
aus CT-101 laufen über guest-root (Host-UID 100000; `admin users` führt
Dateioperationen als root aus). Da die Pipeline-Verzeichnisse via NFS den
realen UIDs 982/983:970 gehören und diese im LXC-idmap nicht abgebildet sind
(im Gast: `nobody:nogroup`), tragen `input/` und der `output/`-Baum Mode
`2777`; `jd/`, `queue/`, `work/` und `state/` bleiben eng (2770/0750).
**Layout-Anlage:** Wegen `root_squash` auf dem Export kann Ansible als root
keine chowned-Verzeichnisse anlegen; die Struktur wird als `gn-encoding`
angelegt (runuser; Muster der Rolle `video_encoding`) oder vom Worker beim
Start erzeugt und geprüft.
**Abholung:** Die fertigen Outputs werden über CT-101 per SMB abgeholt: Share
`[Encode]` (Pfad `/media/datenhdd3/Encoding/output`, RW für `ghost`, lesend für
`daidalaw`/`debugofen`). Die Entnahme per `mv` in die Bibliotheks-Shares
@@ -231,9 +254,10 @@ die Container gemountet (Updates ohne Image-Rebuild, versioniert über git).
## 11. Offene Punkte
1. Feinjustierung der Ressourcenlimits nach Lasttest unter Inferenzlast
1. NFSv4.2-Mount-Abnahme von `ghostnet-ki` gegen `10.0.0.2` — inkl.
Schreib-/Lesetest als UID 982/983 über den Mount und mv-Simulation als
`ghost` über SMB; mit der Encoding-Implementierung.
2. Feinjustierung der Ressourcenlimits nach Lasttest unter Inferenzlast
(GNENC-001 Abschnitt 4).
2. Rootless-TUN-Verifizierung für den VPN-Sidecar auf dem Host (Fallback:
3. Rootless-TUN-Verifizierung für den VPN-Sidecar auf dem Host (Fallback:
host-seitiger WireGuard mit Policy-Routing).
3. UID/GID-Abgleich: Gruppe `gn-media` (GID 970) muss auf CT-101 identisch
existieren; `ghost` Mitglied für die Abholung per `mv` (GNAI-017).