
Immer häufiger erhalten wir Anfragen von Kunden wie: „Wir wollen etwas wie Amazon RDS, aber günstiger“; „Wir möchten RDS, jedoch überall und in jeder Infrastruktur“. Um eine solche Managed-Lösung auf Kubernetes umzusetzen, haben wir uns die aktuellen Lösungen der gängigsten PostgreSQL-Operatoren (Stolon, Lösungen von Crunchy Data und Zalando) angesehen und unsere Entscheidung getroffen.
Dieser Artikel basiert auf unseren Erfahrungen sowohl aus theoretischer Sicht (Überblick über Lösungen) als auch aus praktischer Sicht (was ausgewählt wurde und welches Ergebnis erzielt wurde). Aber zuerst sollten wir klären, welche Anforderungen tatsächlich an einen potentiellen Ersatz für RDS gestellt werden…
Was ist eigentlich RDS?
Wenn Menschen von RDS sprechen, verstehen sie nach unserer Erfahrung in der Regel einen verwalteten (Managed) Datenbankdienst, der:
- einfach einzurichten ist;
- die Möglichkeit zur Arbeit mit Snapshots bietet und sich aus diesen wiederherstellen lässt (idealerweise mit Unterstützung von );
- ermöglicht die Erstellung von Master-Slave-Topologien;
- über eine umfangreiche Liste an Erweiterungen verfügt;
- Audit- und Benutzerverwaltungs-/Zugriffsoptionen bereitstellt.
Wenn wir allgemein sprechen, gibt es viele Ansätze zur Umsetzung der gestellten Aufgabe, jedoch ist der Weg mit Ansible für uns nicht geeignet. (Zu einem ähnlichen Schluss kamen auch die Kollegen von 2GIS aus ihrem Versuch, Betreiber sind der allgemein akzeptierte Ansatz zur Lösung solcher Aufgaben im Kubernetes-Ökosystem. Mehr dazu in Bezug auf Datenbanken, die innerhalb von Kubernetes ausgeführt werden, hat der technische Direktor von "Flanta" bereits in einem seiner Vorträge erzählt,
: Um einfache Operatoren schnell zu erstellen, empfehlen wir, unsere Open Source-Utility zu beachten. , in .
NBFür PostgreSQL gibt es mehrere beliebte K8s-Operatoren: Stolon;
Crunchy Data PostgreSQL Operator;
- Zalando Postgres Operator.
- Schauen wir uns diese genauer an.
- Die Wahl des Operators
Neben den wichtigen Funktionen, die bereits erwähnt wurden, erwarteten wir als Infrastruktur-Engineers im Kubernetes auch Folgendes von den Operatoren:
Deployment aus Git und mit
Custom Resources
- Unterstützung von Pod-Anti-Affinität; ;
- Unterstützung für Anti-Affinität;
- die Konfiguration von Node Affinity oder Node Selector;
- die Konfiguration von Tolerierungen;
- die Verfügbarkeit von Tuning-Möglichkeiten;
- verständliche Technologien und sogar Befehle.
Ohne auf die Details jedes Punktes einzugehen (fragen Sie in den Kommentaren, wenn nach dem Lesen des gesamten Artikels noch Fragen dazu bleiben), möchte ich insgesamt anmerken, dass diese Parameter für eine genauere Beschreibung der Spezialisierung der Clusterknoten notwendig sind, um sie für spezifische Anwendungen zu konfigurieren. So können wir ein optimales Gleichgewicht zwischen Performance und Kosten erreichen.
Kommen wir nun zu den PostgreSQL-Operatoren.
1. Stolon
von der italienischen Firma Sorint.lab in wurde als eine Art Benchmark unter den Operatoren für Datenbanken betrachtet. Es ist ein recht altes Projekt: Die erste öffentliche Veröffentlichung fand bereits im November 2015 statt(!), und das GitHub-Repository kann mit fast 3000 Sternen und über 40 Mitwirkenden aufwarten.
Und tatsächlich ist Stolon ein hervorragendes Beispiel für durchdachte Architektur:

Die Details dieses Operators finden Sie im Bericht oder . Insgesamt gesagt, ist es ausreichend zu erwähnen, dass er alles beschriebene beherrscht: Failover, Proxys für einen transparenten Zugang für Kunden, Backups… Zudem bieten Proxys Zugang über einen einzigen Service-Endpoint – im Gegensatz zu den zwei anderen Lösungen, die hier behandelt werden (dort gibt es jeweils zwei Dienste für den Zugang zur Datenbank).
Doch Stolon , weshalb es nicht möglich ist, ihn so zu deployen, dass man einfach und schnell – „wie frische Brötchen“ – Instanzen einer DBMS in Kubernetes erstellen kann. Die Verwaltung erfolgt über das Dienstprogramm stolonctl, das Deployment geschieht über das Helm-Chart, und Benutzerdefinierte Ressourcen werden in ConfigMap festgelegt.
Einerseits scheint es, dass der Operator nicht wirklich ein Operator ist (da er keine CRD verwendet). Andererseits ist es ein flexibles System, das es erlaubt, Ressourcen in K8s so anzupassen, wie es Ihnen passt.
Zusammenfassend erschien es uns nicht optimal, für jede DB ein eigenes Chart anzulegen. Daher begannen wir, nach Alternativen zu suchen.
2. Crunchy Data PostgreSQL Operator
, eines jungen amerikanischen Startups, erschien als logische Alternative. Seine öffentliche Geschichte beginnt mit dem ersten Release im März 2017. Seitdem hat das GitHub-Repository knapp 1300 Sterne und über 50 Mitwirkende erhalten. Die letzte Veröffentlichung im September wurde auf die Kompatibilität mit Kubernetes 1.15–1.18, OpenShift 3.11+ und 4.4+, GKE sowie VMware Enterprise PKS 1.3+ getestet.
Die Architektur des Crunchy Data PostgreSQL Operators erfüllt ebenfalls die angegebenen Anforderungen:

Die Verwaltung erfolgt über das Dienstprogramm pgo, welches seinerseits Custom Resources für Kubernetes generiert. Daher waren wir als potenzielle Benutzer erfreut, dass der Operator folgende Funktionen bietet:
- Verwaltung über CRD;
- benutzerfreundliche Verwaltung (ebenfalls über CRD);
- Integration mit anderen Komponenten — einer spezialisierten Sammlung von Container-Images für PostgreSQL und dazugehörigen Tools (einschließlich pgBackRest, pgAudit, Erweiterungen aus contrib usw.).
Bei dem Versuch, den Operator von Crunchy Data zu nutzen, traten jedoch einige Probleme auf:
- Es gab keine Möglichkeit, Tolerierungen zu nutzen — lediglich nodeSelector wurde vorgesehen.
- Die erstellten Pods waren Teil des Deployments, obwohl wir eine zustandsbehaftete Anwendung bereitgestellt haben. Im Gegensatz zu StatefulSets können Deployments keine Datenträger erstellen.
Der letzte Nachteil führte zu amüsanten Situationen: In der Testumgebung konnten 3 Replikate mit einem einzigen Datenträger gestartet werden, lokaler Speicher, was dazu führte, dass der Operator meldete, dass 3 Replikate laufen (was nicht der Fall war).
Eine weitere Besonderheit dieses Operators ist seine sofortige Integration mit verschiedenen Hilfsystemen. So lassen sich zum Beispiel pgAdmin und pgBounce problemlos installieren, während vorgestellte vorkonfigurierte Instanzen von Grafana und Prometheus berücksichtigt werden. In der jüngsten wurde die verbesserte Integration mit dem Projekt , wodurch der Operator eine anschauliche Visualisierung von PgSQL-Metriken „out of the box“ bietet.
Dennoch führte die seltsame Auswahl der erzeugten Kubernetes-Ressourcen dazu, dass wir eine andere Lösung finden mussten.
3. Zalando Postgres Operator
Die Produkte von Zalando sind uns schon lange bekannt: Wir haben Erfahrungen mit Zalenium und natürlich haben wir ihr beliebtes HA-Setup für PostgreSQL ausprobiert. Über den Ansatz des Unternehmens zur Erstellung des berichtete einer seiner Autoren – Alexey Klyukin – im , und es hat uns gefallen.
Dies ist die jüngste Lösung aus den in dem Artikel betrachteten: Die erste Veröffentlichung fand im August 2018 statt. Trotz einer geringen Anzahl formaler Releases hat das Projekt jedoch einen langen Weg zurückgelegt und bereits die Lösung von Crunchy Data mit über 1300 Sternen auf GitHub und der höchsten Anzahl an Mitwirkenden (über 70) überholt.
Unter der Haube dieses Operators kommen bewährte Lösungen zum Einsatz:
- Patroni und für das Management,
- für Backups,
- als Verbindungspool.
So sieht die Architektur des Operators von Zalando aus:

Der Operator wird vollständig über benutzerdefinierte Ressourcen verwaltet, erstellt automatisch ein StatefulSet aus Containern, das dann anpassbar ist, indem verschiedene Sidecars in den Pods hinzugefügt werden. Dies ist ein erheblicher Vorteil im Vergleich zum Operator von Crunchy Data.
Da wir uns für die Lösung von Zalando unter den 3 betrachteten Optionen entschieden haben, wird die weitere Beschreibung seiner Funktionen unten zusammen mit praktischen Anwendungen dargestellt.
Praktische Erfahrung mit dem Postgres Operator von Zalando
Das Deployment des Operators erfolgt sehr einfach: Es genügt, die aktuelle Version von GitHub herunterzuladen und die YAML-Dateien aus dem Verzeichnis anzuwenden. . Alternativ können Sie auch .
Nach der Installation sollten Sie die Konfiguration . Dies erfolgt über ConfigMap postgres-operator im Namensraum, in dem Sie den Operator installiert haben. Nachdem die Speicher konfiguriert sind, können Sie den ersten PostgreSQL-Cluster bereitstellen.
Zum Beispiel sieht unser Standard-Deployment wie folgt aus:
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
name: staging-db
spec:
numberOfInstances: 3
patroni:
synchronous_mode: true
postgresql:
version: "12"
resources:
limits:
cpu: 100m
memory: 1Gi
requests:
cpu: 100m
memory: 1Gi
sidecars:
- env:
- name: DATA_SOURCE_URI
value: 127.0.0.1:5432
- name: DATA_SOURCE_PASS
valueFrom:
secretKeyRef:
key: password
name: postgres.staging-db.credentials
- name: DATA_SOURCE_USER
value: postgres
image: wrouesnel/postgres_exporter
name: prometheus-exporter
resources:
limits:
cpu: 500m
memory: 100Mi
requests:
cpu: 100m
memory: 100Mi
teamId: staging
volume:
size: 2Gi
Dieses Manifest deployt einen Cluster mit 3 Instanzen mit einem Sidecar, das wir für die Metriken der Anwendung nutzen. Wie Sie sehen, ist es ganz einfach, und wenn Sie möchten, können Sie buchstäblich eine unbegrenzte Anzahl an Clustern erstellen.
Es ist auch wichtig, auf die Weboberfläche zur Verwaltung — . Es wird zusammen mit dem Operator bereitgestellt und ermöglicht das Erstellen und Löschen von Clustern sowie die Verwaltung von Backups, die der Operator erstellt.

Liste der PostgreSQL-Cluster

Backup-Verwaltung
Ein weiteres interessantes Merkmal ist die Unterstützung von . Dieser Mechanismus erstellt automatisch Rollen in PostgreSQL, basierend auf der erhaltenen Liste von Benutzernamen. Anschließend ermöglicht die API die Rückgabe einer Liste von Benutzern, für die automatisch Rollen erstellt werden.
Probleme und deren Lösungen
Die Nutzung des Operators hat jedoch bald mehrere wesentliche Nachteile aufgedeckt:
- fehlende Unterstützung für nodeSelector;
- Unmöglichkeit, Backups zu deaktivieren;
- bei der Verwendung der Funktion zum Erstellen von Datenbanken fehlen standardmäßig Berechtigungen;
- gelegentlich mangelt es an Dokumentation oder sie ist veraltet.
Glücklicherweise können viele von ihnen gelöst werden. Beginnen wir mit dem Ende – Probleme mit Dokumentation.
Wahrscheinlich werden Sie feststellen, dass es nicht immer klar ist, wie man ein Backup schreibt und wie man den Backup-Bucket mit der Operator UI verbindet. In der Dokumentation wird dies nur kurz erwähnt, während eine detaillierte Beschreibung in :
- ein Geheimnis erstellt werden muss;
- es muss dem Operator als Parameter übergeben werden.
pod_environment_secret_nameim CRD mit den Operator-Einstellungen oder in einem ConfigMap (je nachdem, wie Sie sich entschieden haben, den Operator zu installieren).
Wie sich herausgestellt hat, ist dies derzeit jedoch nicht möglich. Deshalb haben wir mit einigen zusätzlichen externen Arbeiten entwickelt. Weitere Informationen finden Sie unten.
Wenn man dem Operator Parameter für das Backup übergibt, nämlich wal_s3_bucket und die Zugangskeys für AWS S3, wird er alles sichern: nicht nur die Datenbanken in der Produktion, sondern auch in der Staging-Umgebung. Das war für uns nicht akzeptabel.
In der Beschreibung der Parameter zu Spilo, das die grundlegende Docker-Hülle für PgSQL bei Verwendung des Operators ist, stellte sich heraus: Man kann den Parameter WAL_S3_BUCKET leer übergeben, wodurch die Backups deaktiviert werden. Zudem hat sich zu unserer großen Freude auch ein , den wir sofort in unser Fork aufgenommen haben, gefunden. Jetzt reicht es, einfach enableWALArchiving: false zum PostgreSQL-Cluster-Ressourc hinzuzufügen.
Ja, es wäre möglich gewesen, es anders zu machen, indem man 2 Operatoren gestartet hätte: einen für Staging (ohne Backups) und einen für die Produktion. Aber so konnten wir mit einem auskommen.
Okay, wir haben gelernt, den Zugriff auf S3 für die Datenbanken zu gewähren, und die Backups landen nun im Speicher. Wie sollen wir die Backup-Seiten im Operator UI zum Laufen bringen?

In der Operator-Benutzeroberfläche müssen 3 Variablen hinzugefügt werden:
-
SPILO_S3_BACKUP_BUCKET -
AWS_ACCESS_KEY_ID -
AWS_SECRET_ACCESS_KEY
Nach dieser Anpassung wird die Verwaltung von Backups verfügbar sein, was in unserem Fall die Arbeit mit Staging vereinfachen wird, indem wir Snapshots aus der Produktion dorthin bereitstellen, ohne zusätzliche Skripte.
Ein weiterer Vorteil ist die Arbeit mit der Teams API und die umfangreichen Möglichkeiten zur Erstellung von Datenbanken und Rollen durch den Operator. Allerdings hatten die erstellten Rollen standardmäßig keine Berechtigungen.Daher konnte ein Benutzer mit Lesezugriff keine neuen Tabellen lesen.
Warum ist das so? Obwohl im Code die erforderlichen GRANTvorhanden sind, werden sie nicht immer angewendet. Es gibt 2 Methoden: syncPreparedDatabases und syncDatabasesIn syncPreparedDatabases — obwohl im Abschnitt preparedDatabases eine Bedingung vorhanden ist defaultRoles und defaultUsers um Rollen zu erstellen, werden die Standardberechtigungen nicht angewendet. Wir arbeiten an einem Patch, damit diese Berechtigungen automatisch angewendet werden.
Und der letzte Punkt in den für uns relevanten Verbesserungen ist — , die Node Affinity in das erstellte StatefulSet integriert. Unsere Kunden ziehen oft in Betracht, Kosten zu sparen, indem sie Spot-Instanzen nutzen, auf denen DB-Services eindeutig nicht platziert werden sollten. Dieses Problem könnte auch durch Tolerierungen gelöst werden, aber Node Affinity bietet eine größere Sicherheit.
Was ist das Ergebnis?
Nach der Lösung der genannten Probleme haben wir den Postgres Operator von Zalando in , wo er mit so nützlichen Patches zusammengestellt wird. Zur Erleichterung haben wir auch .
Eine Liste der PRs, die in den Fork aufgenommen wurden:
- ;
- ;
- ;
- .
Es wäre großartig, wenn die Community diese PRs unterstützt, damit sie in der nächsten Version des Operators (1.6) in den Upstream gelangen.
Bonus! Erfolgsgeschichte zur Migration von Production
Wenn Sie Patroni verwenden, können Sie mit dem Operator live Production mit minimalen Ausfallzeiten migrieren.
Spilo ermöglicht die Erstellung von Standby-Clustern über S3-Speicher mit , wenn das binäre PgSQL-Protokoll zuerst in S3 gespeichert und dann von einem Replikat extrahiert wird. Aber was tun, wenn Sie nicht Wal-E in einer alten Infrastruktur verwenden? Die Lösung dieses Problems ist bereits auf Habr.
Hier kommt die logische Replikation von PostgreSQL ins Spiel. Lassen Sie uns jedoch nicht in die Einzelheiten eintauchen, wie Publikationen und Abonnements erstellt werden, denn… unser Plan hat gefloppt.
Das Problem ist, dass es in der Datenbank mehrere stark belastete Tabellen mit Millionen von Zeilen gab, die zudem ständig hinzugefügt und gelöscht wurden. mit copy_data, bei dem die neue Replik alles vom Master kopiert, konnte einfach nicht mit dem Master Schritt halten. Die Datenübertragung lief eine Woche, aber holte den Master nicht ein. Schließlich half, das Problem zu lösen, ein Kollege von Avito: es ist möglich, die Daten zu übertragen, indem man pg_dump. Ich beschreibe unsere (leicht überarbeitete) Variante dieses Algorithmus.
Die Idee besteht darin, ein deaktiviertes Abonnement zu erstellen, das an einen bestimmten Replikationsslot gebunden ist, und dann die Transaktionsnummer zu korrigieren. Es gab Repliken für den Betrieb in der Produktion. Das ist wichtig, denn die Replik hilft, einen konsistenten Dump zu erstellen und weiterhin Änderungen vom Master zu empfangen.
In den folgenden Befehlen, die den Migrationsprozess beschreiben, werden die folgenden Bezeichnungen für Hosts verwendet:
- master — Quellserver;
- replica1 — Stream-Replikat auf der alten Produktionsumgebung;
- replica2 — neue logische Replikation.
Migrationsplan
1. Wir erstellen auf dem Master eine Publikation für alle Tabellen im Schema public Datenbank dbname:
psql -h master -d dbname -c "CREATE PUBLICATION dbname FOR ALL TABLES;"
2. Wir erstellen einen Replikationsslot auf dem Master:
psql -h master -c "select pg_create_logical_replication_slot('repl', 'pgoutput');"
3. Wir stoppen die Replikation auf der alten Replik:
psql -h replica1 -c "select pg_wal_replay_pause();"
4. Wir erhalten die Transaktionsnummer vom Master:
psql -h master -c "select replay_lsn from pg_stat_replication where client_addr = 'replica1';"
5. Wir erstellen ein Dump von der alten Replik. Wir werden dies in mehreren Streams tun, um den Prozess zu beschleunigen:
pg_dump -h replica1 --no-publications --no-subscriptions -O -C -F d -j 8 -f dump/ dbname
6. Wir laden das Dump auf den neuen Server:
pg_restore -h replica2 -F d -j 8 -d dbname dump/
7. Nach dem Laden des Dumps kann die Replikation auf der Stream-Replik gestartet werden:
psql -h replica1 -c "select pg_wal_replay_resume();"
8. Wir erstellen eine Publikation auf der neuen logischen Replik:
psql -h replica2 -c "create subscription oldprod connection 'host=replica1 port=5432 user=postgres password=secret dbname=dbname' publication dbname with (enabled = false, create_slot = false, copy_data = false, slot_name='repl');"
9. Wir erhalten oid der Publikation:
psql -h replica2 -d dbname -c "select oid, * from pg_subscription;"
10. Angenommen, wir haben erhalten oid=1000. Wir wenden die Transaktionsnummer auf die Publikation an:
psql -h replica2 -d dbname -c "select pg_replication_origin_advance('pg_1000', 'AA/AAAAAAAA');"
10. Lassen Sie uns die Replikation starten:
psql -h replica2 -d dbname -c "alter subscription oldprod enable;"
11. Überprüfen Sie den Status des Abonnements, die Replikation sollte aktiv sein:
psql -h replica2 -d dbname -c "select * from pg_replication_origin_status;"
psql -h master -d dbname -c "select slot_name, restart_lsn, confirmed_flush_lsn from pg_replication_slots;"
12. Nachdem die Replikation gestartet und die Datenbanken synchronisiert sind, kann der Umschalter vollzogen werden.
13. Nach der Deaktivierung der Replikation sollten die Sequenzen angepasst werden. Dies ist gut beschrieben .
Dank dieses Plans wurde der Umschaltvorgang mit minimalen Verzögerungen durchgeführt.
Fazit
Kubernetes-Operatoren vereinfachen verschiedene Aktionen, indem sie diese auf die Erstellung von K8s-Ressourcen reduzieren. Es ist jedoch wichtig zu bedenken, dass trotz der hervorragenden Automatisierung auch unerwartete Nuancen auftreten können, daher sollten Sie bei der Auswahl der Operatoren weise vorgehen.
Nachdem wir die drei beliebtesten Kubernetes-Operatoren für PostgreSQL untersucht hatten, entschieden wir uns für das Projekt von Zalando. Damit hatten wir einige Herausforderungen zu bewältigen, aber das Ergebnis hat uns wirklich erfreut, weshalb wir planen, diese Erfahrungen auch auf weitere PgSQL-Installationen auszuweiten. Wenn Sie Erfahrungen mit ähnlichen Lösungen haben, würden wir uns freuen, Ihre Details in den Kommentaren zu sehen!
P.S.
Lesen Sie auch in unserem Blog:
- «»;
- «»;
- «».
Quelle: habr.com
