PostgreSQL mit CloudNativePG in GKE bereitstellen

In dieser Anleitung erfahren Sie, wie Sie PostgreSQL-Cluster mit dem Operator CloudNativePG in Google Kubernetes Engine (GKE) bereitstellen.

PostgreSQL ist eine objektrelationale Open-Source-Datenbank mit seit mehreren Jahrzehnten aktiver Entwicklung, die für eine stabile Clientleistung sorgt. Es bietet eine Reihe von Features, darunter Replikation, Wiederherstellung zu einem bestimmten Zeitpunkt, Sicherheitsfeatures und Erweiterbarkeit. PostgreSQL ist mit wichtigen Betriebssystemen kompatibel und entspricht vollständig den ACID-Standards (Atomarität, Konsistenz, Isolation, Langlebigkeit).

Dieser Leitfaden richtet sich an Plattformadministratoren, Cloud-Architekten und Betriebsexperten, die an der Bereitstellung von Postgres-Clustern in GKE interessiert sind. Wenn Sie Postgres in GKE anstelle von Cloud SQL ausführen, können erfahrene Datenbankadministratoren mehr Flexibilität und Konfigurationskontrollen erhalten.

Vorteile

CloudNativePG ist ein Open-Source-Operator, der von EDB unter einer Apache 2-Lizenz entwickelt wurde. Es bietet folgende Features für die PostgreSQL-Bereitstellung:

  • Eine deklarative und Kubernetes-native Methode zum Verwalten und Konfigurieren von PostgreSQL-Clustern
  • Sicherungsverwaltung mit Volume-Snapshots oder Cloud Storage
  • Verschlüsselte TLS-Verbindung während der Übertragung, die Möglichkeit, Ihre eigene Zertifizierungsstelle zu verwenden und den Zertifikatmanager für die automatisierte Ausgabe und Rotation von TLS-Zertifikaten einzubinden
  • Rolling Updates für PostgreSQL-Nebenversionen
  • Verwendung des Kubernetes API-Servers zur Aufrechterhaltung des PostgreSQL-Clusterstatus und für Failover für Hochverfügbarkeit ohne zusätzliche Tools
  • Eine integrierte Prometheus-Exporter-Konfiguration über benutzerdefinierte Messwerte, die in SQL geschrieben werden.

Umgebung einrichten

So richten Sie Ihre Umgebung ein:

  1. Legen Sie Umgebungsvariablen fest:

    export PROJECT_ID=PROJECT_ID export KUBERNETES_CLUSTER_PREFIX=postgres export REGION=us-central1 

    Ersetzen Sie PROJECT_ID durch Ihre Google Cloud Projekt-ID.

  2. Klonen Sie das GitHub-Repository:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples 
  3. Wechseln Sie in das Arbeitsverzeichnis:

    cd kubernetes-engine-samples/databases/postgresql-cloudnativepg 

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:

Führen Sie die folgenden Befehle aus, um diese Infrastruktur bereitzustellen:

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)

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:

Führen Sie die folgenden Befehle aus, um die Infrastruktur bereitzustellen:

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 ServiceAccount mit 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} 

CloudNativePG-Operator bereitstellen

Stellen Sie die CloudNativePG mithilfe eines Helm-Diagramms in Ihrem Kubernetes-Cluster bereit:

  1. Fügen Sie das Helm-Diagramm-Repository für den CloudNativePG-Operator hinzu:

    helm repo add cnpg https://cloudnative-pg.github.io/charts 
  2. Stellen Sie den CloudNativePG-Operator mit dem Helm-Befehlszeilentool bereit:

    helm upgrade --install cnpg \     --namespace cnpg-system \     --create-namespace \     cnpg/cloudnative-pg 

    Die Ausgabe sieht in etwa so aus:

    Release "cnpg" does not exist. Installing it now. NAME: cnpg LAST DEPLOYED: Fri Oct 13 13:52:36 2023 NAMESPACE: cnpg-system STATUS: deployed REVISION: 1 TEST SUITE: None ... 

Postgres bereitstellen

Das folgende Manifest beschreibt einen PostgreSQL-Cluster, wie durch die benutzerdefinierte Ressource des CloudNativePG-Operators definiert:

apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata:   name: gke-pg-cluster spec:   description: "Standard GKE PostgreSQL cluster"   imageName: ghcr.io/cloudnative-pg/postgresql:16.2   enableSuperuserAccess: true   instances: 3   startDelay: 300   primaryUpdateStrategy: unsupervised   postgresql:     pg_hba:       - host all all 10.48.0.0/20 md5   bootstrap:     initdb:       database: app   storage:     storageClass: premium-rwo     size: 2Gi   resources:     requests:       memory: "1Gi"       cpu: "1000m"     limits:       memory: "1Gi"       cpu: "1000m"   affinity:     enablePodAntiAffinity: true     tolerations:     - key: cnpg.io/cluster       effect: NoSchedule       value: gke-pg-cluster       operator: Equal     additionalPodAffinity:       preferredDuringSchedulingIgnoredDuringExecution:       - weight: 1         podAffinityTerm:           labelSelector:             matchExpressions:             - key: app.component               operator: In               values:               - "pg-cluster"           topologyKey: topology.kubernetes.io/zone   monitoring:     enablePodMonitor: true

Dieses Manifest hat die folgenden Felder:

  • spec.instances: die Anzahl der Cluster-Pods
  • spec.primaryUpdateStrategy: die Rolling Update-Strategie:
    • Unsupervised: aktualisiert den primären Clusterknoten automatisch nach den Replikatknoten
    • Supervised: für den primären Clusterknoten ist ein manueller Switchover erforderlich
  • spec.postgresql: postgres.conf-Dateiparameterüberschreibungen, z. B. pg-hba-Regeln, LDAP und Anforderungen für die Erfüllung von Synchronisierungsreplikaten.
  • spec.storage: speicherbezogene Einstellungen wie Speicherklasse, Volume-Größe und Write-Ahead-Log-Einstellungen.
  • spec.bootstrap: Parameter der ersten im Cluster erstellten Datenbank, Nutzeranmeldedaten und Optionen zur Datenbankwiederherstellung
  • spec.resources sind Anfragen und Limits für Cluster-Pods
  • spec.affinity: Affinitäts- und Anti-Affinitätsregeln der Clusterarbeitslasten

Einfachen Postgres-Cluster erstellen

  1. Erstellen Sie einen Namespace:

    kubectl create ns pg-ns 
  2. Erstellen Sie den PostgreSQL-Cluster mit der benutzerdefinierten Ressource:

    kubectl apply -n pg-ns -f manifests/01-basic-cluster/postgreSQL_cluster.yaml 

    Die Ausführung dieses Befehls kann mehrere Minuten dauern.

  3. Prüfen Sie den Clusterstatus:

    kubectl get cluster -n pg-ns --watch 

    Warten Sie, bis die Ausgabe den Status Cluster in healthy state anzeigt, bevor Sie mit dem nächsten Schritt fortfahren.

    NAME             AGE     INSTANCES   READY   STATUS                     PRIMARY gke-pg-cluster   2m53s   3           3       Cluster in healthy state   gke-pg-cluster-1 

Ressourcen überprüfen

Prüfen Sie, ob GKE die Ressourcen für den Cluster erstellt hat:

kubectl get cluster,pod,svc,pvc,pdb,secret,cm -n pg-ns 

Die Ausgabe sieht in etwa so aus:

NAME                                        AGE   INSTANCES   READY   STATUS                     PRIMARY cluster.postgresql.cnpg.io/gke-pg-cluster   32m   3           3       Cluster in healthy state   gke-pg-cluster-1  NAME                   READY   STATUS    RESTARTS   AGE pod/gke-pg-cluster-1   1/1     Running   0          31m pod/gke-pg-cluster-2   1/1     Running   0          30m pod/gke-pg-cluster-3   1/1     Running   0          29m  NAME                        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE service/gke-pg-cluster-r    ClusterIP   10.52.11.24   <none>        5432/TCP   32m service/gke-pg-cluster-ro   ClusterIP   10.52.9.233   <none>        5432/TCP   32m service/gke-pg-cluster-rw   ClusterIP   10.52.1.135   <none>        5432/TCP   32m  NAME                                     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE persistentvolumeclaim/gke-pg-cluster-1   Bound    pvc-bbdd1cdd-bdd9-4e7c-8f8c-1a14a87e5329   2Gi        RWO            standard       32m persistentvolumeclaim/gke-pg-cluster-2   Bound    pvc-e7a8b4df-6a3e-43ce-beb0-b54ec1d24011   2Gi        RWO            standard       31m persistentvolumeclaim/gke-pg-cluster-3   Bound    pvc-dac7f931-6ac5-425f-ac61-0cfc55aae72f   2Gi        RWO            standard       30m  NAME                                                MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE poddisruptionbudget.policy/gke-pg-cluster           1               N/A               1                     32m poddisruptionbudget.policy/gke-pg-cluster-primary   1               N/A               0                     32m  NAME                                TYPE                       DATA   AGE secret/gke-pg-cluster-app           kubernetes.io/basic-auth   3      32m secret/gke-pg-cluster-ca            Opaque                     2      32m secret/gke-pg-cluster-replication   kubernetes.io/tls          2      32m secret/gke-pg-cluster-server        kubernetes.io/tls          2      32m secret/gke-pg-cluster-superuser     kubernetes.io/basic-auth   3      32m  NAME                                DATA   AGE configmap/cnpg-default-monitoring   1      32m configmap/kube-root-ca.crt          1      135m 

Der Operator erstellt die folgenden Ressourcen:

  • Eine benutzerdefinierte Clusterressource, die den vom Operator gesteuerten PostgreSQL-Cluster darstellt
  • PersistentVolumeClaim-Ressourcen mit entsprechenden nichtflüchtigen Volumes
  • Secrets mit Nutzeranmeldedaten für den Zugriff auf die Datenbank und die Replikation zwischen Postgres-Knoten.
  • Drei Datenbank-Endpunktdienste: <name>-rw, <name>-ro und <name>-r zum Herstellen einer Verbindung zum Cluster. Weitere Informationen finden Sie unter PostgreSQL-Architektur.

Bei Postgres authentifizieren

Sie können eine Verbindung zur PostgreSQL-Datenbank herstellen und den Zugriff über verschiedene vom Operator erstellte Dienstendpunkte prüfen. Dazu verwenden Sie einen zusätzlichen Pod mit einem PostgreSQL-Client und synchronisierten Anmeldedaten von Anwendungsnutzern, die als Umgebungsvariablen bereitgestellt wurden.

  1. Führen Sie den Client-Pod aus, um mit Ihrem Postgres-Cluster zu interagieren:

    kubectl apply -n pg-ns -f manifests/02-auth/pg-client.yaml 
  2. Führen Sie einen exec-Befehl auf dem Pod pg-client aus und melden Sie sich beim Dienst gke-pg-cluster-rw an:

    kubectl wait --for=condition=Ready -n pg-ns pod/pg-client --timeout=300s kubectl exec -n pg-ns -i -t pg-client -- /bin/sh 
  3. Melden Sie sich mit dem Dienst gke-pg-cluster-rw bei der Datenbank an, um eine Verbindung mit Lese-/Schreibberechtigungen herzustellen:

    psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-rw.pg-ns/app 

    Das Terminal beginnt mit dem Namen Ihrer Datenbank:

    app=> 
  4. Eine Tabelle erstellen:

    CREATE TABLE travel_agency_clients ( client VARCHAR ( 50 ) UNIQUE NOT NULL, address VARCHAR ( 50 ) UNIQUE NOT NULL, phone VARCHAR ( 50 ) UNIQUE NOT NULL); 
  5. Fügen Sie Daten in die Tabelle ein:

    INSERT INTO travel_agency_clients(client, address, phone) VALUES ('Tom', 'Warsaw', '+55555') RETURNING *; 
  6. Rufen Sie die von Ihnen erstellten Daten auf:

    SELECT * FROM travel_agency_clients ; 

    Die Ausgabe sieht in etwa so aus:

    client | address |  phone --------+---------+--------- Tom    | Warsaw  | +55555 (1 row) 
  7. Melden Sie sich von der aktuellen Datenbanksitzung ab:

    exit 
  8. Melden Sie sich mit dem Dienst gke-pg-cluster-ro bei der Datenbank an, um den Lesezugriff zu prüfen. Dieser Dienst ermöglicht das Abfragen von Daten, schränkt jedoch alle Schreibvorgänge ein:

    psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-ro.pg-ns/app 
  9. Versuchen Sie, neue Daten einzufügen:

    INSERT INTO travel_agency_clients(client, address, phone) VALUES ('John', 'Paris', '+55555') RETURNING *; 

    Die Ausgabe sieht in etwa so aus:

    ERROR:  cannot execute INSERT in a read-only transaction 
  10. Versuchen, Daten zu lesen:

    SELECT * FROM travel_agency_clients ; 

    Die Ausgabe sieht in etwa so aus:

    client | address |  phone --------+---------+--------- Tom    | Warsaw  | +55555 (1 row) 
  11. Melden Sie sich von der aktuellen Datenbanksitzung ab:

    exit 
  12. 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 Port 9187 erfasst.
  • Prometheus-basierte Collectors, die die Messwerte aus dem Postgres-Pod verarbeiten.
  • Eine PodMonitoring-Ressource, die Messwerte an Cloud Monitoring sendet

Führen Sie die folgenden Schritte aus, um das Erfassen von Messwerten aus Ihren Pods zu ermöglichen:

  1. Erstellen Sie die Ressource PodMonitoring:

    kubectl apply -f manifests/03-observability/pod-monitoring.yaml -n pg-ns 
  2. Rufen Sie in der Google Cloud Console die Seite Metrics Explorer auf:

    Zum Metrics Explorer

    Im Dashboard wird eine Datenaufnahmerate ungleich null angezeigt.

  3. Geben Sie unter Messwert auswählen den Wert Prometheus-Ziel ein.

  4. Wählen Sie im Bereich Aktive Messwertkategorien die Option Cnpg aus.

Messwert-Dashboard erstellen

Erstellen Sie ein Messwert-Dashboard, um die exportierten Messwerte zu visualisieren.

  1. Stellen Sie ein Dashboard bereit:

    gcloud --project "${PROJECT_ID}" monitoring dashboards create --config-from-file manifests/03-observability/gcp-pg.json 
  2. Rufen Sie in der Google Cloud Console die Seite Dashboards auf.

    Dashboards aufrufen

  3. Wählen Sie das Dashboard PostgresQL Prometheus – Übersicht aus.

    Wenn Sie prüfen möchten, wie Dashboards Funktionen überwachen, können Sie Aktionen aus dem Abschnitt Datenbankauthentifizierung wiederverwenden, Lese- und Schreibanfragen auf die Datenbank anwenden und die Visualisierung der erfassten Messwerte in einem Dashboard ansehen.

  4. Stellen Sie eine Verbindung zum Client-Pod her:

    kubectl exec -n pg-ns -i -t pg-client -- /bin/sh 
  5. Zufällige Daten einfügen:

    psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-rw.pg-ns/app -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);INSERT INTO test (randomdata) VALUES (generate_series(1, 1000));" 
  6. Dashboard aktualisieren Die Grafiken werden mit den aktualisierten Messwerten aktualisiert.

  7. Beenden Sie die Pod-Shell:

    exit