Warum Ihre Datenbank eine eigene CI/CD-Pipeline braucht

Sie arbeiten an einer Anwendung, die täglich von echten Menschen genutzt wird. Wenn eine neue Funktion ausgeliefert werden soll, ändern Sie etwas am Code, schieben ihn durch die Pipeline, und eine neue Version wird in der Produktion deployed. Wenn etwas schiefgeht, rollen Sie auf die vorherige Version zurück, und innerhalb weniger Minuten ist alles wieder normal. Der Prozess fühlt sich reibungslos an, weil Ihre Anwendung keine wichtigen Daten in ihrem eigenen Code mitführt.

Stellen Sie sich nun vor, Sie müssen eine Spalte zur Benutzertabelle hinzufügen. Auf Ihrem Laptop führen Sie ALTER TABLE user ADD COLUMN ... aus, und es ist erledigt. Aber in der Produktion enthält diese Tabelle Millionen von Zeilen mit echten Benutzerdaten. Anwendungen lesen und schreiben jede Sekunde darauf. Einige Abfragen könnten brechen, wenn die neue Spalte die Indexstruktur verändert. Datenbankverbindungen könnten ein Timeout haben, wenn die Alter-Operation zu lange läuft.

Dies ist der grundlegende Unterschied, der Datenbankänderungen fundamental von Anwendungsänderungen unterscheidet. Und genau deshalb wird die Behandlung von Datenbankmigrationen wie normale Code-Deployments irgendwann zu echten Problemen führen.

Zustandslos vs. Zustandsbehaftet: Der Kernunterschied

Anwendungen sind zustandslos. Sie können eine Instanz beenden, durch eine neue ersetzen oder auf eine ältere Version zurückrollen, ohne etwas zu verlieren. Der Code kümmert sich nicht darum, wer ihn vorher genutzt hat. Jedes Deployment ist ein sauberer Austausch.

Datenbanken sind zustandsbehaftet. Sie enthalten Daten, die intakt, konsistent und für aktive Benutzer zugänglich bleiben müssen. Das Schema ist ein Vertrag zwischen Ihrer Anwendung und Ihren Daten. Wenn sich dieser Vertrag plötzlich oder falsch ändert, können Daten beschädigt werden, Anwendungen beginnen, Fehler zu werfen, und Benutzer verlieren den Zugriff.

Dieser Unterschied ändert alles daran, wie Sie Änderungen handhaben. Eine typische Anwendungspipeline prüft, ob der Code kompiliert, ob Tests bestehen, und deployed dann. Eine Datenbankpipeline muss schwierigere Fragen beantworten:

  • Ist diese Schemaänderung kompatibel mit der aktuell laufenden Anwendungsversion?
  • Wird diese Operation die Tabelle zu lange sperren?
  • Sind vorhandene Daten nach der Änderung noch lesbar?
  • Wenn etwas auf halbem Weg fehlschlägt, wie kommen Sie in einen sicheren Zustand zurück, ohne Daten zu verlieren?

Das Timing-Problem

Anwendungspipelines können jederzeit laufen, sogar mehrmals täglich. Sie pushen Code, die Pipeline läuft, und eine neue Version ist live. Der gesamte Prozess dauert Minuten.

Datenbankpipelines müssen oft zu bestimmten Zeiten laufen. Vielleicht während verkehrsarmer Stunden. Vielleicht nach Bestätigung, dass keine langlaufenden Transaktionen aktiv sind. Vielleicht nur nach einer manuellen Freigabe von jemandem, der die Produktionslast versteht.

Wenn eine Anwendungspipeline fehlschlägt, deployen Sie die vorherige Version neu. Einfach. Wenn eine Datenbankpipeline auf halbem Weg durch eine Migration fehlschlägt, haben Sie eine partielle Migration: die Hälfte der Änderungen angewendet, die Hälfte nicht. Dies ist eines der kniffligsten Probleme, und es erfordert sorgfältige Planung, bevor Sie die Pipeline überhaupt ausführen.

Kompatibilität ist keine Option

Wenn Sie eine neue Version Ihrer Anwendung deployen, erwartet sie ein bestimmtes Datenbankschema. Wenn Sie eine Migration ausführen, ändert sie dieses Schema. Wenn die beiden nicht übereinstimmen, geht etwas kaputt.

Die Herausforderung besteht darin, dass während eines Deployments sowohl die alte als auch die neue Version Ihrer Anwendung gleichzeitig laufen können. Blue-Green-Deployments, Canary-Releases und Rolling-Updates erzeugen alle ein Zeitfenster, in dem mehrere Anwendungsversionen aktiv sind. Ihr Datenbankschema muss gleichzeitig mit allen kompatibel sein.

Das bedeutet, Sie können nicht einfach eine Spalte hinzufügen und sofort im selben Deployment verwenden. Sie benötigen einen mehrstufigen Ansatz: Fügen Sie zuerst die Spalte hinzu, ohne sie zu verwenden, deployen Sie die Anwendung, und verwenden Sie die Spalte dann in einem späteren Deployment. Dieses abwärtskompatible Migrationsmuster ist für Zero-Downtime-Deployments unerlässlich und erfordert Koordination zwischen Ihrer Anwendungspipeline und Ihrer Datenbankpipeline.

Warum separate Pipelines

Sie könnten versucht sein, Datenbankmigrationen als Schritt in Ihre Anwendungspipeline aufzunehmen. Schließlich sind beide Teil der Auslieferung einer Funktion. Aber die Vermischung verursacht mehrere Probleme:

Das folgende Flussdiagramm zeigt, wie sich die beiden Pipelines in Komplexität und Sicherheitsprüfungen unterscheiden:

flowchart TD subgraph App[Application Pipeline] A1[Code commit] --> A2[Build] A2 --> A3[Unit tests] A3 --> A4[Deploy to staging] A4 --> A5[Integration tests] A5 --> A6[Deploy to production] A6 --> A7[Monitor] end subgraph DB[Database Pipeline] B1[Migration script commit] --> B2[Syntax validation] B2 --> B3[Dry-run on staging] B3 --> B4[Schema diff check] B4 --> B5[Performance impact analysis] B5 --> B6[Run migration on staging] B6 --> B7[Verify] B7 --> B8[Run migration on production] B8 --> B9[Verify] end

Ihre Anwendungspipeline läuft bei jeder Codeänderung. Datenbankmigrationen sollten nur laufen, wenn sich das Schema tatsächlich ändert. Das Ausführen unnötiger Migrationen erhöht das Risiko und verlangsamt Deployments.

Anwendungs-Rollbacks sind einfach. Datenbank-Rollbacks sind es nicht. Wenn Ihre Pipeline beides bündelt, könnte das Zurückrollen der Anwendung auch eine Datenbankänderung zurückrollen, die zu Datenverlust führen würde.

Anwendungspipelines sind schnell. Datenbankmigrationen können langsam sein, besonders bei großen Tabellen. Eine langsame Migration kann Ihre gesamte Deployment-Pipeline blockieren und andere Änderungen aufhalten, die die Datenbank gar nicht betreffen.

Anwendungspipelines gehen von zustandslosen Umgebungen aus. Datenbankpipelines müssen den aktuellen Zustand des Schemas, das Datenvolumen und die Produktionslast verstehen. Dies sind grundlegend unterschiedliche Belange.

Wie eine gute Datenbankpipeline aussieht

Eine gut entworfene Datenbankpipeline muss nicht kompliziert sein. Sie muss nur die Natur zustandsbehafteter Systeme respektieren. Hier ist, was sie tun sollte:

Führen Sie jede Migration als wiederholbares Skript aus, das überprüft, getestet und konsistent ausgeführt werden kann. Jede Migration sollte eine einzelne Datei mit einer klaren Versionsnummer sein, die sowohl die Vorwärts- als auch die Rückwärtsschritte enthält.

Testen Sie Migrationen gegen eine Datenbank, die der Produktion sehr ähnlich ist. Nicht nur im Schema, sondern auch im Datenvolumen und in der Struktur. Eine Migration, die auf einer leeren Testdatenbank in einer Sekunde läuft, kann in der Produktion zwanzig Minuten dauern.

Führen Sie Migrationen in einer kontrollierten Reihenfolge aus, eine nach der anderen. Fassen Sie niemals mehrere Schemaänderungen in einer einzigen Operation zusammen. Jede Migration sollte klein, fokussiert und umkehrbar sein.

Überprüfen Sie das Ergebnis nach jeder Migration. Prüfen Sie, ob das Schema den Erwartungen entspricht, ob Indizes vorhanden sind und ob vorhandene Daten intakt sind.

Bieten Sie einen klaren Weg vorwärts oder rückwärts, wenn etwas schiefgeht. Das bedeutet, getestete Rollback-Skripte zu haben, zu wissen, wie lange sie dauern, und zu verstehen, welche Daten betroffen sein könnten.

Praktische Checkliste für Ihre Datenbankpipeline

Bevor Sie Ihre Datenbankpipeline einrichten, stellen Sie sicher, dass Sie diese Fragen beantworten können:

  • Kann jede Migration unabhängig ausgeführt werden, oder hängt sie davon ab, dass andere Migrationen zuerst ausgeführt werden?
  • Ist jede Migration umkehrbar, und haben Sie das Rollback getestet?
  • Funktioniert die Migration mit der aktuellen Anwendungsversion und der nächsten?
  • Wie lange wird die Migration bei Ihrem Produktionsdatenvolumen dauern?
  • Wird die Migration Tabellen sperren, und wenn ja, für wie lange?
  • Was passiert, wenn die Migration auf halbem Weg fehlschlägt?
  • Wer muss die Ausführung dieser Migration in der Produktion genehmigen?
  • Zu welcher Tageszeit sollte diese Migration ausgeführt werden?
  • Wie werden Sie überprüfen, ob die Migration erfolgreich war?

Das Fazit

Datenbankänderungen sind keine Codeänderungen. Sie arbeiten mit Live-Daten, betreffen aktive Benutzer und bergen echtes Risiko. Wenn Sie sie wie Anwendungscode behandeln, führt das irgendwann zu Ausfallzeiten, Datenproblemen oder beidem. Eine separate Pipeline für Datenbankänderungen gibt Ihnen die Kontrolle, Sicherheit und Vorhersagbarkeit, die Sie benötigen. Sie muss nicht komplex sein. Sie muss nur für das ausgelegt sein, was sie verwaltet: zustandsbehaftete, langlebige Daten, auf die Menschen angewiesen sind.