json-formatieren.de

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:

  1. Die Datei wurde erst im CI-Build-Job generiert - lokal lief die App mit einer hand-gepflegten Version.
  2. Der Build-Step prüfte den Exit-Code des Bash-Scripts, nicht den Inhalt der Datei.
  3. 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)

  1. Pre-Commit-Hook: jeder Commit der .json-Files berührt durchläuft node -e "JSON.parse(require('fs').readFileSync('FILE'))"
  2. CI-Job: nach Config-Build wird die Datei gegen ein JSON-Schema validiert (Ajv mit additionalProperties: false), bricht den Build bei Fehler
  3. 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
  4. 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.