In dieser Anleitung erfahren Sie, wie Sie mit dem Zalando-Postgres-Operator Postgres-Cluster in Google Kubernetes Engine (GKE) bereitstellen.
PostgreSQL ist ein leistungsstarkes, objektrelationales Open-Source-Datenbanksystem, das über mehrere Jahrzehnte hinweg aktiv entwickelt wurde und sich einen guten Ruf für Zuverlässigkeit, Robustheit von Features und Leistung verdient hat.
Dieser Leitfaden richtet sich an Plattformadministratoren, Cloud-Architekten und Betriebsexperten, die PostgreSQL als Datenbankanwendung in GKE ausführen möchten, anstatt Cloud SQL für PostgreSQL zu verwenden.
Umgebung einrichten
So richten Sie Ihre Umgebung ein:
Legen Sie Umgebungsvariablen fest:
export PROJECT_ID=PROJECT_ID export KUBERNETES_CLUSTER_PREFIX=postgres export REGION=us-central1Ersetzen Sie
PROJECT_IDdurch Ihre Google Cloud Projekt-ID.Klonen Sie das GitHub-Repository:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samplesWechseln Sie in das Arbeitsverzeichnis:
cd kubernetes-engine-samples/databases/postgres-zalando
Clusterinfrastruktur erstellen
In diesem Abschnitt führen Sie ein Terraform-Skript aus, um einen privaten, hochverfügbaren regionalen GKE-Cluster zu erstellen.
Sie können den Operator mit einem Standard- oder Autopilot-Cluster installieren.
Standard
Das folgende Diagramm zeigt einen privaten regionalen Standard-GKE-Cluster, der in drei verschiedenen Zonen bereitgestellt wird:
Stellen Sie diese Infrastruktur bereit:
export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-standard init
terraform -chdir=terraform/gke-standard apply \
-var project_id=${PROJECT_ID} \
-var region=${REGION} \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
Geben Sie bei Aufforderung yes ein. Es kann einige Minuten dauern, bis dieser Befehl abgeschlossen ist und der Cluster den Status „Bereit“ anzeigt.
Terraform erstellt die folgenden Ressourcen:
- Ein VPC-Netzwerk und ein privates Subnetz für die Kubernetes-Knoten
- Ein Router für den Zugriff auf das Internet über NAT
- Ein privater GKE-Cluster in der Region
us-central1 - Knotenpools mit aktiviertem Autoscaling (ein bis zwei Knoten pro Zone, mindestens ein Knoten pro Zone)
- Ein
ServiceAccountmit Logging- und Monitoring-Berechtigungen - Backup for GKE zur Notfallwiederherstellung
- Google Cloud Managed Service for Prometheus für das Clustermonitoring
Die Ausgabe sieht in etwa so aus:
...
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
...
Autopilot
Das folgende Diagramm zeigt einen privaten regionalen Autopilot-GKE-Cluster:
Stellen Sie die Infrastruktur bereit:
export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-autopilot init
terraform -chdir=terraform/gke-autopilot apply \
-var project_id=${PROJECT_ID} \
-var region=${REGION} \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
Geben Sie bei Aufforderung yes ein. Es kann einige Minuten dauern, bis dieser Befehl abgeschlossen ist und der Cluster den Status „Bereit“ anzeigt.
Terraform erstellt die folgenden Ressourcen:
- Ein VPC-Netzwerk und ein privates Subnetz für die Kubernetes-Knoten
- Ein Router für den Zugriff auf das Internet über NAT
- Ein privater GKE-Cluster in der Region
us-central1 - Ein
ServiceAccountmit Logging- und Monitoring-Berechtigung - Google Cloud Managed Service for Prometheus für das Clustermonitoring
Die Ausgabe sieht in etwa so aus:
...
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
...
Mit dem Cluster verbinden
Konfigurieren Sie kubectl für die Kommunikation mit dem Cluster:
gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${REGION}
Zalando-Operator in Ihrem Cluster bereitstellen
Stellen Sie den Zalando-Operator mithilfe eines Helm-Diagramms in Ihrem Kubernetes-Cluster bereit.
Fügen Sie das Helm-Diagramm-Repository für den Zalando-Operator hinzu:
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operatorErstellen Sie einen Namespace für den Zalando-Operator und den Postgres-Cluster:
kubectl create ns postgres kubectl create ns zalandoStellen Sie den Zalando-Operator mit dem Helm-Befehlszeilentool bereit:
helm install postgres-operator postgres-operator-charts/postgres-operator -n zalando \ --set configKubernetes.enable_pod_antiaffinity=true \ --set configKubernetes.pod_antiaffinity_preferred_during_scheduling=true \ --set configKubernetes.pod_antiaffinity_topology_key="topology.kubernetes.io/zone" \ --set configKubernetes.spilo_fsgroup="103"Sie können die Einstellungen von
podAntiAffinitynicht direkt für die benutzerdefinierte Ressource konfigurieren, die den Postgres-Cluster darstellt. Legen Sie stattdessen diepodAntiAffinity-Einstellungen global für alle Postgres-Cluster in den Operatoreinstellungen fest.Prüfen Sie den Bereitstellungsstatus des Zalando-Operators mit Helm:
helm ls -n zalandoDie Ausgabe sieht in etwa so aus:
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION postgres-operator zalando 1 2023-10-13 16:04:13.945614 +0200 CEST deployed postgres-operator-1.10.1 1.10.1
Postgres bereitstellen
Die grundlegende Konfiguration für die Postgres-Clusterinstanz umfasst die folgenden Komponenten:
- Drei Postgres-Replikate: ein Leader und zwei Standby-Replikate.
- CPU-Ressourcenzuweisung: eine CPU-Anfrage und zwei CPU-Limits mit 4 GB Speicheranfragen und -Limits.
- Toleranzen,
nodeAffinitiesundtopologySpreadConstraints, die für jede Arbeitslast konfiguriert sind und eine ordnungsgemäße Verteilung auf Kubernetes-Knoten mithilfe ihrer jeweiligen Knotenpools und verschiedenen Verfügbarkeitszonen gewährleisten.
Diese Konfiguration stellt die minimale Einrichtung dar, die zum Erstellen eines produktionsfertigen Postgres-Clusters erforderlich ist.
Das folgende Manifest beschreibt einen Postgres-Cluster:
Dieses Manifest hat die folgenden Felder:
spec.teamIdist ein Präfix für die von Ihnen ausgewählten Clusterobjektespec.numberOfInstancesist die Gesamtzahl der Instanzen für einen Clusterspec.usersist die Nutzerliste mit Berechtigungenspec.databasesist die Datenbankliste im Formatdbname: ownernamespec.postgresqlsind die Postgres-Parameterspec.volumesind die Parameter für den nichtflüchtigen Speicherspec.tolerationsist die Toleranz-Pod-Vorlage, mit der Cluster-Pods aufpool-postgres-Knoten geplant werden könnenspec.nodeAffinityist die Pod-VorlagenodeAffinity, die GKE mitteilt, dass Cluster-Pods lieber aufpool-postgres-Knoten geplant werden sollen.spec.resourcessind Anfragen und Limits für Cluster-Podsspec.sidecarsist eine Liste der Sidecar-Container, diepostgres-exporterenthält
Weitere Informationen finden Sie in der Referenz zu Clustermanifesten in der Postgres-Dokumentation.
Einfachen Postgres-Cluster erstellen
Erstellen Sie mithilfe der grundlegenden Konfiguration einen neuen Postgres-Cluster:
kubectl apply -n postgres -f manifests/01-basic-cluster/my-cluster.yamlMit diesem Befehl wird eine benutzerdefinierte PostgreSQL-Ressource des Zalando-Betreibers mit folgenden Eigenschaften erstellt:
- CPU- und Speicheranforderungen und -limits
- Markierungen und Affinitäten, um die bereitgestellten Pod-Replikate auf GKE-Knoten zu verteilen.
- Eine Datenbank
- Zwei Nutzer mit Datenbankinhaberberechtigungen
- Ein Nutzer ohne Berechtigungen
Warten Sie, bis GKE die erforderlichen Arbeitslasten gestartet hat:
kubectl wait pods -l cluster-name=my-cluster --for condition=Ready --timeout=300s -n postgresDie Verarbeitung dieses Befehls kann einige Minuten dauern.
Prüfen Sie, ob GKE die Postgres-Arbeitslasten erstellt hat:
kubectl get pod,svc,statefulset,deploy,pdb,secret -n postgresDie Ausgabe sieht in etwa so aus:
NAME READY STATUS RESTARTS AGE pod/my-cluster-0 1/1 Running 0 6m41s pod/my-cluster-1 1/1 Running 0 5m56s pod/my-cluster-2 1/1 Running 0 5m16s pod/postgres-operator-db9667d4d-rgcs8 1/1 Running 0 12m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/my-cluster ClusterIP 10.52.12.109 <none> 5432/TCP 6m43s service/my-cluster-config ClusterIP None <none> <none> 5m55s service/my-cluster-repl ClusterIP 10.52.6.152 <none> 5432/TCP 6m43s service/postgres-operator ClusterIP 10.52.8.176 <none> 8080/TCP 12m NAME READY AGE statefulset.apps/my-cluster 3/3 6m43s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/postgres-operator 1/1 1 1 12m NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE poddisruptionbudget.policy/postgres-my-cluster-pdb 1 N/A 0 6m44s NAME TYPE DATA AGE secret/my-user.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m45s secret/postgres.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s secret/sh.helm.release.v1.postgres-operator.v1 helm.sh/release.v1 1 12m secret/standby.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s secret/zalando.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s
Der Operator erstellt die folgenden Ressourcen:
- Ein Postgres-StatefulSet, das drei Pod-Replikate für Postgres steuert
- Einen
PodDisruptionBudgets, wodurch mindestens ein verfügbares Replikat garantiert wird - Den
my-cluster-Dienst, der nur auf das Leader-Replikat abzielt - Der Dienst
my-cluster-repl, der den Postgres-Port für eingehende Verbindungen und für die Replikation zwischen Postgres-Replikaten freigibt - Den monitorlosen Dienst
my-cluster-configzum Abrufen der Liste der laufenden Postgres-Pod-Replikate - Secrets mit Nutzeranmeldedaten für den Zugriff auf die Datenbank und die Replikation zwischen Postgres-Knoten.
Bei Postgres authentifizieren
Sie können Postgres-Nutzer erstellen und ihnen Datenbankberechtigungen zuweisen. Das folgende Manifest beschreibt beispielsweise eine benutzerdefinierte Ressource, die Nutzern Rollen zuweist:
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
users:
mydatabaseowner:
- superuser
- createdb
myuser: []
databases:
mydatabase: mydatabaseowner
In diesem Manifest:
- Der
mydatabaseowner-Nutzer hat die RollenSUPERUSERundCREATEDB, die uneingeschränkte Administratorrechte gewähren (Verwaltung der Postgres-Konfiguration, neue Datenbanken, Tabellen und Nutzer erstellen, usw). Sie sollten diesen Nutzer nicht mit Kunden teilen. In Cloud SQL können Kunden beispielsweise nicht auf Nutzer mit der RolleSUPERUSERzugreifen. - Dem Nutzer
myusersind keine Rollen zugewiesen. Dies entspricht der Best Practice, mit derSUPERUSERNutzer mit den geringsten Berechtigungen zu erstellen. Detaillierte Rechte werdenmyuservonmydatabaseownergewährt. Aus Sicherheitsgründen sollten Siemyuser-Anmeldedaten nur für Clientanwendungen freigeben.
Passwörter speichern
Sie sollten die scram-sha-256
empfohlene Methode zum Speichern von Passwörtern verwenden. Das folgende Manifest beschreibt beispielsweise eine benutzerdefinierte Ressource, die die scram-sha-256-Verschlüsselung mithilfe des Felds postgresql.parameters.password_encryption angibt:
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
postgresql:
parameters:
password_encryption: scram-sha-256
Nutzeranmeldedaten rotieren
Sie können Nutzer-Anmeldedaten rotieren, die in Kubernetes-Secrets mit Zalando gespeichert sind. Das folgende Manifest beschreibt beispielsweise eine benutzerdefinierte Ressource, die die Rotation der Nutzeranmeldedaten mithilfe des Felds usersWithSecretRotation definiert:
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
usersWithSecretRotation:
- myuser
- myanotheruser
- ...
Beispiel für die Authentifizierung: Mit Postgres verbinden
In diesem Abschnitt erfahren Sie, wie Sie einen Postgres-Beispielclient bereitstellen und mit dem Passwort aus einem Kubernetes-Secret eine Verbindung zur Datenbank herstellen.
Führen Sie den Client-Pod aus, um mit Ihrem Postgres-Cluster zu interagieren:
kubectl apply -n postgres -f manifests/02-auth/client-pod.yamlDie Anmeldedaten der Nutzer
myuserundmydatabaseownerwerden aus den zugehörigen Secrets übernommen und als Umgebungsvariablen im Pod bereitgestellt.Stellen Sie eine Verbindung zum Pod her, wenn er bereit ist:
kubectl wait pod postgres-client --for=condition=Ready --timeout=300s -n postgres kubectl exec -it postgres-client -n postgres -- /bin/bashStellen Sie eine Verbindung zu Postgres her und versuchen Sie, mit
myuser-Anmeldedaten eine neue Tabelle zu erstellen:PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);"Der Befehl sollte mit einem Fehler wie dem folgenden fehlschlagen:
ERROR: permission denied for schema public LINE 1: CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR...Der Befehl schlägt fehl, weil Nutzer ohne zugewiesene Berechtigungen sich standardmäßig nur in Postgres anmelden und Datenbanken auflisten können.
Erstellen Sie eine Tabelle mit den Anmeldedaten
mydatabaseownerund gewähren Siemyuseralle Berechtigungen für die Tabelle:PGPASSWORD=$OWNERPASSWORD psql \ -h my-cluster \ -U $OWNERUSERNAME \ -d mydatabase \ -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);GRANT ALL ON test TO myuser;GRANT ALL ON SEQUENCE test_id_seq TO myuser;"Die Ausgabe sieht in etwa so aus:
CREATE TABLE GRANT GRANTFügen Sie mithilfe von
myuser-Anmeldedaten zufällige Daten in die Tabelle ein:for i in {1..10}; do DATA=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13) PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "INSERT INTO test(randomdata) VALUES ('$DATA');" doneDie Ausgabe sieht in etwa so aus:
INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1Rufen Sie die von Ihnen eingefügten Werte ab:
PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "SELECT * FROM test;"Die Ausgabe sieht in etwa so aus:
id | randomdata ----+--------------- 1 | jup9HYsAjwtW4 2 | 9rLAyBlcpLgNT 3 | wcXSqxb5Yz75g 4 | KoDRSrx3muD6T 5 | b9atC7RPai7En 6 | 20d7kC8E6Vt1V 7 | GmgNxaWbkevGq 8 | BkTwFWH6hWC7r 9 | nkLXHclkaqkqy 10 | HEebZ9Lp71Nm3 (10 rows)Beenden Sie die Pod-Shell:
exit
Informationen zum Erfassen von Messwerten für den Postgres-Cluster durch Prometheus
Das folgende Diagramm zeigt, wie die Erfassung von Prometheus-Messwerten funktioniert:
Im Diagramm enthält ein privater GKE-Cluster Folgendes:
- Einen Postgres-Pod, der Messwerte für den Pfad
/und den Port9187erfasst. - Prometheus-basierte Collectors, die die Messwerte aus dem Postgres-Pod verarbeiten.
- Eine
PodMonitoring-Ressource, die Messwerte an Cloud Monitoring sendet
Google Cloud Managed Service for Prometheus unterstützt die Messwerterfassung im Prometheus-Format. Cloud Monitoring verwendet ein integriertes Dashboard für Postgres-Messwerte.
Zalando stellt Clustermesswerte im Prometheus-Format bereit. Dabei wird die postgres_exporter-Komponente als Sidecar-Container verwendet.
Erstellen Sie die
PodMonitoring-Ressource, um Messwerte nachlabelSelectorzu extrahieren:kubectl apply -n postgres -f manifests/03-prometheus-metrics/pod-monitoring.yamlRufen Sie in der Google Cloud Console die Seite GKE-Cluster auf.
Im Dashboard wird eine Datenaufnahmerate ungleich null angezeigt.
Rufen Sie in der Google Cloud Console die Seite Dashboards auf.
Öffnen Sie das PostgreSQL Prometheus-Übersichts-Dashboard. Im Dashboard wird die Anzahl der abgerufenen Zeilen angezeigt. Es kann einige Minuten dauern, bis das Dashboard automatisch bereitgestellt wird.
Stellen Sie eine Verbindung zum Client-Pod her:
kubectl exec -it postgres-client -n postgres -- /bin/bashZufällige Daten einfügen:
for i in {1..100}; do DATA=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13) PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "INSERT INTO test(randomdata) VALUES ('$DATA');" doneAktualisieren Sie die Seite. Die Diagramme Zeilen und Blöcke werden aktualisiert, um den tatsächlichen Datenbankstatus anzuzeigen.
Beenden Sie die Pod-Shell:
exit