Blue-Green funktioniert hervorragend für zustandslose Apps. Beide Umgebungen teilen sich eine Datenbank — und unsere Schemaänderungen machten den Rollback genau dann unmöglich, als wir ihn brauchten.

Die Situation:

  • Neue Version auf Green deployen
  • Die neue Version führt beim Start ihre DB-Migration aus
  • Traffic auf Green umschalten
  • Eine Stunde später wird ein Bug entdeckt
  • Wir wollen auf Blue zurückrollen...
  • Aber Blue kann das neue Schema nicht lesen

Die destruktive Migration:

-- The migration that shipped with the green release
ALTER TABLE users DROP COLUMN legacy_id;
ALTER TABLE users RENAME COLUMN user_id TO id;

Der alte Code erwartet legacy_id und user_id. Beide sind weg. Der „sofortige Rollback“, der Blue-Green überhaupt erst gerechtfertigt hat, erfordert jetzt das Einspielen eines Backups oder das Handschreiben einer Rückwärtsmigration mitten im Incident — der denkbar schlechteste Zeitpunkt, um DDL zu schreiben.

Die Lösung — Expand/Contract, ausgearbeitet über drei Releases:

Release N (Expand). Die neue Spalte hinzufügen, ohne die alten anzufassen. Der Code schreibt doppelt, liest aber weiterhin die alte Spalte:

ALTER TABLE users ADD COLUMN id BIGINT;
-- backfill in batches to avoid long locks
UPDATE users SET id = user_id WHERE id IS NULL AND user_id < 100000;
-- ...repeat per batch, then:
CREATE UNIQUE INDEX CONCURRENTLY users_id_key ON users (id);

Rollback an dieser Stelle? Trivial — der alte Code sieht die neue Spalte nie.

Release N+1 (Reads migrieren). Der Code liest jetzt aus id, schreibt aber weiterhin beide Spalten. Vor dem nächsten Schritt einen Paritätscheck fahren, der die beiden Spalten vergleicht. Rollback? Ebenfalls unproblematisch — das vorherige Release schreibt noch doppelt, also veraltet keine der beiden Spalten.

Release N+2 (Contract). Erst wenn N+1 stabil gelaufen ist und die Query-Logs bestätigen, dass nichts mehr auf die alten Spalten verweist, werden sie gelöscht:

ALTER TABLE users DROP COLUMN legacy_id;
ALTER TABLE users DROP COLUMN user_id;

Der destruktive Schritt passiert weiterhin — aber zwei Releases nach der riskanten Codeänderung, wenn ein Rollback der App nicht mehr davon abhängt, dass die Spalten noch da sind.

Kernprinzip:

  • Jede Schemaänderung muss rückwärtskompatibel zum laufenden Release sein
  • Version N-1 muss mit Schema N funktionieren — das ist der Rollback-Vertrag
  • Niemals im selben Release löschen oder umbenennen, das etwas nicht mehr verwendet

Die Konfiguration leidet zwischen Blue und Green unter demselben Shared-State-Problem — auch das haben wir erlebt, beim Blue-Green-Config-Drift.

Lektion: Die Datenbank ist der schwierigste Teil von Blue-Green, weil sie weder blau noch grün ist — sie ist geteilt. Planen Sie ihre Migrationen explizit, als Teil der Deployment-Automatisierung und nicht als nachträglich an den App-Start geschraubten Gedanken.


← Zurück zu Lessons Learned

Incidents wie dieser sind vermeidbar. Unser AWS Managed Services-Team überwacht Kundenumgebungen 24/7 mit KI-gestütztem Monitoring und Senior Engineers auf dem Pager — damit Geschichten wie diese im Archiv bleiben.