In diesem Leitfaden wird ausführlich beschrieben, wie Sie einen hochverfügbaren PostgreSQL-Stack in einer isolierten Google Distributed Cloud-Umgebung (GDC) über drei Zonen hinweg bereitstellen. Sie erfahren, wie Sie die erforderlichen Softwareartefakte vorbereiten, die Ziel-VMs booten und Autobase verwenden, um den gesamten Bereitstellungsprozess zu automatisieren. In diesem Leitfaden wird Patroni als primäre Verwaltungsebene verwendet, um den PostgreSQL-Lebenszyklus zu orchestrieren und automatische Failovers zu verarbeiten.
Architektur
Die Architektur besteht aus einer Umgebung mit drei VMs, die auf drei Verfügbarkeitszonen verteilt sind.

Jede VM ist identisch und führt einen gemeinsam genutzten Stack von Diensten aus:
- PostgreSQL 17: Das relationale Datenbankmodul.
- Patroni: Der Hochverfügbarkeitsmanager. Er verwaltet den Lebenszyklus des PostgreSQL-Prozesses und führt automatische Failovers durch. Er stellt eine HTTPS-REST API auf Port
8008(Endpunkt/primary) bereit, die vom Load-Balancer verwendet wird, um den aktuellen Leader zu identifizieren. - etcd: Der verteilte Konfigurationsspeicher (Distributed Configuration Store, DCS). Er bietet die Konsensschicht für die Leader-Wahl und speichert die Konfiguration von Patroni.
- PgBouncer: Ein Verbindungspooler, der vor PostgreSQL steht, um den Verbindungs-Overhead zu stabilisieren. Er bietet den empfohlenen Einstiegspunkt für Anwendungstraffic auf Port
6432.
Der Stack umfasst auch einen isolierten globalen L4-Load-Balancer von GDC, einen von der Plattform verwalteten Dienst, der eine stabile virtuelle IP-Adresse (VIP) bietet. Anwendungen stellen eine Verbindung zur stabilen VIP auf Port 6432 her, die der Load-Balancer an PgBouncer auf der aktuellen Leader-VM weiterleitet. PgBouncer leitet die Anfrage dann an die lokale PostgreSQL-Instanz weiter. Um den Trafficfluss zu verwalten, fragt der Load-Balancer die HTTPS-Endpunkte von Patroni kontinuierlich als Systemdiagnose ab.
Die Systemdiagnose auf der Leader-VM gibt HTTP 200 OK zurück, um zu signalisieren, dass die VM für Traffic bereit ist. Die Systemdiagnosen auf den Replikat-VMs geben HTTP 503 Service Unavailable zurück, um den Load-Balancer anzuweisen, sie zu umgehen. Wenn der Leader ausfällt, wird ein neuer Leader gewählt und seine Patroni-Instanz beginnt, HTTP 200 OK zurückzugeben. Dadurch leitet der Load-Balancer den Traffic automatisch an den PgBouncer-Port der neuen VM weiter.
Um Hochverfügbarkeit zu gewährleisten und Datenverlust zu verhindern, basiert der Stack auf dem Konzept eines Quorums. Bei drei VMs muss eine Mehrheit von mindestens zwei Mitgliedern fehlerfrei sein und kommunizieren, um einen Leader zu wählen und betriebsbereit zu bleiben. Dieser mehrheitsbasierte Konsens, der von etcd und Patroni verwaltet wird, ermöglicht es dem Stack, den vollständigen Ausfall einer einzelnen VM oder Zone automatisch zu tolerieren.
Hinweise zur Leistung
Berücksichtigen Sie bei der Planung Ihrer Bereitstellung die folgenden konkreten Faktoren, um Leistung und Zuverlässigkeit zu optimieren:
- Hardwaregröße: Die Anforderungen variieren je nach Arbeitslast. Verwenden Sie diese Standardprofile als Ausgangspunkt für jede VM:
- Entwicklung/Proof of Concept: 2 vCPUs, 8 GB RAM (Minimum für stabilen Betrieb).
- Kleine Produktion: 4 vCPUs, 16 GB RAM. Geeignet für interne Tools mit moderater Parallelität.
- Standardproduktion: 8 vCPUs, 32 GB RAM. Die empfohlene Baseline für geschäftskritische Anwendungen.
- Hoher Durchsatz: 16 oder mehr vCPUs, 64 GB oder mehr RAM. Für Arbeitslasten, die umfangreiches Daten-Caching im Arbeitsspeicher erfordern (gemeinsam genutzte PostgreSQL-Puffer).
- Speicherleistung: Hochleistungsspeicher ist unerlässlich. SSDs werden für die Stabilität von etcd dringend empfohlen. etcd reagiert sehr empfindlich auf die Latenz beim Schreiben auf das Laufwerk. Die offiziellen Hardware-Richtlinien für etcd empfehlen eine p99-Latenz für WAL-fdatasync von < 10 ms.
- Netzwerklatenz: Die Latenz zwischen VMs wirkt sich direkt auf die Replikationsleistung aus:
- etcd-Quorum: Die durchschnittliche Umlaufzeit (Round-Trip Time, RTT) sollte weniger als 50 ms (idealerweise weniger als 10 ms) betragen, um Zeitüberschreitungen bei der Wahl und Clusterinstabilität zu vermeiden.
- Synchrone Replikation: Wenn konfiguriert, muss jede Schreibtransaktion auf die Bestätigung eines Replikats warten. Die Latenz zwischen Zonen in einer isolierten GDC-Umgebung beträgt in der Regel weniger als 1 ms. Das ist hervorragend, um den Schreib-Overhead minimal zu halten (in der Regel 10–30%).
- Die Rolle von PgBouncer: PostgreSQL erstellt für jede Verbindung einen neuen Betriebssystemprozess, der etwa 10 MB RAM verbraucht und Kosten für den CPU-Kontextwechsel verursacht. PgBouncer reduziert diesen Overhead, indem ein Pool persistenter Verbindungen verwaltet wird. So kann die Datenbank Tausende von Anwendungsverbindungen mit deutlich weniger Backend-Prozessen verarbeiten.
- Sidecar-Komponenten: Patroni und etcd sind ressourcenschonend, erfordern aber eine konsistente CPU-Verfügbarkeit. In Szenarien mit hoher Last sollten Sie darauf achten, dass die VMs auf Hypervisor-Ebene nicht überlastet sind, um zu vermeiden, dass CPU-Zyklen „gestohlen“ werden, die für Heartbeats und die Leader-Wartung erforderlich sind.
- Kernel-Optimierung: Die Autobase-Automatisierung wendet automatisch Optimierungen
an, die für PostgreSQL von Vorteil sind, z. B. die Konfiguration von
sysctl
Parametern (z. B.
vm.swappiness,net.core.somaxconn) und die Deaktivierung von Transparent Huge Pages (THP). Diese Änderungen reduzieren den Overhead bei der Speicherverwaltung und verbessern den Netzwerkdurchsatz für Datenbankinstanzen mit hohem Traffic.
Hinweis
Bevor Sie mit der Bereitstellung beginnen, müssen Sie sicherstellen, dass Ihre Umgebung die folgenden Anforderungen erfüllt.
VM-Anforderungen prüfen
Für diese Anleitung müssen Sie drei VMs in Ihrem GDC mit Air Gap-Projekt erstellen. Sie müssen die folgenden Punkte und Anforderungen für die VMs berücksichtigen:
- Zonenverteilung: Damit diese Bereitstellung wirklich widerstandsfähig gegen Zonenausfälle ist, sollten Sie die VMs auf drei verschiedene Verfügbarkeitszonen verteilen. Die Bereitstellung bleibt jedoch identisch, wenn sich die VMs in zwei oder sogar einer einzigen Zone befinden. Am wichtigsten ist, dass alle VMs über ihre internen IP-Adressen über das Netzwerk miteinander kommunizieren können.
- Betriebssystem: In dieser Anleitung wird davon ausgegangen, dass Sie Ubuntu 22.04-Images verwenden. Die weiteren Schritte in diesem Leitfaden können abweichen, wenn Sie eine andere Distribution verwenden.
- Ressourcen: Für diese Anleitung sollten Sie mindestens 2 CPUs und 8 GB Arbeitsspeicher pro VM bereitstellen. In der Produktion müssen Sie Ressourcen bereitstellen, die für Ihre spezifischen Arbeitslasten geeignet sind (siehe Hinweise zur Leistung).
- Netzwerk-IPs: Sie sollten sich sowohl die internen als auch die externen IP-Adressen für jede VM notieren. In diesem Leitfaden verwenden Sie externe IPs für die Ansible-Steuerung, da Sie Befehle von einer externen Workstation aus ausführen. Interne IPs werden für die Kommunikation und Bindung zwischen Diensten verwendet. Wenn Sie eine Bootstrapper-VM im Netzwerk bereitgestellt haben, benötigen Sie nur die internen IPs.
- Zugriff: Für den Bereitstellungsnutzer ist ein passwortloser sudo-Zugriff erforderlich, da die Ansible-Automatisierung administrative Aufgaben ausführen muss (Pakete installieren, Systemkonfigurationen ändern), ohne durch Passworteingabeaufforderungen blockiert zu werden.
- SSH: Die schlüsselbasierte Authentifizierung muss aktiviert sein, damit Ansible sicher und nicht interaktiv eine Verbindung zu den Ziel-VMs herstellen kann.
Software für die lokale Workstation vorbereiten
Um die Bereitstellung zu verwalten und die isolierten Artefakte vorzubereiten, benötigen Sie eine Reihe von Automatisierungs- und Containerisierungstools, die auf Ihrer lokalen Workstation installiert sind.
- Ansible 2.17.0 oder höher: Die Automatisierungs-Engine, die die Bereitstellungs-Playbooks und -Rollen ausführt.
- Docker: Wird verwendet, um Betriebssystemabhängigkeiten in einer Umgebung abzurufen und zu verpacken, die mit den Ziel-VMs identisch ist (Ubuntu 22.04).
- PostgreSQL-Client (
psql): Erforderlich, um die Testabfragen auszuführen und die Datenreplikation von Ihrer lokalen Workstation aus zu prüfen. Das Autobase-Repository:
- Klonen Sie das Repository, um auf die Automatisierungs-Playbooks und -Rollen zuzugreifen: https://github.com/vitabaks/autobase
Checken Sie einen bestimmten Release aus (in diesem Leitfaden wird Version 2.5.2 verwendet):
git checkout 2.5.2Die weiteren Schritte in diesem Leitfaden können abweichen, wenn Sie eine andere Distribution verwenden.
Um die Playbooks in diesem Leitfaden auszuführen, müssen Sie den lokalen
autobase-Quellcode als Ansible-Sammlung installieren, damit die Rollenpräfixe aufgelöst werden können:cd autobase/automation ansible-galaxy collection install . --force
Umgebungsvariablen erstellen
In diesem Leitfaden verwenden Sie die folgenden Umgebungsvariablen, um Befehle zu vereinfachen. In diesen Variablen werden wichtige Parameter wie Ihre Projekt-ID, die Verfügbarkeitszonen für Ihre VMs, ihre Hostnamen und die Labels gespeichert, die vom Load-Balancer verwendet werden, um Ihren Cluster zu identifizieren. Legen Sie sie in Ihrer aktuellen Shell-Sitzung mit den tatsächlichen Werten für Ihre Umgebung fest (achten Sie darauf, dass die Zonen durch Leerzeichen getrennt sind).
Obwohl Sie beliebige Namen für Ihre VMs festlegen können, werden in diesem Leitfaden postgres-vm-1, postgres-vm-2 und postgres-vm-3 als willkürliche Beispielnamen für die Clusterknoten verwendet:
export PROJECT_ID="your-project-id"
export ZONES="zone1 zone2 zone3"
export VM1_NAME="postgres-vm-1"
export VM2_NAME="postgres-vm-2"
export VM3_NAME="postgres-vm-3"
export VM_LABEL="app=my-postgres-cluster"
export CLUSTER_NAME="my-postgres-cluster"
Ansible konfigurieren
Definieren Sie Ihre VM-Umgebung in der Datei inventory.ini mit der folgenden Vorlage:
[master]
postgres-vm-1 ansible_host=XX.XX.XX.XX hostname=postgres-vm-1 bind_address=XX.XX.XX.XX
[replica]
postgres-vm-2 ansible_host=XX.XX.XX.XX hostname=postgres-vm-2 bind_address=XX.XX.XX.XX
postgres-vm-3 ansible_host=XX.XX.XX.XX hostname=postgres-vm-3 bind_address=XX.XX.XX.XX
[postgres_cluster:children]
master
replica
[etcd_cluster]
postgres-vm-1
postgres-vm-2
postgres-vm-3
[all:vars]
ansible_user=...
ansible_ssh_private_key_file=~/.ssh/...
postgresql_version=17
with_haproxy_load_balancing=false
patroni_superuser_password=...
etcd_package_repo="file:///tmp/packages/etcd-v3.5.25-linux-amd64.tar.gz"
installation_method="packages"
install_postgresql_repo=false
install_timescale_repo=false
install_citus_repo=false
apt_repository=[]
yum_repository=[]
install_system_packages=false
patroni_installation_method=deb
Informationen zur Konfiguration:
[master]und[replica]: Definiert die primären und sekundären Datenbank-VMs. Verwenden Sie die tatsächlichen VM-Namen, die in den UmgebungsvariablenVM1_NAME,VM2_NAMEundVM3_NAMEfestgelegt wurden.[postgres_cluster:children]: Eine Gruppe, die sowohl die Master- als auch die Replikatknoten zusammenfasst, sodass Ansible den gesamten Datenbankcluster mit einem einzigen Befehl ansprechen kann.[etcd_cluster]: Definiert die Knoten, die am etcd-Konsenscluster teilnehmen. Dazu gehören alle drei Datenbankknoten, um Hochverfügbarkeit zu gewährleisten.ansible_host: (Für jede VM) Die externe Ingress-IP der VM, die von Ansible verwendet wird, um eine Verbindung zu dieser VM herzustellen. Ersetzen SieXX.XX.XX.XXdurch die tatsächliche externe IP-Adresse.bind_address: (Für jede VM) Die interne IP-Adresse der VM. Ersetzen SieXX.XX.XX.XXdurch die tatsächliche interne IP-Adresse.ansible_user: Der Remote-Nutzer, der von Ansible verwendet wird, um eine Verbindung zu den Ziel-VMs mit SSH herzustellen. Ersetzen Sie...durch den tatsächlichen Nutzernamen.ansible_ssh_private_key_file: Der lokale Pfad zum privaten SSH-Schlüssel, der für die Authentifizierung bei den Ziel-VMs verwendet wird. Ersetzen Sie~/.ssh/...durch den tatsächlichen Pfad.patroni_superuser_password: Das Passwort für denpostgres-Nutzer. Verwenden Sie hier ein starkes, sicheres Passwort.with_haproxy_load_balancing=false: Deaktiviert den lokalen HAProxy, da Sie den plattformnativen L4-Load-Balancer verwenden.etcd_package_repo: Verweist auf den lokalen Pfad der etcd-Binärdatei im Bootstrap-Verzeichnis der VM.installation_method="packages": Weist die Automatisierung an, Komponenten mit Betriebssystempaketen zu installieren, anstatt sie aus dem Quellcode zu kompilieren oder Python pip zu verwenden.install_..._repo=falseund_repository=[]: Diese Überschreibungen verhindern, dass Ansible versucht, eine Verbindung zum Internet herzustellen, um externe Repositories hinzuzufügen oder Paketlisten zu aktualisieren.install_system_packages=false: Verhindert, dass die Automatisierung versucht, Pakete herunterzuladen und zu installieren, die Sie bereits während der Initialisierungs- oder Bootstrap-Phase bereitgestellt haben.patroni_installation_method=deb: Weist die Rolle speziell an, das installierte.deb-Paket zu verwenden.
VMs initialisieren
Der Datenbank-Stack erfordert mehrere Betriebssystempakete und -bibliotheken, die möglicherweise nicht in Ihrem Ubuntu-Basis-Image enthalten sind. Da sich die VMs in einer isolierten Umgebung ohne Internetzugriff befinden, können sie diese Abhängigkeiten nicht selbst herunterladen.
Gehen Sie so vor, um dieses Problem zu beheben:
Verwenden Sie einen Docker-Container auf Ihrer lokalen Workstation, um alle erforderlichen Dateien herunterzuladen. Der folgende Befehl verwendet
apt-rdepends, um rekursiv alle freigegebenen Bibliotheken und Abhängigkeiten zu identifizieren, die von den Zielanwendungen benötigt werden. Er konfiguriert das offizielle PostgreSQL-Repository im Container, um Artefakte der Version 17 abzurufen, und durchläuft dann die Liste der Abhängigkeiten, um einzelne.deb-Dateien herunterzuladen. Dabei werden Kernsystembibliotheken (z. B.libc6oderhostname) herausgefiltert, um Versionskonflikte auf den Ziel-VMs zu vermeiden. Schließlich wird die eigenständige etcd-Binärdatei direkt von GitHub abgerufen.Erstellen Sie zuerst ein Verzeichnis für die Pakete:
mkdir -p ./packagesFühren Sie dann den Docker-Befehl aus, um alle erforderlichen Pakete und die etcd-Binärdatei herunterzuladen:
docker run --rm --platform linux/amd64 -v "$(pwd)/packages:/packages" \ ubuntu:22.04 bash -c " set -e apt-get update apt-get install -y ca-certificates curl gnupg apt-rdepends # Add PostgreSQL Repository curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \ gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg echo 'deb http://apt.postgresql.org/pub/repos/apt jammy-pgdg main' > \ /etc/apt/sources.list.d/pgdg.list apt-get update # Define Application Targets + Explicit dependencies needed for air-gap TARGETS='unzip tar pgbouncer patroni netdata postgresql-17 \ postgresql-client-17 postgresql-contrib-17 \ postgresql-server-dev-17 postgresql-17-dbgsym \ python3-psycopg2 python3-click python3-yaml python3-prettytable \ python3-urllib3 python3-tz python3-pip python3-setuptools \ python3-cryptography moreutils vim jq acl zstd libjq1 \ libpython3.10-stdlib libexpat1-dev zlib1g-dev libipc-run-perl \ libtime-duration-perl libjson-perl libpython3-dev \ libjs-sphinxdoc python3-wheel' # Resolve all recursive dependencies ALL_DEPS=\$(apt-cache depends --recurse --no-recommends --no-suggests \ --no-conflicts --no-breaks --no-replaces --no-enhances \$TARGETS | \ grep '^\w' | sort -u) cd /packages for pkg in \$ALL_DEPS; do if apt-cache show \"\$pkg\" > /dev/null 2>&1; then # Filter system core to avoid VM conflicts/breaks # We exclude core OS libraries (libc, systemd, etc.) because these # often cause version conflicts if the VM's patch level differs # from the online container. FILTER='base-files|debianutils|coreutils|findutils|diffutils|sed' FILTER+='|grep|gzip|hostname|ncurses|perl-base|libc6|binutils' FILTER+='|linux-libc|libc-bin|libc-dev-bin|systemd|dpkg|init' if [[ ! \"\$pkg\" =~ \$FILTER ]]; then apt-get download \"\$pkg\" || echo \"Failed \$pkg\" fi fi done # Download etcd binary if [ ! -f etcd-v3.5.25-linux-amd64.tar.gz ]; then curl -L https://github.com/etcd-io/etcd/releases/download/v3.5.25/\ etcd-v3.5.25-linux-amd64.tar.gz -o etcd-v3.5.25-linux-amd64.tar.gz fi "Verwenden Sie Ansible, um das Archiv gleichzeitig auf alle drei Ziel-VMs hochzuladen:
ansible all -i inventory.ini -m copy -a "src=packages.tar.gz dest=/tmp/" -bLöschen Sie alle vorhandenen Paketdaten auf den VMs und extrahieren Sie die neue tar-Datei:
ansible all -i inventory.ini -m shell -a "rm -rf /tmp/packages && \ mkdir -p /tmp/packages && tar -xzf /tmp/packages.tar.gz -C /tmp/packages" -bFühren Sie eine nicht interaktive Installation aller heruntergeladenen
.deb-Pakete durch. Um Probleme mit bestimmten Vorabhängigkeiten in einer isolierten Umgebung zu vermeiden, verwenden Sie das Flag--force-dependsgefolgt vonapt-get install -fy, um die Abhängigkeitsstruktur lokal aufzulösen:ansible all -i inventory.ini -m shell -a "DEBIAN_FRONTEND=noninteractive \ NEEDRESTART_MODE=a dpkg -i --force-depends /tmp/packages/*.deb" -b ansible all -i inventory.ini -m shell -a "DEBIAN_FRONTEND=noninteractive \ NEEDRESTART_MODE=a apt-get install -fy" -bBeenden Sie sofort alle Dienste, damit sie nicht mit Standardzuständen ohne Konfiguration gestartet werden, bevor die Automatisierung bereit ist:
ansible all -i inventory.ini -m shell -a \ "systemctl stop patroni etcd pgbouncer postgresql || true" -bEntfernen Sie schließlich die Standard-PostgreSQL-Cluster und alle vorhandenen etcd-Daten, um eine saubere Initialisierung zu ermöglichen:
ansible all -i inventory.ini -m shell -a \ "pg_dropcluster 17 main --stop || true" -b ansible all -i inventory.ini -m shell -a \ "rm -rf /var/lib/postgresql/17/main/* /var/lib/etcd/default.etcd/*" -b
Datenbankinfrastruktur bereitstellen
Nachdem die VMs gebootet und das Inventar konfiguriert wurde, können Sie jetzt die Autobase-Automatisierungs-Playbooks mit Ansible verwenden, um den hochverfügbaren PostgreSQL-Stack bereitzustellen.
Führen Sie zuerst die Vorabprüfungen aus, um sicherzustellen, dass die Umgebung bereit ist:
ansible-playbook vitabaks.autobase.deploy_pgcluster -i inventory.ini \
--tags pre_checks
Wenn die Prüfungen erfolgreich sind, fahren Sie mit der vollständigen Bereitstellung fort:
ansible-playbook vitabaks.autobase.deploy_pgcluster -i inventory.ini
Erwartete Ausgabe: Das Playbook sollte mit einer erfolgreichen Zusammenfassung (PLAY RECAP) abgeschlossen werden, in der alle Ziel-VMs als erreicht und aktualisiert angezeigt werden:
PLAY RECAP ********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=254 rescued=0 ignored=0
postgres-vm-1 : ok=160 changed=53 unreachable=0 failed=0 skipped=514 rescued=0 ignored=2
postgres-vm-2 : ok=116 changed=40 unreachable=0 failed=0 skipped=505 rescued=0 ignored=2
postgres-vm-3 : ok=116 changed=40 unreachable=0 failed=0 skipped=505 rescued=0 ignored=2
Bereitstellung prüfen
Nach Abschluss der Bereitstellung sollten Sie mehrere Prüfungen durchführen, um sicherzustellen, dass alle Komponenten ordnungsgemäß funktionieren.
HA-Status prüfen
Prüfen Sie den Status des Hochverfügbarkeitsmanagers, um die Rollen zu sehen, die jeder VM zugewiesen sind:
ansible master -i inventory.ini -m shell -a "patronictl list" -b
Beispielausgabe:
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Leader | running | 1 | | | | |
| postgres-vm-2 | 10.253.1.253 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
Systemdiagnose-Endpunkte prüfen
Testen Sie, ob Patroni den Leader und die Replikate mithilfe der REST API korrekt identifiziert.
Die Systemdiagnose der Leader-VM sollte 200 OK zurückgeben, während die Systemdiagnosen der Replikat-VMs 503 Service Unavailable zurückgeben sollten:
ansible ${VM1_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
ansible ${VM2_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
ansible ${VM3_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
Status der einzelnen VMs prüfen
Prüfen Sie die Bereitschaft aller PostgreSQL-Instanzen:
ansible postgres_cluster -i inventory.ini -m shell -a "pg_isready -p 5432" -b
Beispielausgabe:
postgres-vm-1 | CHANGED | rc=0 >>
/var/run/postgresql:5432 - accepting connections
postgres-vm-2 | CHANGED | rc=0 >>
/var/run/postgresql:5432 - accepting connections
postgres-vm-3 | CHANGED | rc=0 >>
/var/run/postgresql:5432 - accepting connections
etcd-Status prüfen
Prüfen Sie den Status der Konsensschicht auf allen VMs mit „localhost“ als Endpunkt:
ansible all -i inventory.ini -m shell -a "ETCDCTL_API=3 etcdctl \
--endpoints=https://localhost:2379 \
--cacert=/etc/etcd/tls/ca.crt \
--cert=/etc/etcd/tls/server.crt \
--key=/etc/etcd/tls/server.key \
endpoint health" -b
Beispielausgabe:
postgres-vm-1 | CHANGED | rc=0 >>
https://localhost:2379 is healthy: successfully committed proposal: \
took = 28.78311ms
postgres-vm-2 | CHANGED | rc=0 >>
https://localhost:2379 is healthy: successfully committed proposal: \
took = 33.081265ms
postgres-vm-3 | CHANGED | rc=0 >>
https://localhost:2379 is healthy: successfully committed proposal: \
took = 24.414291ms
Globalen Load-Balancer konfigurieren
Um eine stabile virtuelle IP-Adresse (VIP) für den Datenbank-Stack bereitzustellen, konfigurieren Sie den plattformnativen globalen L4-Load-Balancer mit der gdcloud-Befehlszeile.
Voraussetzungen:
- Sie benötigen die Rolle
load-balancer-adminin Ihrem Projekt. Wenden Sie ein Label auf Ihre VMs an, damit der Load-Balancer die Instanzen korrekt ansprechen kann, die er bedienen muss. Ersetzen Sie die Parameterwerte
kubeconfigdurch die entsprechendenkubeconfig-Dateien der Management API für jede Zone:kubectl --kubeconfig=ZONE_A_MANAGEMENT_API label VirtualMachine \ -n ${PROJECT_ID} \ ${VM1_NAME} \ ${VM_LABEL} kubectl --kubeconfig=ZONE_B_MANAGEMENT_API label VirtualMachine \ -n ${PROJECT_ID} \ ${VM2_NAME} \ ${VM_LABEL} kubectl --kubeconfig=ZONE_C_MANAGEMENT_API label VirtualMachine \ -n ${PROJECT_ID} \ ${VM3_NAME} \ ${VM_LABEL}
- Sie benötigen die Rolle
Definieren Sie die Zugriffsebene für den Load-Balancer. Legen Sie
EXTERNALfest, wenn Sie eine Verbindung von außerhalb des Netzwerks des Projekts herstellen müssen, oderINTERNAL, wenn der Zugriff nur innerhalb der VPC erforderlich ist. In dieser Anleitung verwenden wir eine externe Einrichtung:export LB_SCHEME=EXTERNALErstellen Sie eine Systemdiagnose. Der Load-Balancer verwendet die REST API von Patroni, um den Leader zu identifizieren:
gdcloud compute health-checks create https ${CLUSTER_NAME}-hc \ --project=${PROJECT_ID} \ --port=8008 \ --request-path="/primary" \ --check-interval=10 \ --timeout=5 \ --healthy-threshold=2 \ --unhealthy-threshold=3 \ --globalErstellen Sie für jede Zone, in der sich Ihre VMs befinden, ein separates zonales Backend:
for zone in $(echo $ZONES); do gdcloud compute backends create ${CLUSTER_NAME}-backend-${zone} \ --project=${PROJECT_ID} \ --zone=${zone} \ --labels="${VM_LABEL}" doneErstellen Sie einen globalen Backend-Dienst:
gdcloud compute backend-services create ${CLUSTER_NAME}-bes \ --project=${PROJECT_ID} \ --health-check="${CLUSTER_NAME}-hc" \ --globalFügen Sie dem globalen Dienst Ihre zonalen Backends hinzu:
for zone in $(echo $ZONES); do gdcloud compute backend-services add-backend ${CLUSTER_NAME}-bes \ --project=${PROJECT_ID} \ --backend=${CLUSTER_NAME}-backend-${zone} \ --backend-zone=${zone} \ --global doneErstellen Sie eine globale Weiterleitungsregel (die VIP). Diese Regel stellt die Datenbank auf Port
6432bereit:gdcloud compute forwarding-rules create ${CLUSTER_NAME}-fr \ --project=${PROJECT_ID} \ --load-balancing-scheme=${LB_SCHEME} \ --backend-service=${CLUSTER_NAME}-bes \ --ip-protocol-port="TCP:6432" \ --globalRufen Sie die VIP-Adresse ab:
LB_IP=$(gdcloud compute forwarding-rules describe ${CLUSTER_NAME}-fr \ --project=${PROJECT_ID} \ --load-balancing-scheme=${LB_SCHEME} \ --global \ --format=json \ | jq -r '.metadata.annotations["networking.gke.io/forwardingRuleCIDR"]' \ | cut -d '/' -f 1) echo "The load balancer IP is: ${LB_IP}"Erstellen Sie eine
ProjectNetworkPolicy(PNP), um eingehenden Traffic zum PgBouncer-Port zuzulassen. Ersetzen Sie den Parameterwertkubeconfigdurch die entsprechendekubeconfig-Datei der globalen API Ihrer Umgebung:kubectl --kubeconfig=GLOBAL_API_KUBECONFIG apply -f - <<EOF apiVersion: networking.global.gdc.goog/v1 kind: ProjectNetworkPolicy metadata: name: allow-pgbouncer namespace: ${PROJECT_ID} spec: ingress: - ports: - port: 6432 protocol: TCP policyType: Ingress subject: subjectType: UserWorkload EOF
Datenreplikation prüfen
Um zu bestätigen, dass der hochverfügbare Stack wie erwartet funktioniert, können Sie Beispieldaten auf dem Leader erstellen und prüfen, ob sie auf den Replikaten vorhanden sind.
Beispieldaten einfügen
Die Automatisierung generiert bei der ersten Bereitstellung ein zufälliges Passwort für den postgres-Nutzer, wenn in inventory.ini keines angegeben ist. Sie können es von jeder VM abrufen:
export PG_PASSWORD=$(ansible master -i inventory.ini -m shell -a \
"grep -A10 'authentication:' /etc/patroni/patroni.yml | \
grep -A3 'superuser' | grep 'password:' | awk '{ print \$2 }'" -b | \
tail -n 1)
echo $PG_PASSWORD
Stellen Sie eine Verbindung zur VIP des Load-Balancers auf dem PgBouncer-Port (6432) her und erstellen Sie eine Beispieltable:
PGPASSWORD="${PG_PASSWORD}" psql -h ${LB_IP} -p 6432 -U postgres -c "
CREATE TABLE employees (first_name TEXT, last_name TEXT);
INSERT INTO employees (first_name, last_name) VALUES ('John', 'Doe');
"
Erwartete Ausgabe:
INSERT 0 1
Replikationsstatus prüfen
Führen Sie eine SELECT-Abfrage auf allen VMs aus, um sicherzustellen, dass die Daten vom Leader auf alle Replikate repliziert wurden:
ansible postgres_cluster -i inventory.ini -m shell -a "psql -U postgres -c \
'SELECT * FROM employees;'" -b
Beispielausgabe:
postgres-vm-1 | CHANGED | rc=0 >>
first_name | last_name
------------+-----------
John | Doe
(1 row)
postgres-vm-2 | CHANGED | rc=0 >>
first_name | last_name
------------+-----------
John | Doe
(1 row)
postgres-vm-3 | CHANGED | rc=0 >>
first_name | last_name
------------+-----------
John | Doe
(1 row)
Manuellen Wechsel testen
Mit einem manuellen Wechsel können Sie die Leader-Rolle ordnungsgemäß auf eine bestimmte Kandidaten-VM verschieben. Dies wird in der Regel für geplante Wartungsarbeiten, Softwareupgrades oder zum Ausgleich der Ressourcennutzung über Zonen hinweg durchgeführt.
Aktuellen Leader identifizieren
Prüfen Sie die aktuelle Rolle und den Status der VMs:
ansible master -i inventory.ini -m shell -a "patronictl list" -b
Beispielausgabe:
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Leader | running | 1 | | | | |
| postgres-vm-2 | 10.253.1.253 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
Wechsel durchführen
Lösen Sie einen Wechsel vom aktuellen Leader zu einer anderen VM aus (in diesem Fall von postgres-vm-1 zu postgres-vm-2). Der Befehl verwendet --force, um manuelle Bestätigungsaufforderungen zu überspringen:
ansible master -i inventory.ini -m shell -a "patronictl switchover \
--leader ${VM1_NAME} --candidate ${VM2_NAME} --force" -b
Beispielausgabe:
Successfully switched over to "postgres-vm-2"
+ Cluster: postgres-cluster (7607933704953386478) -+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+---------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Replica | stopped | | unknown | | unknown | |
| postgres-vm-2 | 10.253.1.253 | Leader | running | 1 | | | | |
| postgres-vm-3 | 10.253.1.252 | Replica | running | 1 | 0/70000A0 | 0 | 0/70000A0 | 0 |
+---------------+--------------+---------+---------+----+-------------+-----+------------+-----+
Verschiebung der Systemdiagnose prüfen
Prüfen Sie nach dem Wechsel, ob sich der Status der Systemdiagnose auf den neuen Leader verschoben hat:
ansible ${VM1_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
ansible ${VM2_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
Der alte Leader (postgres-vm-1) sollte 503 zurückgeben, während der neue Leader (postgres-vm-2) 200 zurückgeben sollte.
Automatischen Failover testen
Im Gegensatz zu einem manuellen Wechsel tritt ein automatischer Failover auf, wenn die Leader-VM nicht mehr verfügbar ist. Dieser Test bestätigt, dass Patroni einen neuen Leader wählt und der Load-Balancer den Traffic ohne manuellen Eingriff weiterleitet. Angenommen, postgres-vm-2 ist nach dem zuvor durchgeführten manuellen Wechsel der aktuelle Leader.
Aktuellen Leader identifizieren
Prüfen Sie die aktuelle Rolle und den Status der VMs:
ansible master -i inventory.ini -m shell -a "patronictl list" -b
Beispielausgabe:
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Replica | streaming | 2 | 0/8000000 | 0 | 0/8000000 | 0 |
| postgres-vm-2 | 10.253.1.253 | Leader | running | 2 | | | | |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 2 | 0/8000000 | 0 | 0/8000000 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
VM-Ausfall simulieren
Beenden Sie den patroni-Dienst auf der Leader-VM, um einen Absturz oder einen schwerwiegenden Fehler zu simulieren:
ansible master -i inventory.ini -m shell -a "systemctl stop patroni" -b
Neue Wahl beobachten
Warten Sie 10 bis 20 Sekunden und prüfen Sie den Status von einer anderen VM aus, um die Beförderung eines neuen Leaders zu sehen:
ansible replica -i inventory.ini -m shell -a "patronictl list" -b
Beispielausgabe:
postgres-vm-3 | CHANGED | rc=0 >>
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Leader | running | 3 | | | | |
| postgres-vm-2 | 10.253.1.253 | Replica | stopped | | unknown | | unknown | |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 3 | 0/90003F8 | 0 | 0/90003F8 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
Sie sollten sehen, dass eine der anderen VMs (postgres-vm-1 oder postgres-vm-3) zum Leader geworden ist und der alte Leader (postgres-vm-2) als beendet markiert ist.
Verschiebung der Systemdiagnose prüfen
Prüfen Sie, ob die Systemdiagnosen des Load-Balancers den neu gewählten Leader jetzt korrekt identifizieren:
ansible ${VM1_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
Der neue Leader sollte 200 OK zurückgeben.
Ausgefallene VM wiederherstellen
Starten Sie den patroni-Dienst wieder auf der ursprünglichen VM, damit sie dem Stack als Replikat beitreten und alle verpassten Daten nachholen kann:
ansible ${VM2_NAME} -i inventory.ini -m shell -a \
"systemctl start patroni" -b