PostgreSQL hochverfügbar im Cluster betreiben mit KubeDB, Patroni, Spilo, Postgres-Operator oder Stolon?

Von: Niklas Resch
Datum: 20. April 2020

In der Cloud lassen sich Anwendungen mit mehreren Instanzen ausfallsicher betreiben. Der redundante Betrieb einer Datenbank mit Master/Slave Replikation erfordert manuelle Eingriffe wie z.B. Masterelection, Backups und Updates. Die Cloud kann, beispielsweise bei der Aktualisierung des Betriebssystems, nicht darauf warten, dass ein Administrator händische Eingriffe durchführt. KubeDB, Patroni und Stolon helfen bei der Automation dieser Aufgaben und ermöglichen einen ausfallsicheren Cloud nativen Betrieb von Datenbanken.

Den Zustand von relationalen Datenbanksystemen in der Cloud zu verwalten, ist schwer. Es besteht die Möglichkeit ein DBaaS (Database as a Service) des Cloud-Anbieters der Wahl zu verwenden oder sich selbst um den Betrieb zu kümmern.

1. Aufgaben der Clusterverwaltung

Es gibt eine Reihe von Aufgaben, die der Administrator manuell oder, besser, das Cluster automatisch erledigen sollte.

1.1. Garantieren der Verfügbarkeit

In der Cloud kommt es häufiger zum Hochfahren, Neustarten oder Herunterfahren von einzelnen Recheninstanzen. Sei es durch Updates oder die Erweiterung beziehungsweise die Minimierung des gesamten Clusters. Daher muss sichergestellt werden, dass immer die gewünschte Anzahl an Datenbankinstanzen vorhanden ist.

1.2. Korrekte Zuordnung von Dateien zu Datenbankinstanzen

Relationale Datenbanken, oder im speziellen PostgreSQL Datenbanken, laufen in Probleme, wenn zwei verschiedene Instanzen dieselbe Datei ändern. Es muss also sichergestellt werden, dass jede Datenbank daher zu exakt einer Datenbankinstanz gehört und nur von ihr verändert wird.

1.3. Bestimmung des führenden Systems

Daher wird, um Datenbankinstanzen wie PostgreSQL unter einander synchron zu halten, üblicherweise das Konzept einer "Master"-Instanz verwendet: Nur auf dieser Master-Instanz dürfen Änderungen durchgeführt werden. Die Master-Instanz zu bestimmen ist nicht einfach.

1.4. Schutz vor Datenverlust

Beim Ausfall des Master Knotens muss ein Slave zum neuen Master ernannt werden. Nur Slaves, die über eine Kopie aller abgeschlossenen Transaktionen verfügen eignen sich als Kandidaten.

Einzelne Applikationsinstanzen können in einem Kubernetes Cluster jederzeit beendet werden. Dies sollte einer Datenbankinstanz keine Probleme bereiten. Dafür verwendet sie intern das sogenannte WAL (Write-Ahead-Log). Würde die Datenbank außerplanmäßig beendet werden (z.B. Crash), würde diese bei einem Neustart eine Recovery durchführen. Hierbei wird überprüft, wie viele Transaktionen vor dem Crash die Festplatte erreicht haben und noch verwendet werden können. Es wäre fatal in einem Datenbank-Cluster, der das Überleben aller Transaktionen garantieren soll, einige zu verlieren.

1.5. Lösungsansätze und Produkte

Um diese Herausforderungen zu meistern, muss ein geeignetes Koordinationsverfahren implementiert werden. Das Koordinationsverfahren löst die Schwächen einer einzelnen Datenbankinstanz durch eigene Logik sowie die Kopplung mehrerer Datenbankinstanzen.

Natürlich ist es möglich, für alles Lösungen zu finden oder zu bauen, doch dies kostet Zeit und Nerven. Desweiteren muss das Rad nicht immer wieder neu erfunden werden. Es gibt verschiedene Werkzeuge, mit denen ein hochverfügbares Datenbanken Cluster aufgesetzt und gewartet werden kann. Beispiele für diese Werkzeuge sind KubeDB, Patroni, Spilo, Postgres-Operator und Stolon, die in diesem Artikel verglichen werden.

Die folgende Tabelle zeigt die "Beliebtheit" der verschiedenen Produkte in der Community:

\newpage

Stand 2020-04-06 KubeDB Patroni Spilo Postgres-Operator Stolon
Lizenz Apache 2.0 MIT Apache 2.0 MIT Apache 2.0
Erstes Release 2017-06 2015-09 2015-09 2018-08 2015-11
Github Stars 723 3148 621 982 2708
Letzter Commit 2019-12-21 2020-04-01 2020-04-01 2020-04-03 2020-03-20
Unterstützte DBs Elasticsearch, Memcached, MongoDB, MySQL, PostgreSQL, Redis PostgreSQL PostgreSQL PostgreSQL PostgreSQL

2. Was ist ein Operator?

Ein Vorarbeiter auf der Baustelle kennt sein Team und weiß, welche Aufgaben er an welche Mitarbeiter verteilen kann. Der Operator in der Cloud verhält sich ähnlich. Es wird ein gewisser Soll-Zustand an den Operator übermittelt. Seine Aufgabe ist der Vergleich zwischen dem Soll-Zustand und dem Ist-Zustand in der Cloud. Falls sich die beiden Zustände unterscheiden, müssen Aktionen ausgeführt werden, die den Ist-Zustand dem Soll-Zustand näher bringen. Diese Aufgabe wiederholt sich so lange, bis der Soll-Zustand erreicht ist.

Am Beispiel eines PostgreSQL-Clusters in einer Kubernetes Umgebung sähe der Ablauf wie folgt aus:

Soll-Zustand:

Betreibe ein 3-Knoten-PostgreSQL-Cluster!

Aktionen:

Starte 3 einzelne PostgreSQL Instanzen und verbinde diese.

Das Ergebnis wäre ein Master-Slave-Slave-System. Wer Master und wer Slave wird, entscheidet der Operator. Er ist die Instanz, die entscheidet, wann zu einem neuen Master gewechselt wird, falls der alte Master nicht mehr zur Verfügung steht.

Master-Slave-Slave-System

Abbildung : Die Abbildung zeigt ein solches Master-Slave-Slave-System und die Interaktion von Clients.

3. KubeDB

KubeDB ist, mit dem Postgres-Operator, ein relativ neues Framework, aus dem Hause AppsCode, mit dem Datenbanken-Operatoren geschrieben werden können. Es ist möglich folgende Produkte "produktionstauglich" zu betreiben:

  • Elasticsearch
  • Memcached
  • MongoDB
  • MySQL
  • Redis
  • PostgreSQL

Es muss ein sogenannter KubeDB-Operator auf dem Kubernetes Cluster installiert werden, der die Erstellung und Verwaltung weiterer Kubernetes Objekte übernimmt. Für die Erstellung eines hochverfügbaren PostgreSQL Clusters bestehend aus drei Knoten, genügt die Formulierung eines einfachen Kubernetes Objektes:

        apiVersion: kubedb.com/v1alpha1
        kind: Postgres
        metadata:
            name: ha-postgres
        spec:
            version: "10.6-v2"
            replicas: 3
            storage:
                storageClassName: "standard"
                accessMode:
                 - ReadWriteOnce
                resources:
                    requests:
                      storage: 1Gi
        

Aus dieser Beschreibung erzeugt der KubeDB-Operator ein hochverfügbares PostgreSQL Cluster mit drei Knoten.

3.1. Weitere Funktionen:

Über die grundlegenden Funktionen hinaus bietet KubeDB die folgenden Features:

  • Backups/Restore der Daten in/aus verschiedenen "Clouds"
  • Native Prometheus Integration mittels des CoreOS Prometheus Operators
  • "Deletion lock," um ungewollte Löschungen der Datenbank zu verhindern
  • Kommandozeilen-Tool ähnlich zu "kubectl," um Datenbanken zu verwalten

3.2. Besonderheiten

Der größte Unterschied zwischen KubeDB und anderen Operatoren liegt in der Anzahl der unterstützten Datenbanksysteme. KubeDB unterstützt sechs verschiedene Datenbanken. Im Vergleich dazu unterstützen die anderen, in diesem Test betrachteten Lösungen, ausschließlich die PostgreSQL Datenbank.

4. Patroni

Patroni ist ein Template für ein selbstkonfigurierbares PostgreSQL HA Cluster mit Python und einem verteilten Konfigurationsspeicher wie Zookeeper, etcd oder Consul. Zalando entwickelt dieses Projekt als eine Vorlage für weitere Projekte oder Implementationen, da es nach eigenen Angaben keine one-size-fits-all Lösung gibt.

Das Projekt entstand ursprünglich als ein Fork des Governor Projekts von Compose.

Aus diesem Template sind verschiedene Projekte von Zalando entstanden. Das Spilo Projekt beispielsweise hat Patroni in einem Docker Image verpackt und lässt sich leicht mittels eines Helm Charts auf Kubernetes bereitstellen. Ebenso gibt es den Postgres-Operator, der sich ähnlich zum KubeDB Projekt verhält.

Patroni bietet zwar die Möglichkeit, in Docker oder auch direkt in Kubernetes deployed zu werden, doch gibt es dafür aus dem Hause Zalando "bessere" Alternativen. Dieses Projekt dient vielmehr als Template und "Mutter"-Projekt, aus welchem weitere Projekte für spezielle Anwendungsfälle entstanden sind, oder noch entstehen können.

4.1. Besonderheiten

Patroni überzeugt durch die Anpassbarkeit. Dadruch, dass es sich um ein Template handelt, ist es theoretisch möglich, Patroni in verschiedenen Umgebungen auszuführen. Aufbauende Projekte, wie Spilo und der Postgres-Operator zeigen, wie es unter Docker und Kubernetes möglich ist.

5. Spilo

Spilo verpackt Patroni in ein Docker Image und stammt ebenso aus der Open Source Abteilung von Zalando. Der Name Spilo ist abgeleitet aus dem georgischen und bedeutet so viel wie Elefant.

Es gibt ein Helm-Chart, welches die Spilo Docker Images verwendet und ein 5-Knoten-PostgreSQL HA Cluster auf Kubernetes in einer GCE Umgebung deployed.

Die Entwickler von Spilo arbeiten zur Zeit fleißig am nächsten Projekt: Dem Postgres-Operator, der weiter unten beschrieben wird.

5.1. Besonderheiten

Spilo beschränkt sich in den Funktionen auf das absolute Minimum. Es wird lediglich Patroni in Docker verpackt. Ein Loadbalancer, der den Traffic an die Master-Instanz weiterleitet oder einen Operator, der neue Instanzen startet oder alte abschaltet, sucht man vergeblich. Dadurch lässt sich Spilo sehr gut an die gegebenen Vorraussetzungen im eigenen Umfeld anpassen.

6. Postgres-Operator

Der Postgres-Operator dient, wie der Name vermuten lässt, als Überwacher und Verwalter der PostgreSQL Datenbank. Der Operator wird durch CRDs (Custom-Resource-Definition) dazu aufgefordert, das PostgreSQL-Cluster zu erstellen, zu erweitern oder zu minimieren. Ein solches CRD kann wie folgt aussehen:

        yaml
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
  name: p8-test-cluster
  namespace: p8-test
spec:
  teamId: "p8"
  volume:
    size: 1Gi
  numberOfInstances: 3
  users:
    predic8:
    - superuser
    - createdb
  databases:
    p8-test: predic8
  postgresql:
    version: "12"

Diese Form der Konfiguration, macht eine Integration in die eigene automatisierte CI/CD Pipeline möglich.

Zalando entwickelt dieses Projekt aktiv weiter und setzt den Postgres-Operator, nach eigenen Angaben, seit über zwei Jahren in Produktion ein.

6.1. Features

Ebenso wie KubeDB bringt der Postgres-Operator verschiedene Funktionalitäten mit:

  • Rolling Updates
  • Speichergrößenveränderung ohne Neustart des Pods
  • DB Connection Pool
  • PostgreSQL-Cluster klonen
  • Backups zu einem S3 Bucket
  • Befüllen eines neuen Knotens durch ein S3 WAL Archiv
  • Eine UI zum Erstellen und Editieren des Clusters
  • Unterstützung aller PostgreSQL Versionen ab 9.6

6.2. Besonderheit

Der Postgres-Operator verbindet Patroni, gepackt in ein Spilo Docker Image, mit der einfachen Handhabung von Operatoren. Die Hauptaufgabe diese Operators ist das Management eines PostgreSQL-Clusters. Es wird lediglich eine Manifest-Datei benötigt, die alle Eigenschaften des gewünschten Clusters enthält. Dadurch ist es besonders einfach, den Operator durch eine CI/CD Pipeline mit Aufgaben zu versorgen.

7. Stolon

Stolon ist, ebenso wie der Postgres-Operator und KubeDB, ein Manager für ein PostgreSQL HA Cluster in der Cloud. Entwickelt wird dieser Manager von SORINTLab.

Stolon besteht aus 3 Hauptkomponenten:

  • keeper - Verwaltet die jeweilige PostgreSQL Instanz
  • sentinel - Erkennt und überwacht die verschiedenen Keepers und Proxies
  • proxy - Dient als Zugang für die Clients

7.1. Features

  • PostgreSQL streaming Replication
  • Jegliche Art der Partitionierung wird unterstützt, wobei mehr Wert auf Konsistenz als Verfügbarkeit gelegt wird
  • Kubernetes Integration
  • Verteilter Datenspeicher mittels der Registries etcd oder consul
  • Installation in "Minuten"
  • Einfache Administration über das stolonctl Kommandozeilen-Tool
  • Backups und Recovery

7.2. Besonderheit

Stolon vereinigt das, was Zalando mit Patroni, Spilo und dem Postgres-Operator in 3 Projekten macht, in einem. Das vereinfacht die Kommunikation in der Community und hilft bei der Fehlersuche.

8. Fazit

Ein PostgreSQL HA Cluster in der Cloud zu Betreiben ist nicht leicht. Es gibt einige Herausforderungen, die gelöst werden müssen, wie beispielsweise das Verhalten beim Ausfall einer Instanz.

Alle hier vorgestellen Lösungen sind relativ schwer von einander abzugrenzen. Im Endeffekt erstellen und warten alle ein PostgreSQL HA Cluster innerhalb von Kubernetes. Bei der Auswahl kommt es wie immer auf den Anwendungsfall an.

Ein Operator ist eine sinnvolle Art des Deployments innerhalb eines Kubernetes Clusters. Er hilft den Betriben von hochverfügbaren Datenbanken zu automatisieren. Das ist auch dringend notwendig, da im Cloud Umfeld ein Master-Wechsel wesentlich häufiger, durch Security Updates teilweise täglich, auftritt. Der händische Betrieb wäre viel zu aufwendig.

Die Möglichkeit ein ganzes Cluster aus mehreren Datenbank-Instanzen über eine kleine Textdatei zu konfigurieren und zu deployen nimmt einem Administrator viel Arbeit ab.