DEV Community

Frederik von der Heyden
Frederik von der Heyden

Posted on

85 Container. 1 Entwickler.

85 Container, 24 Datenbanken, 232 Cron-Jobs — und ein Gründer

Wenn ich jemandem sage, dass ich alleine arbeite, kommt meistens dieselbe Reaktion: Ungläubiges Staunen, gefolgt von der Frage, wie das funktionieren soll.

Die ehrliche Antwort: Es funktioniert nicht trotz der Komplexität. Es funktioniert wegen ihr.

Ich bin seit 14 Monaten dabei, ein System zu bauen, das die operative Arbeit übernimmt. Heute laufen 85 Container, 24 Datenbanken, 67 Domains und 232 Cron-Jobs. 1.087 Tasks hat das System seit dem ersten Tag selbständig erledigt, mit einer Erfolgsrate von 88 Prozent. Der Rest landet bei mir, aber nur weil ich es so eingestellt habe.

Das ist kein Zufallsergebnis. Es ist das Ergebnis von Dutzenden Fehlern, drei komplett verworfenen Architekturen und einem Prinzip, das ich erst nach Monaten wirklich verstanden habe: Nicht alles automatisieren. Die richtigen Dinge automatisieren.

Was ich falsch gemacht habe, bevor ich es richtig gemacht habe

Mein erster Instinkt war der klassische Fehler: Ich wollte alles automatisieren. Deployments, Tests, Monitoring, Backups, Rechnungsstellung, Kundenkommunikation. Gleichzeitig. Mit möglichst viel Code.

Das Ergebnis war ein fragiles Netz aus Shell-Skripten, das ich öfter reparieren musste als die Systeme, die es überwachen sollte. Ich hatte Automatisierung gebaut, die selbst Betreuung brauchte.

Der Wendepunkt kam, als ich anfing, meine eigenen Aufgaben zu kategorisieren. Nicht nach Zeitaufwand, sondern nach einer anderen Frage: Würde ein intelligenter Newcomer mit klaren Regeln dieselbe Entscheidung treffen wie ich?

Alles, worauf ich mit Ja antworten konnte, war ein Kandidat für Automatisierung. Alles andere war echte Arbeit.

Guard-Regeln statt Micromanagement

Das Konzept, das mein System träglich macht, heißt bei mir "Guard-Regeln". Es geht nicht darum, einem Agenten oder Skript zu sagen, was es tun soll. Sondern darum, klare Grenzen zu definieren, was es nicht darf.

Ein konkretes Beispiel: Mein Deployment-System entscheidet selbst, wann es ein Update einspielt. Aber es hat Guards:

# guard: nie deployen wenn health-check < 95%
# guard: kein deploy zwischen 22:00 und 06:00 local time
# guard: rollback automatisch wenn error-rate > 2% in ersten 10 minuten
# guard: bei db-migration immer snapshot vorher
Enter fullscreen mode Exit fullscreen mode

Das klingt simpel. Und das ist der Punkt. Die Regeln müssen so klar sein, dass sie keine Interpretation brauchen. Sobald ich anfange, Ausnahmen zu dokumentieren, ist das ein Zeichen, dass die Regel selbst falsch ist.

In 14 Monaten hatte ich drei automatische Rollbacks. Alle drei haben einen Produktionsausfall verhindert. Keinen davon habe ich bemerkt, bis ich am nächsten Morgen das Log geöffnet habe.

Crystallization statt Dokumentation

Das zweite Prinzip ist weniger technisch, aber mindestens so wichtig: Ich dokumentiere nicht mehr.

Klassische Dokumentation veraltet. Sobald ich etwas aufschreibe, ist es schon nicht mehr vollständig aktuell. Ich habe stattdessen ein System entwickelt, das ich "Crystallization" nenne: Jede Entscheidung, die ich zweimal treffe, wird zu einer Regel. Jede Regel, die zweimal angewendet wird, wird zu einer Konfiguration. Jede Konfiguration, die sich bewährt, wird Teil des Systems.

Das sieht in der Praxis so aus:

# crystallized-decisions/deployments.yml
version_bump:
  trigger: merge to main
  condition: tests_pass AND no_breaking_changes
  action: bump_patch
  rationale: "Frederik hat das 12x manuell entschieden. Immer gleich."

breaking_change_detection:
  check: conventional_commits
  keywords: [BREAKING, feat!, "!:"]
  action: require_manual_review
  rationale: "Dreimal falsch eingeschätzt. Regel schützt vor Wiederholung."
Enter fullscreen mode Exit fullscreen mode

Das Ergebnis ist kein Handbuch. Es ist ein lebendes Regelwerk, das wächst, weil ich es leben lasse.

Das beschreibe ich ausführlich in "Läuft ohne mich" — wie aus Einzelentscheidungen ein System wird, das selbst lernt, wann es Entscheidungen treffen darf und wann nicht.

Self-Healing statt Bereitschaftsdienst

Der dritte Baustein ist der, der mir am meisten Zeit zurückgegeben hat.

Ich war früher ständig erreichbar. Nicht weil meine Systeme so instabil waren, sondern weil ich keine klare Definition hatte, was einen menschlichen Eingriff rechtfertigt.

Heute hat jeder Service drei Eskalationsstufen:

Stufe 1: Self-Healing — Das System versucht es selbst zu lösen. Neustart, Cache leeren, Verbindung neu aufbauen. Kein Alert, kein Log-Eintrag auf Warnstufe. Nur eine stille Zählung.

Stufe 2: Alert mit Kontext — Wenn Self-Healing nach drei Versuchen scheitert, bekomme ich eine Nachricht. Nicht "Service X ist down", sondern: "Service X ist dreimal neu gestartet, Fehler ist [exakter Fehler], letzte erfolgreiche Anfrage war vor [Zeit], ähnlicher Fehler wurde [Datum] durch [Maßnahme] gelöst."

Stufe 3: Eskalation — Wenn ich nicht reagiere und der Fehler business-kritisch ist, greift ein weiterer Agent ein, der dokumentierte Recovery-Prozeduren ausführt.

def handle_service_failure(service, error, attempt):
    if attempt < 3:
        restart_service(service)
        log_silent(service, error, attempt)
    elif attempt == 3:
        context = build_error_context(service, error)
        send_alert(context, urgency="normal")
    else:
        if is_business_critical(service):
            run_recovery_procedure(service, error)
            send_alert(context, urgency="high")
Enter fullscreen mode Exit fullscreen mode

In den letzten sechs Monaten habe ich drei Nacht-Alerts bekommen. Vor dem System waren es wöchentlich mehrere.

Was die 12 Prozent Fehlerquote bedeuten

Die 88-Prozent-Erfolgsrate klingt gut. Was bedeuten die anderen 12 Prozent?

Die meisten davon sind keine Fehler im klassischen Sinne. Es sind Situationen, in denen das System korrekt erkannt hat, dass ein Mensch entscheiden muss. Neue Anforderungen, die außerhalb definierter Parameter liegen. Konflikte, die keine eindeutige Regel-Antwort haben. Edge Cases, die das Regelwerk noch nicht kennt.

Jeder dieser Fälle ist ein Lernmoment. Nach jedem manuellen Eingriff stelle ich mir dieselbe Frage: Warum konnte das System das nicht selbst lösen? Und dann ändere ich entweder die Regel oder akzeptiere, dass es keine Regel geben sollte.

Der Unterschied zwischen einem System, das 80 Prozent schafft, und einem, das 88 Prozent schafft, ist nicht mehr Code. Es ist ein besseres Verständnis davon, wo Regeln aufhören und Urteilsvermögen anfängt.

Was ich automatisieren würde, wenn ich nochmal anfangen würde

Wer das liest und überlegt, wo er anfangen soll: Nicht mit der Infrastruktur. Nicht mit Deployments oder CI/CD.

Fang mit Datenflüssen an. Welche Informationen bewegst du täglich von A nach B, weil du weißt, wie das geht, aber nicht, warum du persönlich dafür zuständig sein musst? Das sind die einfachsten Wins. Keine KI, kein Agenten-Framework. Nur klare Regeln und ein Skript, das sie ausführt.

Dann erst die Entscheidungslogik. Und dann, wenn beides läuft und du weißt, wo die Grenzen sind, die Autonomie.

Wichtigste Erkenntnisse

Guard-Regeln sind mächtiger als Micromanagement. Ein System, das weiß, was es nicht darf, ist zuverlässiger als eines, das für jeden Fall eine Anweisung braucht.

Crystallization schlägt Dokumentation. Regeln entstehen aus Wiederholung, nicht aus Vorsatz. Schreib auf, was du dreimal gleich entschieden hast.

Self-Healing braucht klare Eskalationsstufen. Nicht jeder Fehler braucht einen Menschen. Die Kunst ist, zu wissen, welcher es tut.

Die 12 Prozent sind kein Versagen. Sie sind das System, das weiß, wann es Grenzen hat.

Fang mit Datenflüssen an, nicht mit KI. Die meisten Automatisierungsprojekte scheitern, weil sie zu früh zu komplex werden.


Das Buch: Taschenbuch (24,99 EUR) https://amazon.de/dp/B0HDMT162J | E-Book (9,99 EUR) https://amazon.de/dp/B0HDMS2YQ9


Dieser Artikel wurde mit KI erstellt, auf Basis meiner eigenen Systeme und Praxiserfahrung.

Top comments (0)