DELIVERY · 05 / 06

DevOps & Cloud

Delivery ist der Teil der Softwareentwicklung, der sich am schlechtesten improvisieren lässt. Wir bauen Pipelines, Container-Images und deklarative Infrastruktur so, dass ein Release reproduzierbar aus einem Commit entsteht, im Betrieb messbar ist und sich im Fehlerfall umkehren lässt. Dazu gehört auch die Entscheidung, welche Werkzeuge ein Projekt nicht braucht.

Ausgangslage

Woran es in der Praxis scheitert

Der häufigste Befund ist ein Build, der sich nicht wiederholen lässt. Abhängigkeiten werden ohne Lockfile aufgelöst, Basis-Images über den beweglichen Tag latest gezogen, und der Build-Agent trägt Werkzeuge in genau der Version, die vor zwei Jahren dort installiert wurde. Ein Artefakt aus dem Januar entsteht im Juli nicht mehr identisch aus demselben Commit. Damit ist jede Aussage über den Inhalt der laufenden Produktionsversion eine Vermutung.

Daneben steht das Deployment als Ritual: jemand verbindet sich per SSH, führt drei Skripte in der richtigen Reihenfolge aus und prüft danach von Hand, ob der Dienst antwortet. Das funktioniert, solange diese Person verfügbar ist. Rollback existiert selten als definierter Schritt, sondern als Rekonstruktionsversuch unter Zeitdruck. Freitags wird deshalb nicht ausgeliefert – ein zuverlässiges Symptom dafür, dass dem Prozess niemand traut.

Container-Images wachsen unbemerkt. Das Laufzeit-Image enthält Compiler, Paketmanager, Debug-Werkzeuge und den Git-Verlauf, läuft als root und bringt mehrere hundert Pakete mit, von denen der Dienst eine Handvoll benötigt. Jedes dieser Pakete erzeugt CVE-Meldungen, die niemand mehr bewertet. Gleichzeitig landen Zugangsdaten als Build-Argument in einem Layer und bleiben dort nachweisbar, auch wenn sie im finalen Dateisystem nicht mehr auftauchen.

Auf der Betriebsseite sehen wir zwei Extreme. Entweder fehlt Beobachtbarkeit fast vollständig: Logs liegen lokal auf den Hosts, Fehler melden Nutzer, über Latenzen existieren keine Zeitreihen. Oder es gibt hunderte Alarme, von denen ein Teil täglich feuert, sodass die Bereitschaft gelernt hat, sie zu ignorieren. Nicht selten läuft dazu ein Kubernetes-Cluster für drei Dienste, dessen Betrieb mehr Aufmerksamkeit verlangt als die Anwendung selbst.

Vorgehen

Wie wir Delivery aufbauen

Wir beginnen beim Artefakt. Abhängigkeiten werden über Lockfiles festgeschrieben, Basis-Images per Digest referenziert statt per Tag, und der Build läuft in einer Umgebung, deren Inhalt selbst versioniert ist. Multi-Stage-Builds trennen Kompilierung von Laufzeit: ausgeliefert wird ein Image mit Binary, Zertifikatsspeicher und den nötigen Laufzeitbibliotheken, sonst nichts. Es startet unter einer unprivilegierten UID, wo möglich mit schreibgeschütztem Root-Dateisystem. Da Layer entlang der Dockerfile-Reihenfolge gecacht werden, stehen selten geänderte Schritte oben.

Die Pipeline liegt als Code im Repository – als .gitlab-ci.yml oder als Workflow unter .github/workflows – und durchläuft feste Stufen: Formatprüfung, Tests, Build, Abhängigkeits- und Image-Scan, Signatur, Deployment. Gebaut wird genau einmal. Dasselbe Image wandert per Digest durch Staging und Produktion, statt pro Umgebung neu zu entstehen. Ein SBOM entsteht im Build und wird mit dem Artefakt aufbewahrt, sodass die Frage nach einer betroffenen Bibliothek eine Abfrage ist und keine Recherche.

Infrastruktur wird deklariert, nicht geklickt. Provisionierung beschreiben wir mit OpenTofu beziehungsweise Terraform in versionierten Modulen, Konfiguration mit idempotenten Ansible-Rollen. Der Zustand liegt in einem Remote-Backend mit Locking, jede Änderung wird als Plan im Merge Request gelesen und erst danach angewendet. Wiederkehrende Plan-Läufe machen Drift sichtbar, also Abweichungen durch manuelle Eingriffe. Secrets bleiben außerhalb der Repositories: verschlüsselt mit SOPS und age oder in einem Secret-Store, für die Pipeline mit kurzlebigen OIDC-Tokens statt dauerhafter Zugangsschlüssel.

Für das Ausrollen wählen wir die einfachste Strategie, die das Risiko trägt. Rolling Updates mit ernst gemeinten Readiness-Probes genügen häufig. Blue/Green lohnt, wenn ein Umschalten am Reverse Proxy sauberer ist als ein gemischter Zustand. Canary passt dort, wo genug Verkehr für eine statistische Aussage anliegt – mit vorab definierten Abbruchkriterien aus Fehlerrate und Latenz. Datenbankmigrationen rollen wir nach dem Muster expand/contract zweistufig aus, damit alte und neue Version gleichzeitig lauffähig bleiben. Erst das macht Rollback zu einem einzelnen Schritt.

Leistungsumfang

Was konkret dazugehört

01

CI/CD-Pipelines als Code
Pipeline-Definitionen im Repository, versioniert und im Review. Klare Stufen, bewusste Cache-Strategie und kurze Laufzeiten, damit die Pipeline nicht umgangen wird.

02

Container-Images mit kleiner Angriffsfläche
Multi-Stage-Builds auf schlanken Basen wie debian-slim, Alpine oder Distroless. Non-root, Basis per Digest gepinnt, Image-Scan im Build und regelmäßiger Rebuild statt Einmalprüfung.

03

Deployment-Strategien und Rollback
Rolling, Blue/Green oder Canary – begründet ausgewählt statt kopiert. Rollback ist definiert: bekanntes Vorgänger-Digest, migrationsverträgliches Schema, dokumentierte Reihenfolge.

04

Infrastructure as Code
OpenTofu- und Terraform-Module für Provisionierung, Ansible-Rollen für Konfiguration. Remote-State mit Locking, Plan im Merge Request, Drift-Erkennung über wiederkehrende Läufe.

05

Secrets und Pipeline-Zugriff
Verschlüsselung mit SOPS und age oder Anbindung an einen Secret-Store, kurzlebige OIDC-Tokens für Deployments, definierte Rotation. Keine Zugangsdaten in Images, Logs oder Repositories.

06

Observability: Metriken, Logs, Traces
Prometheus für Zeitreihen, Grafana für Dashboards, Loki für strukturierte Logs, OpenTelemetry für Traces. Trace-ID im Log, damit ein Vorfall über Dienstgrenzen hinweg rekonstruierbar bleibt.

07

Alerting, das ernst genommen wird
Alarme auf Symptome und Fehlerbudget-Verbrauch statt auf einzelne Ressourcenwerte. Jeder Alarm hat Empfänger und Runbook; ein Alarm ohne Handlungsoption wird gelöscht, nicht stummgeschaltet.

Einsatzfälle

Wann diese Leistung passt

Deployment ist Handarbeit

Auslieferung läuft über SSH, Shell-Skripte und eine Checkliste im Wiki, die eine Person im Kopf hat. Wir überführen den bestehenden Ablauf schrittweise in eine Pipeline mit Artefakt-Promotion, Health-Checks und definiertem Rollback.

Images sind gewachsen und unklar

Ein Laufzeit-Image von über einem Gigabyte, root als Nutzer, Build-Werkzeuge inklusive, Scanner-Report mit dreistelliger Zahl an Befunden. Wir zerlegen den Build in Stufen, pinnen die Basis und binden Scan und SBOM in die Pipeline ein.

Cloud-Ressourcen ohne dokumentierten Zustand

Netze, Instanzen und Firewall-Regeln sind über die Web-Konsole entstanden, niemand kennt den Sollzustand. Wir übernehmen den Bestand per Import in OpenTofu-Module und machen jede weitere Änderung über Plan und Review nachvollziehbar.

Monitoring liefert Rauschen

Dashboards existieren, Alarme feuern regelmäßig, reagiert wird nicht mehr. Wir definieren Service-Level-Ziele, leiten daraus wenige belastbare Alarme ab und ergänzen Logs und Traces so, dass die Ursachensuche nicht bei der Grafik endet.

Ergebnis

  • Jedes Release lässt sich aus einem Commit identisch neu bauen und per Digest nachweisen.
  • Rollback ist ein definierter Schritt mit bekanntem Zielzustand, keine Improvisation im Vorfall.
  • Laufzeit-Images enthalten nur, was der Dienst braucht: weniger CVE-Meldungen, kürzere Pull-Zeiten.
  • Infrastrukturänderungen sind im Merge Request lesbar, überprüfbar und wiederholbar.
  • Alarme haben Empfänger und Runbook: wer geweckt wird, weiß, was zu tun ist.
  • Die Delivery-Kette läuft auf offenen Werkzeugen und bleibt zwischen Anbietern portierbar.

Ablauf

Wie die Zusammenarbeit läuft

  1. 01 Analyse Bestandsaufnahme von System, Code und Betrieb. Am Ende steht eine belastbare Beschreibung des Ist-Zustands statt einer Vermutung.
  2. 02 Architektur Schnitt der Komponenten, Datenflüsse und Schnittstellen. Entscheidungen werden begründet und schriftlich festgehalten.
  3. 03 Entwicklung Umsetzung in kleinen, überprüfbaren Schritten. Jede Änderung ist nachvollziehbar, reviewbar und rückrollbar.
  4. 04 Automatisierung Alles, was mehr als einmal passiert, wird automatisiert: Build, Tests, Deployment und Infrastruktur.
  5. 05 Testing Tests dort, wo sie Risiko abdecken. Ziel ist Vertrauen in Änderungen, keine Abdeckungsquote als Selbstzweck.
  6. 06 Betrieb & Weiterentwicklung Software ist mit dem ersten Deployment nicht fertig. Betrieb, Beobachtbarkeit und Updates gehören zur Arbeit.

Fragen

Häufige Fragen zu DevOps & Cloud

Brauchen wir Kubernetes?

Häufig nicht. Für wenige Dienste mit überschaubarer Last trägt eine Kombination aus Container-Runtime, systemd-Units beziehungsweise Podman-Quadlets und einem Reverse Proxy sehr weit – bei deutlich geringerem Betriebsaufwand. Kubernetes lohnt, wenn viele Dienste, mehrere Teams, echte Autoskalierung oder eine bestehende Plattform es rechtfertigen. Wir bewerten das anhand Ihrer Last, Ihrer Teamgröße und der Frage, wer den Cluster später betreibt.

Können wir unser bestehendes CI-System behalten?

Ja. GitLab CI und GitHub Actions decken beide alles ab, was für reproduzierbare Builds, Scans und Deployments nötig ist; die Muster sind übertragbar. Ein Wechsel ist nur dann ein Thema, wenn konkrete Grenzen auftreten, etwa fehlende Runner-Isolation oder Lizenzmodelle, die Parallelität teuer machen.

Wie kommen Secrets in die Pipeline, ohne im Repository zu landen?

Konfiguration wird verschlüsselt versioniert, üblicherweise mit SOPS und age, oder zur Laufzeit aus einem Secret-Store bezogen. Die Pipeline authentifiziert sich per OIDC gegen das Zielsystem und erhält ein kurzlebiges Token, statt einen dauerhaften Zugangsschlüssel gespeichert zu halten. Secrets werden nie als Build-Argument übergeben, weil sie sonst im Image-Layer nachweisbar bleiben.

Wie funktioniert Deployment ohne Downtime bei Datenbankmigrationen?

Über zwei Schritte. Zuerst wird das Schema erweitert, sodass alte und neue Anwendungsversion gleichzeitig damit arbeiten können – neue Spalten nullable, keine Umbenennungen, Schreibpfade doppelt geführt. Nach dem Ausrollen und einer Beobachtungsphase entfernt ein zweiter Schritt die alten Strukturen. Ohne diese Trennung blockiert die Migration den Rollback.

Bindet uns eine Cloud-Migration an einen Anbieter?

Das hängt von den gewählten Bausteinen ab. Rechenleistung, Blockspeicher, S3-kompatibler Objektspeicher und managed PostgreSQL sind weitgehend austauschbar; proprietäre Funktionsplattformen, Event-Dienste und Identitätslösungen sind es nicht. Wir halten die Grenze bewusst und beschreiben Infrastruktur deklarativ, damit ein Wechsel eine Aufwandsfrage bleibt und keine Neuentwicklung.

Weiter im Zusammenhang

Kontakt

DevOps & Cloud besprechen

Beschreiben Sie kurz Ihr System und die offene Frage. Wir antworten mit einer fachlichen Einschätzung – ohne Vertriebsschleife.