Öffentliche Nix-Container-Images
openEduSuite baut seine Infrastruktur-Images nicht mehr von Upstream-Registries ab, sondern stellt sie als reproduzierbare Nix-Builds bereit. Jedes Image wird deterministisch aus dem Quellcode erzeugt, ist byte-für-byte nachbaubar und kann vollständig offline betrieben werden; dies ist die Grundvoraussetzung für luftdicht betriebene Hochschul-Cluster.
Die Image-Familie
Alle Images folgen demselben Muster: ein flacher, mehrschichtiger OCI-Container (dockerTools.buildLayeredImage), erzeugt aus einem pinnten Nix-Build des jeweiligen Upstream-Projekts. Keine Alpine-Distro, keine unkontrollierte Paketliste; nur die Binaries und Bibliotheken, die das Nix-Store-Layout hergibt.
| Image | Ersetzt | Version | Zweck |
|---|---|---|---|
dex |
ghcr.io/dexidp/dex |
2.38.0-nix | OIDC/OAuth2-Identitätsprovider (ArgoCD-SSO) |
helmfile |
ghcr.io/helmfile/helmfile |
1.8.0-nix | Helmfile-Renderer für den ArgoCD-CMP-Sidecar |
k8up |
ghcr.io/k8up-io/k8up |
2.13.1-nix | Kubernetes-Backup-Operator (Restic) |
cloudnative-pg |
ghcr.io/cloudnative-pg/cloudnative-pg |
1.30.1-nix | Postgres-Operator; injiziert den Instance-Manager in jeden DB-Pod |
postgresql |
ghcr.io/cloudnative-pg/postgresql |
16.15-nix | CNPG-kompatibles PostgreSQL 16 (UID 26, /controller-Layout, barman-cloud) |
agentflow |
— (Nachfolger von taskfleet) | 0.1.0-nix | DAG-orchestrierte Coding-Agent-Kampagnen (af) |
Bezugsquellen
Öffentliche Haupt-Registry (registry.openedusuite.org)
Die vollständige, öffentlich zugängliche Bildfamilie liegt auf der öffentlichen OCI-Registry des Projekts (Zot hinter Traefik, Let's-Encrypt-Zertifikat):
https://registry.openedusuite.org/dex:2.38.0-nix
https://registry.openedusuite.org/helmfile:1.8.0-nix
https://registry.openedusuite.org/k8up:2.13.1-nix
https://registry.openedusuite.org/cloudnative-pg:1.30.1-nix
https://registry.openedusuite.org/postgresql:16.15-nix
https://registry.openedusuite.org/agentflow:0.1.0-nix
Pull ist ohne Authentifizierung möglich; nur das Pushen ist zugangsgeschützt:
$ docker pull registry.openedusuite.org/k8up:2.13.1-nix
GHCR (öffentliche Registry, geplant)
Optional werden dieselben Images zusätzlich auf ghcr.io/tobias-weiss-ai-xr/… veröffentlicht (Sichtbarkeit & Redundanz). Stand: Push auf GHCR wartet auf ein Token mit Packages: write-Scope.
ghcr.io/tobias-weiss-ai-xr/dex:2.38.0-nix
ghcr.io/tobias-weiss-ai-xr/helmfile:1.8.0-nix
ghcr.io/tobias-weiss-ai-xr/k8up:2.13.1-nix
ghcr.io/tobias-weiss-ai-xr/cloudnative-pg:1.30.1-nix
ghcr.io/tobias-weiss-ai-xr/postgresql:16.15-nix
ghcr.io/tobias-weiss-ai-xr/agentflow:0.1.0-nix
Spiegel: Zot (Cluster-intern)
Luftdichte Zielumgebungen spiegeln dieselbe Bildfamilie auf einen lokalen Zot-Registry-Node, der zugleich als Pull-Through-Cache dient (Beispiel mit einer dokumentationsüblichen Adresse nach RFC 5737):
192.0.2.10:5002/opendesk-nix/<name>:<tag>
Der k3s-Registry-Spiegel leitet jeden ghcr.io-Pull an Zot weiter; der Cluster bleibt selbstständig, auch wenn der externe Egress ausfällt.
Warum Nix?
- Reproduzierbarkeit. Ein Image ist eine Funktion des Nix-Flake-Inputs. Zwei Builds derselben Revision ergeben denselben Store-Pfad und damit denselben Image-Digest.
- Minimalismus durch Herkunft statt durch Entfernen. Ein Nix-Image enthält nur, was der Store hergibt: der Go-Binary des Upstream-Projekts, CA-Zertifikate,
tzdata. Kein Paketmanager, keine Shell, wenn sie nicht gebraucht wird. - Luftdichte Operation. Builds lassen sich offline aus einer nix-copy-closure rekonstruieren; die Zot-Spiegel koppeln den Cluster nicht an externe Registries.
- Auditierbarkeit. Die Derivation ist die SBOM: jede Abhängigkeit ist im Store-Pfad lesbar (
/nix/store/…-k8up-2.13.1).
Selbst bauen
Die Derivations liegen im openEduSuite-hrz-Repository unter nix/images/infra/:
$ nix build .#k8up
$ skopeo copy --dest-tls-verify=false --format oci \
docker-archive:result \
docker://ghcr.io/tobias-weiss-ai-xr/k8up:2.13.1-nix
Der Flake pinnt nixpkgs über flake.lock; die Go-Module-Hashes (vendorHash) und Source-Hashes sind je Derivation fixiert.
Anmerkungen zur CNPG-Kompatibilität
Das PostgreSQL-Image erfüllt den Contract des CloudNativePG-Operators: UID/GID 26, /controller als Arbeitsverzeichnis, /var/run/postgresql als Socket-Verzeichnis und barman-cloud für den Backup-Pfad. Der Instance-Manager wird (wie bei Upstream) nicht ins Image gebacken, sondern vom Operator per bootstrap-controller-InitContainer injiziert; dafür hält das Operator-Image das Binary an beiden Stellen (/manager und /controller/instance-manager).
Ausblick
Die Image-Familie wächst mit dem Suite-Bedarf: als nächste Stufe folgen die Anwendungs-Images (Intercom, Stalwart-Fork, SOGo) auf denselben Nix-Weg. Das Ziel bleibt unverändert: ein Cluster, der ohne einen einzigen imperativen docker pull aus fremden Registries auskommt.