PostgreSQL-Vektordatenbank in GKE bereitstellen


In dieser Anleitung wird gezeigt, wie Sie einen PostgreSQL in Google Kubernetes Engine (GKE) bereitstellen.

PostgreSQL umfasst eine Reihe von Modulen und Erweiterungen, die die Funktionalität der Datenbank erweitern. In dieser Anleitung installieren Sie die Erweiterung pgvector auf einem vorhandenen PostgreSQL-Cluster, der in GKE bereitgestellt wird. Mit der Pgvector-Erweiterung können Sie Vektoren in den Datenbanktabellen speichern, indem Sie Vektortypen zu PostgreSQL hinzufügen. Pgvector bietet auch Ähnlichkeitssuchen mithilfe gängiger SQL-Abfragen.

Wir vereinfachen die Bereitstellung der PGVector-Erweiterung, indem wir zuerst den Operator CloudnativePG bereitstellen, da der Operator eine gebündelte Version der Erweiterung bereitstellt.

Diese Anleitung richtet sich an Cloud Platform-Administratoren und -Architekten, ML-Entwickler und MLOps-Experten (DevOps), die an der Bereitstellung von PostgreSQL-Datenbankclustern auf GKE interessiert sind.

Lernziele

In dieser Anleitung erfahren Sie mehr über die folgenden Themen:

  • Stellen Sie die GKE-Infrastruktur für PostgreSQL bereit.
  • pgvector-Erweiterung auf dem in GKE bereitgestellten PostgreSQL-Cluster installieren
  • CloudNativePG-PostgreSQL-Operator mit Helm bereitstellen und konfigurieren
  • Ein Demo-Dataset hochladen und Suchanfragen mit Jupyter-Notebook ausführen

Kosten

In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten von Google Cloud:

Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen. Neuen Google Cloud-Nutzern steht möglicherweise eine kostenlose Testversion zur Verfügung.

Nach Abschluss der in diesem Dokument beschriebenen Aufgaben können Sie weitere Kosten vermeiden, indem Sie die erstellten Ressourcen löschen. Weitere Informationen finden Sie unter Bereinigen.

Hinweise

In dieser Anleitung verwenden Sie Cloud Shell zum Ausführen von Befehlen. Cloud Shell ist eine Shell-Umgebung für die Verwaltung von Ressourcen, die in Google Cloud gehostet werden. Es ist bei Google Cloud CLI, kubectl, Helm und Terraform-Befehlszeilentools vorinstalliert. Wenn Sie Cloud Shell nicht verwenden, müssen Sie die Google Cloud CLI installieren.

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.
  3. To initialize the gcloud CLI, run the following command:

    gcloud init
  4. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  5. Make sure that billing is enabled for your Google Cloud project.

  6. Enable the Cloud Resource Manager, Compute Engine, GKE, and IAM Service Account Credentials APIs:

    gcloud services enable cloudresourcemanager.googleapis.com compute.googleapis.com container.googleapis.com iamcredentials.googleapis.com
  7. Install the Google Cloud CLI.
  8. To initialize the gcloud CLI, run the following command:

    gcloud init
  9. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  10. Make sure that billing is enabled for your Google Cloud project.

  11. Enable the Cloud Resource Manager, Compute Engine, GKE, and IAM Service Account Credentials APIs:

    gcloud services enable cloudresourcemanager.googleapis.com compute.googleapis.com container.googleapis.com iamcredentials.googleapis.com
  12. Grant roles to your user account. Run the following command once for each of the following IAM roles: roles/compute.securityAdmin, roles/compute.viewer, roles/container.clusterAdmin, roles/container.admin, roles/iam.serviceAccountAdmin, roles/iam.serviceAccountUser

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE
    • Replace PROJECT_ID with your project ID.
    • Replace USER_IDENTIFIER with the identifier for your user account. For example, user:myemail@example.com.

    • Replace ROLE with each individual role.

Umgebung einrichten

So richten Sie Ihre Umgebung mit Cloud Shell ein:

  1. Legen Sie Umgebungsvariablen für Ihr Projekt, Ihre Region und ein Kubernetes-Clusterressourcenpräfix fest:

    export PROJECT_ID=PROJECT_ID
    export KUBERNETES_CLUSTER_PREFIX=postgres
    export REGION=us-central1
    
    • Ersetzen Sie PROJECT_ID durch die Google Cloud-Projekt-ID.

    In dieser Anleitung wird die Region us-central1 verwendet.

  2. Klonen Sie das Beispielcode-Repository aus GitHub:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  3. Rufen Sie das Verzeichnis postgres-pgvector auf:

    cd kubernetes-engine-samples/databases/postgres-pgvector
    

Clusterinfrastruktur erstellen

In diesem Abschnitt führen Sie ein Terraform-Skript aus, um einen privaten, hochverfügbaren regionalen GKE-Cluster zum Bereitstellen Ihrer PostgreSQL-Datenbank zu erstellen.

Sie können PostgreSQL mit einem Standard- oder Autopilot-Cluster bereitstellen. Jede hat ihre eigenen Vorteile und unterschiedliche Preismodelle.

Autopilot

Führen Sie die folgenden Befehle in Cloud Shell aus, um die Autopilot-Clusterinfrastruktur bereitzustellen:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=../postgresql-cloudnativepg/terraform/gke-autopilot init
terraform -chdir=../postgresql-cloudnativepg/terraform/gke-autopilot apply \
-var project_id=${PROJECT_ID} \
-var region=${REGION} \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

GKE ersetzt zur Laufzeit die folgenden Variablen:

  • GOOGLE_OAUTH_ACCESS_TOKEN ruft mit dem Befehl gcloud auth print-access-token ein Zugriffstoken ab, das Interaktionen mit verschiedenen Google Cloud APIs authentifiziert.
  • PROJECT_ID, REGION und KUBERNETES_CLUSTER_PREFIX sind die im Abschnitt Umgebung einrichten definierten Umgebungsvariablen und den neuen relevanten Variablen für den Autopilot-Cluster zugewiesen, den Sie erstellen.

Geben Sie bei Aufforderung yes ein.

Terraform erstellt die folgenden Ressourcen:

  • Ein benutzerdefiniertes VPC-Netzwerk und ein privates Subnetz für die Kubernetes-Knoten
  • Ein Cloud Router für den Zugriff auf das Internet über Network Address Translation (NAT).
  • Ein privater GKE-Cluster in der Region us-central1.
  • Ein ServiceAccount mit Logging- und Monitoring-Berechtigungen für den Cluster.
  • Google Cloud Managed Service for Prometheus-Konfiguration für Clustermonitoring und Benachrichtigungen.

Die Ausgabe sieht in etwa so aus:

...
Apply complete! Resources: 11 added, 0 changed, 0 destroyed.
...

Standard

Führen Sie die folgenden Befehle in der Cloud Shell aus, um die Standard-Clusterinfrastruktur bereitzustellen:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=../postgresql-cloudnativepg/terraform/gke-standard init
terraform -chdir=../postgresql-cloudnativepg/terraform/gke-standard apply \
-var project_id=${PROJECT_ID} \
-var region=${REGION} \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

GKE ersetzt zur Laufzeit die folgenden Variablen:

  • GOOGLE_OAUTH_ACCESS_TOKEN ruft mit dem Befehl gcloud auth print-access-token ein Zugriffstoken ab, das Interaktionen mit verschiedenen Google Cloud APIs authentifiziert.
  • PROJECT_ID, REGION und KUBERNETES_CLUSTER_PREFIX sind die im Abschnitt Umgebung einrichten definierten Umgebungsvariablen und den neuen relevanten Variablen für den Standard-Cluster zugewiesen, den Sie erstellen.

Geben Sie bei Aufforderung yes ein. Es kann einige Minuten dauern, bis diese Befehle abgeschlossen sind und der Cluster den Status „Bereit“ anzeigt.

Terraform erstellt die folgenden Ressourcen:

  • Ein benutzerdefiniertes VPC-Netzwerk und ein privates Subnetz für die Kubernetes-Knoten
  • Ein Cloud Router für den Zugriff auf das Internet über Network Address Translation (NAT).
  • Ein privater GKE-Cluster in der Region us-central1 mit aktiviertem Autoscaling (ein bis zwei Knoten pro Zone).
  • Ein ServiceAccount mit Logging- und Monitoring-Berechtigungen für den Cluster.
  • Google Cloud Managed Service for Prometheus-Konfiguration für Clustermonitoring und Benachrichtigungen.

Die Ausgabe sieht in etwa so aus:

...
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
...

Mit dem Cluster verbinden

Konfigurieren Sie kubectl so, dass Anmeldedaten abgerufen und mit Ihrem neuen GKE-Cluster kommuniziert wird:

gcloud container clusters get-credentials \
    ${KUBERNETES_CLUSTER_PREFIX}-cluster --region ${REGION} --project ${PROJECT_ID}

CloudNativePG-Operator bereitstellen

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

  1. Prüfen Sie die Helm-Version:

    helm version
    

    Aktualisieren Sie die Version, wenn sie älter als 3.13 ist:

    curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
    
  2. Fügen Sie das Helm-Diagramm-Repository des CloudNativePG-Operators hinzu:

    helm repo add cnpg https://cloudnative-pg.github.io/charts
    
  3. 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
    ...
    

PostgreSQL-Vektordatenbank bereitstellen

In diesem Abschnitt stellen Sie die PostgreSQL-Vektordatenbank bereit.

  1. Erstellen Sie einen pg-ns-Namespace für die Datenbank:

    kubectl create ns pg-ns
    
  2. Wenden Sie das Manifest an, um den PostgreSQL-Cluster bereitzustellen: Das Clustermanifest aktiviert die pgvector-Erweiterung.

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

    Das postgreSQL_cluster.yaml-Manifest beschreibt das Deployment:

    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:
          postInitTemplateSQL:
            - CREATE EXTENSION IF NOT EXISTS vector;
          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
  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.

Demo-Dataset hochladen und Suchanfragen mit Jupyter-Notebook ausführen

In diesem Abschnitt laden Sie Vektoren in eine PostgreSQL-Tabelle hoch und führen semantische Suchanfragen mit der SQL-Syntax aus.

Im folgenden Beispiel verwenden Sie ein Dataset aus einer CSV-Datei, die eine Liste von Büchern verschiedener Genres enthält. Pgvector dient als Suchmaschine und der von Ihnen erstellte Pod dient als Client, der die PostgreSQL-Datenbank abfragt.

  1. Warten Sie, bis der PostgreSQL-Leader-Pod erstellt wurde und bereit ist:

    while [[ $(kubectl get pod -l cnpg.io/cluster=gke-pg-cluster,role=primary -n pg-ns -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}') != "True" ]]; do
    sleep 5
    done
    
  2. Erstellen Sie die Configmap mit books-dataset und führen Sie den Jupyter-Pod aus, um mit Ihrem PostgreSQL-Cluster zu interagieren:

    kubectl create -n pg-ns configmap books-dataset --from-file=manifests/02-notebook/dataset.csv
    kubectl create -n pg-ns configmap notebook --from-file=manifests/02-notebook/vector-database.ipynb
    kubectl apply -n pg-ns -f manifests/02-notebook/jupyter.yaml
    
    • Das vom CloudNativePG-Operator erstellte Secret namens gke-pg-cluster-superuser wird im Client-Pod als Umgebungsvariablen namens CLIENTUSERNAME und CLIENTPASSWORD. bereitgestellt
    • Die ConfigMap books-dataset enthält eine csv-Datei mit Buchdaten für die PostgreSQL-Datenbank.
    • Die ConfigMap demo-app enthält Python-Code zum Erstellen der PostgreSQL-Tabelle aus books-dataset.

    Das jupyter.yaml-Manifest beschreibt das notebook-Deployment und seinen Dienst:

    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels: &labels
        app: jupyter-notebook
      name: notebook
    spec:
      ports:
      - port: 8888
      selector: *labels
      type: LoadBalancer
      # type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: notebook
      labels: &labels
        app: jupyter-notebook
    spec:
      selector:
        matchLabels: *labels
      template:
        metadata: 
          labels: *labels
        spec:
          containers:
          - name: jupyter
            image: tensorflow/tensorflow:2.15.0-jupyter
            resources:
              requests:
                memory: "4500Mi"
                cpu: "1"
              limits:
                memory: "4500Mi"
                cpu: "1"
            ports:
            - containerPort: 8888
            env:
            - name: CLIENTPASSWORD
              valueFrom:
                secretKeyRef:
                  name: gke-pg-cluster-superuser
                  key: password
            - name: CLIENTUSERNAME
              valueFrom:
                secretKeyRef:
                  name: gke-pg-cluster-superuser
                  key: username
            volumeMounts:
            - name: books-dataset
              mountPath: /usr/local/dataset
            - name: notebook
              mountPath: /tf
          volumes:
          - name: books-dataset
            configMap:
              name: books-dataset
          - name: notebook
            configMap:
              name: notebook
  3. Warten Sie, bis GKE den Jupyter-Pod gestartet hat:

    kubectl wait pods -l app=jupyter-notebook --for condition=Ready --timeout=300s -n pg-ns
    
  4. Rufen Sie die URL mit dem Zugriffstoken ab, um eine Verbindung zu Jupyter herzustellen:

    export EXTERNAL_IP=$(kubectl -n pg-ns get svc notebook --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
    kubectl logs deploy/notebook -n pg-ns| grep '^ .*http://127'|sed "s|127.0.0.1|${EXTERNAL_IP}|"
    

    Die Ausgabe sieht in etwa so aus:

    http://34.123.21.1:8888/tree?token=a1d48d3531c48328695d6901004c94060aa0aa3554ff7463
    
  5. Öffnen Sie diese URL und klicken Sie auf die Datei vector-database.ipynb.

  6. Klicken Sie auf Run > Run all Cells (Ausführen > Alle Zellen ausführen). Jupyter führt den Code aus und führt eine Suchanfrage für den Text drama about people and unhappy love durch.

    Diese Abfrage führt eine semantische Suche in der Tabelle documents in PostgreSQL aus. Dabei werden maximal zwei Ergebnisse mit der höchsten Relevanz für Ihre Abfrage abgerufen.

    Die Ausgabe sieht in etwa so aus:

    Title: Romeo and Juliet, Author: William Shakespeare, Paul Werstine (Editor),
    Barbara A. Mowat (Editor), Paavo Emil Cajander (Translator)
    In Romeo and Juliet, Shakespeare creates a violent world, in which two young
    people fall in love. It is not simply that their families disapprove; the Montagues
    and the Capulets are engaged in a blood feud.In this death-filled setting, the
    movement from love at first sight to the lovers' final union in death seems
    almost inevitable. And yet, this play set in an extraordinary world has become
    the quintessential story of young love. In part because of its exquisite language,
    it is easy to respond as if it were about all young lovers.
    ---------
    Title: A Midsummer Night's Dream, Author: William Shakespeare, Paul Werstine (Editor),
    Barbara A. Mowat (Editor), Catherine Belsey (Contributor)
    Shakespeare's intertwined love polygons begin to get complicated from the start--Demetrius
    and Lysander both want Hermia but she only has eyes for Lysander. Bad news is,
    Hermia's father wants Demetrius for a son-in-law. On the outside is Helena,
    whose unreturned love burns hot for Demetrius. Hermia and Lysander plan to flee
    from the city under cover of darkness but are pursued by an enraged Demetrius
    (who is himself pursued by an enraptured Helena). In the forest, unbeknownst
    to the mortals, Oberon and Titania (King and Queen of the faeries) are having
    a spat over a servant boy. The plot twists up when Oberon's head mischief-maker,
    Puck, runs loose with a flower which causes people to fall in love with the
    first thing they see upon waking. Throw in a group of labourers preparing a
    play for the Duke's wedding (one of whom is given a donkey's head and Titania
    for a lover by Puck) and the complications become fantastically funny.
    ---------
    

Bereinigen

Damit Ihrem Google Cloud-Konto die in dieser Anleitung verwendeten Ressourcen nicht in Rechnung gestellt werden, löschen Sie entweder das Projekt, das die Ressourcen enthält, oder Sie behalten das Projekt und löschen die einzelnen Ressourcen.

Projekt löschen

Sie vermeiden weitere Kosten am einfachsten, wenn Sie das für die Anleitung erstellte Projekt löschen.

Delete a Google Cloud project:

gcloud projects delete PROJECT_ID

Wenn Sie das Projekt gelöscht haben, ist die Bereinigung abgeschlossen. Wenn Sie das Projekt nicht gelöscht haben, fahren Sie mit dem Löschen der einzelnen Ressourcen fort.

Einzelne Ressourcen löschen

  1. Umgebungsvariablen festlegen

    export PROJECT_ID=${PROJECT_ID}
    export KUBERNETES_CLUSTER_PREFIX=postgres
    export REGION=us-central1
    
  2. Führen Sie den Befehl terraform destroy aus:

    export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
    terraform  -chdir=../postgresql-cloudnativepg/terraform/FOLDER destroy \
    -var project_id=${PROJECT_ID} \
    -var region=${REGION} \
    -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
    

    Ersetzen Sie FOLDER je nach Typ des von Ihnen erstellten GKE-Clusters durch gke-autopilot oder gke-standard.

    Geben Sie bei Aufforderung yes ein.

Nächste Schritte