Der Code zu diesem Artikel steht hier zum Download.
Als Freelancer im Technologiebereich faszinieren mich seit einiger Zeit die Möglichkeiten und Herausforderungen moderner Cloud-nativer Architekturen. Besonders das Thema **Edge Computing** – die Verlagerung von Intelligenz und Datenverarbeitung an den Rand des Netzwerks – hat mein Interesse geweckt. Angesichts der steigenden Anforderungen an geringe Latenz, hohe Zuverlässigkeit und Datensouveränität[1] sehe ich hier ein enormes Potenzial, aber auch komplexe technische Aufgaben.
Um diese Aufgaben besser zu verstehen und praktische Lösungsansätze zu erproben, habe ich mich entschlossen, einen **Prototypen für einen vollständigen Edge-Deployment-Workflow** zu bauen. Dieser Blog-Post dokumentiert meine Reise, die gewählte Architektur, die Begründung hinter den Technologieentscheidungen (basierend auf meiner Recherche zu realen Edge-Implementierungen) und die unvermeidlichen, aber lehrreichen Hürden auf dem Weg.
Motivation: Die Notwendigkeit robuster Edge-Strategien
Meine Recherche, inspiriert durch Berichte über massive Edge-Infrastrukturen wie die von REWE digital zur Versorgung von tausenden Geräten in Filialen, hat die spezifischen Herausforderungen dieses Bereichs verdeutlicht:
- Skalierung und Management: Wie verwaltet man Hunderte oder Tausende von verteilten Standorten konsistent und automatisiert?[25], [4]
- Konnektivität: Viele Edge-Standorte kämpfen mit unzuverlässigen oder langsamen Internetverbindungen, was die Softwareverteilung erschwert – ein Problem, das selbst große Player wie REWE zur Entwicklung eigener Lösungen zwingt.[2]
- Ressourcenbeschränkungen: Edge-Hardware ist oft leistungsschwächer als Server im Rechenzentrum, was spezielle, leichtgewichtige Software erfordert.[1]
- Image-Verteilung: Wie gelangen große Container-Images (z.B. für ML/AI-Anwendungen) effizient und sicher an den Edge, ohne die begrenzte Bandbreite zu überlasten? Techniken wie Delta-Updates sind hier relevant.[9], [30]
- Sicherheit: Physisch oft weniger gesicherte Standorte erfordern robuste Sicherheitskonzepte wie Zero Trust.[1]
Angesichts dieser Komplexität erschien mir ein Ansatz basierend auf **Kubernetes** (für die Orchestrierung) und **GitOps** (für das deklarative Management) als vielversprechend. Kubernetes bietet eine einheitliche Abstraktionsebene[2], während GitOps die notwendige Automatisierung und Konsistenz für skalierte Deployments liefert[4]. Mein Prototyp sollte genau diese Kombination evaluieren.
Die Prototyp-Architektur: Komponenten und Begründungen
Basierend auf den Herausforderungen habe ich folgende Architektur für meinen Prototypen gewählt:
- Infrastructure as Code (Terraform auf GCP): Um eine reproduzierbare und versionierbare Infrastruktur zu gewährleisten – ein Kernprinzip für skalierbare Deployments (“Snowflakes waren gestern”, wie im REWE-Kontext erwähnt). Ich nutze Terraform, um eine GCP VM, VPC, Subnetz und Firewalls zu erstellen.
- Leichtgewichtiges Kubernetes (K3s): Angesichts der Ressourcenbeschränkungen am Edge[1] habe ich mich für K3s entschieden. Es ist eine CNCF-zertifizierte Distribution, die speziell für Edge-Szenarien optimiert wurde, wenig Ressourcen benötigt und als einzelnes Binary einfach (hier via Startup-Skript) installiert werden kann.[7], [38] Dies steht im Gegensatz zu Standard-Kubernetes, das oft zu ressourcenintensiv für Edge-Geräte ist.
- GitOps Engine (Rancher Fleet): Um die Komplexität der Verwaltung verteilter Anwendungen zu adressieren[25], setze ich auf GitOps mit Fleet. Fleet läuft auf K3s und überwacht mein GitOps-Repository, um den deklarierten Zustand automatisch im Cluster herzustellen. Es ist für Multi-Cluster-Szenarien ausgelegt, funktioniert aber auch hier für den einzelnen Cluster.[52]
- GitOps Repository (`fleet-config` auf GitLab): Das zentrale Repository, das den gewünschten Zustand aller Kubernetes-Ressourcen enthält (Helm Charts, CRDs, etc.).
- CI/CD (GitLab CI): Getrennte Pipelines in den Anwendungs-Repositories bauen Images (Multi-Stage Dockerfiles), pushen sie mit Digest in die zentrale GitLab Registry und aktualisieren dann **deklarativ** das GitOps-Repository (via SSH Deploy Key). Dieser Schritt ist entscheidend für den durchgängigen automatisierten Workflow.
- Edge Image Handling (Die Kernlösung für das Verteilungsproblem):
- Edge Registry (In-Cluster): Um die Edge-Knoten von externen Abhängigkeiten zu entkoppeln und Bandbreite zu sparen[30], wird eine Docker Registry direkt im K3s-Cluster (via Helm-Chart aus dem GitOps-Repo) betrieben.
- Deklarative Image-Liste (`EdgeImageSet` CRD): Ich habe eine Custom Resource Definition erstellt, die es mir erlaubt, im GitOps-Repo deklarativ festzulegen, welche Images (mit Digest) in der Edge Registry vorhanden sein sollen. Dies schließt die Lücke im Standard-GitOps-Flow.
- Automatisierte Synchronisation (Image Sync CronJob): Da fertige Open-Source-Controller für die `EdgeImageSet`-Logik rar sind (wie meine Recherche ergab), habe ich als pragmatische Lösung einen Kubernetes `CronJob` implementiert (ebenfalls als Helm-Chart im GitOps-Repo). Dieser Job liest periodisch die `EdgeImageSet`-CR und nutzt `skopeo copy`, um die deklarierten Images von der zentralen GitLab Registry in die lokale Edge Registry zu synchronisieren. Dies automatisiert den Prozess und adressiert die Konnektivitäts/Bandbreiten-Problematik[2], wenn auch nicht rein Event-basiert wie ein idealer Operator.
- K3s Registry Mirror: Über die `registries.yaml`-Datei (im Startup-Skript konfiguriert) wird K3s angewiesen, Image-Pulls von der zentralen Registry zur lokalen Edge Registry umzuleiten.
- Beispiel-Anwendungen (Spring Boot / Angular): Ein typischer Enterprise-Stack (Java/Spring im Backend, Angular im Frontend), wie er auch bei Logistikern wie Kühne+Nagel oder DHL zum Einsatz kommt[31], [60], dient als Platzhalter für die zu deployenden Workloads.
Workflow im Überblick (Diagramm)
sequenceDiagram participant Dev as Developer participant AppRepo as App Source Repo
(spring-app) participant CI as GitLab CI participant CentralReg as Central Registry
(GitLab) participant GitOpsRepo as GitOps Repository
(fleet-config) participant Fleet as Fleet (GitOps Engine) participant K8sRes as K8s Resources
Deployments/EdgeImageSet participant SyncJob as Image Sync CronJob participant EdgeReg as Edge Registry
(in-cluster) participant App as Application Pods
(spring-app) Dev->>AppRepo: 1. Push code change AppRepo->>CI: 2. Trigger pipeline CI->>CI: 3. Build Docker image CI->>CentralReg: 4. Push image with digest CI->>CentralReg: 5. Get image digest CI->>GitOpsRepo: 6. Update values.yaml and
edge-image-set.yaml Fleet->>GitOpsRepo: 7. Watch for changes Fleet->>K8sRes: 8. Apply changes
(Helm/kubectl) K8sRes->>SyncJob: 9. Trigger SyncJob->>SyncJob: 10. Read EdgeImageSet SyncJob->>CentralReg: Request images CentralReg->>EdgeReg: 11. skopeo copy EdgeReg->>App: 12. K3s nodes pull
images from edge registry
Die Reise: Herausforderungen & Lösungen (Meine Lernerfahrungen)
Der Aufbau dieses integrierten Systems war, wie erwartet, keine triviale Aufgabe. Auf dem Weg gab es diverse Hürden, die typisch für die Verknüpfung von IaC, Kubernetes-Bootstrapping, CI/CD und GitOps sind. Anstatt jeden einzelnen Fehler im Detail aufzuzählen, möchte ich die wichtigsten Lernfelder hervorheben:
- Infrastructure as Code & Bootstrapping: Die initiale Bereitstellung der VM und die korrekte Ausführung des Startup-Skripts (OS-Setup, K3s-Installation, Fleet-Installation, K3s-Konfiguration) erforderten mehrere Iterationen. Die Syntax von Terraform-Templates (`templatefile`) und die korrekte Handhabung von Shell-spezifischen Konstrukten (wie Heredocs `<
- CI/CD Pipeline Feinheiten: Die Automatisierung des Builds und der GitOps-Updates barg ihre eigenen Tücken. Angefangen bei der richtigen Build-Umgebung (Multi-Stage Dockerfiles für Java sind Gold wert!), über Probleme beim Pullen von Basis-Images im CI-Runner bis hin zur korrekten und sicheren Authentifizierung – sowohl beim Pushen des Images in die Registry als auch (ganz wichtig!) beim Pushen der Konfigurationsänderungen in das GitOps-Repository. Die Verwendung von SSH Deploy Keys mit GitLab “File”-Variablen statt Access Tokens erwies sich hier als die robusteste Lösung für den Git-Push. Auch die zuverlässige Ermittlung des Image-Digests nach dem Push (mit `skopeo inspect`) war ein wichtiger Schritt.
- GitOps & Kubernetes Debugging: Wenn die Automatisierungskette steht, beginnt das Debugging im Cluster. Warum synchronisiert Fleet nicht? (`kubectl describe gitrepo …` und Controller-Logs sind entscheidend!). Warum startet ein Pod nicht? (`kubectl describe pod …` zeigt Events wie `InvalidImageName` oder Volume-Mount-Fehler). Warum stürzt ein CronJob ab (`CrashLoopBackOff`)? (Container-Logs des Job-Pods prüfen!). Hier zeigt sich die Notwendigkeit, die verschiedenen Status und Logs der beteiligten Systeme (Fleet, Kubernetes API, Pods) systematisch zu analysieren.
Insgesamt war es eine wertvolle Erfahrung, die zeigt, wie wichtig Detailgenauigkeit bei Konfigurationen, ein gutes Verständnis der einzelnen Werkzeuge und ihrer Interaktion sowie eine systematische Herangehensweise an das Debugging sind.
Aktueller Status & Nächste Schritte
Der Prototyp hat einen Stand erreicht, bei dem die Infrastruktur via Terraform erstellt wird, K3s und Fleet über das Startup-Skript installiert werden und die GitLab CI-Pipeline erfolgreich Anwendungs-Images baut, in die GitLab Registry pusht und die Konfiguration im `fleet-config`-Repository (inkl. `EdgeImageSet`) aktualisiert. Fleet erkennt diese Änderungen und deployed die Helm-Charts, inklusive der Edge Registry und des Image Sync CronJobs.
Die nächsten Schritte sind nun primär die Validierung und Optimierung des Edge-Image-Workflows und der Anwendungen selbst:
- Verifizieren, dass der **Image Sync CronJob** korrekt läuft und die Images synchronisiert.
- Verifizieren, dass die **Anwendungs-Pods** von der Edge Registry pullen und starten.
- Die **Platzhalter-Anwendungen** mit Leben füllen.
- Den **Ingress** testen.
- Optional: Die Sicherheit erhöhen (z.B. **Sealed Secrets** für den SSH Deploy Key in der CI).
- Optional: Den CronJob durch einen echten **KubeRegistrySync Operator** ersetzen (mein geplantes Open-Source-Projekt).
Fazit
Die Umsetzung eines vollständigen GitOps-Workflows für Kubernetes am Edge ist komplex, aber die Vorteile – Automatisierung, Konsistenz, Skalierbarkeit und die Fähigkeit, auch unter schwierigen Bedingungen zuverlässig Software bereitzustellen – sind beträchtlich. Mein Prototyp zeigt einen gangbaren Weg auf, wie man mit Tools wie Terraform, K3s, Fleet, GitLab CI und einer pragmatischen Lösung für die Image-Verteilung (Edge Registry + Sync Job/CRD) eine solche Pipeline aufbauen kann.
Diese Reise hat mein Verständnis für die Herausforderungen und Lösungen im Edge-Bereich enorm vertieft. Ich hoffe, dieser Einblick in meinen Prozess und die gewonnenen Erkenntnisse ist nützlich und inspiriert vielleicht den einen oder anderen.