Case-Study · Kubernetes mit 23 Microservices, ConfigMap aus Bash-Build-Script
Case-Study: ein einziges Komma legte 4 Stunden Production lahm
Bash-Script generierte JSON-Config, hängte versehentlich ein Komma an. Alle 23 Microservices crashten beim Boot. Schaden: 4h Downtime.
Metriken vor / nach
Größe / Volumen
1 KB Config
↓
1 KB Config
Parse / Laufzeit
crash beim Boot
↓
OK
Status
4 h Downtime
↓
Schema-Guard in CI
Maßnahmen
- ✓ Bash-Script reparieren (jq statt printf)
- ✓ Pre-Commit-Hook: JSON.parse-Validierung auf alle .json
- ✓ CI-Job: jsonschema-validate gegen config-schema.json
- ✓ K8s-Probe: failOnConfigError statt crash-loop
- ✓ PagerDuty-Runbook für JSON-Parse-Errors
Es war Freitagabend, 17:42. Der wöchentliche Release-Bot hatte eine neue ConfigMap deployed. Drei Minuten später kippten 23 Microservices nacheinander um - alle mit SyntaxError: Unexpected token } in JSON at position 743. Kubernetes versuchte fleißig neu zu starten und scheiterte sofort wieder.
Was war passiert?
Die Config wurde aus einem Bash-Build-Script zusammengebaut, das Feature-Flags aus einer YAML-Quelle iterierte und in JSON ausspuckte:
echo "{"
for flag in $(yq '.features[]' features.yaml); do
echo " \"$flag\": true,"
done
echo "}"
Klassischer Trailing-Comma-Bug. Nach dem letzten Flag stand ein Komma, bevor das schließende } kam. Striktes JSON akzeptiert das nicht. Niemand hatte die Datei manuell validiert.
Warum keiner es vorher gemerkt hat
Drei Probleme zusammen:
- Die Datei wurde erst im CI-Build-Job generiert - lokal lief die App mit einer hand-gepflegten Version.
- Der Build-Step prüfte den Exit-Code des Bash-Scripts, nicht den Inhalt der Datei.
- K8s deployt ConfigMaps eager, ohne Validierung.
Sofort-Maßnahmen (in der ersten Stunde)
- Manuelle Korrektur der ConfigMap (sed-replace des trailing Comma)
- Rolling-Restart aller Microservices
- Bash-Script auf jq umgebaut:
jq -n --argjson flags "$flagsJson" '{$flags}'
Strukturelle Maßnahmen (in der Woche danach)
- Pre-Commit-Hook: jeder Commit der .json-Files berührt durchläuft
node -e "JSON.parse(require('fs').readFileSync('FILE'))" - CI-Job: nach Config-Build wird die Datei gegen ein JSON-Schema validiert (Ajv mit additionalProperties: false), bricht den Build bei Fehler
- K8s-Probe-Pattern: Services lesen die Config beim Start, melden im /healthz Endpoint einen failOnConfigError-Status. K8s rolled-back automatisch wenn neue Pods nicht ready werden
- Runbook in PagerDuty: wenn mehrere Services gleichzeitig in crash-loop, sofort letzte ConfigMap-Änderung prüfen
Lehre
Auto-generiertes JSON aus Shell-Scripts ist immer ein Risiko, weil String-Concatenation keine Strukturkenntnis hat. jq existiert genau für diesen Zweck - es kann nur gültiges JSON ausgeben. Wenn das aus Legacy-Gründen nicht möglich ist: am Ende der Pipeline ein JSON.parse oder jq . FILE > /dev/null als Sanity-Check einbauen. Ein Lint-Failure im CI ist immer billiger als 4 Stunden Production-Down.