Esegui il deployment di PostgreSQL in GKE utilizzando CloudNativePG


La guida mostra come eseguire il deployment di cluster PostgreSQL su Google Kubernetes Engine (GKE) utilizzando l'operatore CloudNativePG.

PostgreSQL è un database relazionale a oggetti open source con diversi decenni di sviluppo attivo, che garantisce prestazioni stabili del client. Offre una gamma di funzionalità, tra cui replica, recupero point-in-time, funzionalità di sicurezza ed estensibilità. PostgreSQL è compatibile con i principali sistemi operativi ed è pienamente conforme agli standard ACID (atomicità, coerenza, isolamento, durabilità).

Questa guida è destinata ad amministratori di piattaforme, architetti cloud e professionisti delle operazioni interessati al deployment di cluster Postgres su GKE. L'esecuzione di Postgres in GKE anziché l'utilizzo di Cloud SQL può offrire maggiore flessibilità e controllo della configurazione agli amministratori di database esperti.

Vantaggi

CloudNativePG è un operatore open source sviluppato da EDB con licenza Apache 2. Offre le seguenti funzionalità per il deployment di PostgreSQL:

  • Un modo dichiarativo e nativo di Kubernetes per gestire e configurare i cluster PostgreSQL
  • Gestione dei backup utilizzando le istantanee del volume o Cloud Storage
  • Connessione TLS crittografata in transito, possibilità di utilizzare la propria autorità di certificazione e integrazione con Certificate Manager per l'emissione e la rotazione automatizzate dei certificati TLS
  • Aggiornamenti continui per le release secondarie di PostgreSQL
  • Utilizzo del server API Kubernetes per mantenere lo stato di un cluster PostgreSQL e i failover per l'alta disponibilità senza richiedere strumenti aggiuntivi
  • Una configurazione dell'esportatore Prometheus integrata tramite metriche definite dall'utente scritte in SQL

Obiettivi

  • Pianifica ed esegui il deployment dell'infrastruttura GKE per Postgres
  • Esegui il deployment e configura l'operatore CloudNativePG Postgres con Helm
  • Esegui il deployment di un cluster PostgreSQL
  • Configura l'autenticazione e l'osservabilità di PostgreSQL

Architettura di deployment

PostgreSQL offre varie opzioni di deployment, da un server di database autonomo a un cluster replicato ad alta disponibilità. Questo tutorial si concentra sul deployment del cluster ad alta disponibilità su GKE.

In questo deployment, i carichi di lavoro del cluster PostgreSQL sono distribuiti su più zone di disponibilità all'interno del cluster GKE regionale, garantendo alta disponibilità e ridondanza. Per saperne di più, consulta cluster regionali.

Il seguente diagramma mostra un cluster Postgres in esecuzione su più nodi e zone in un cluster GKE:

Cluster Postgres su
GKE

  • La configurazione predefinita include un server PostgreSQL principale e due server di backup pronti a subentrare in caso di guasto del server principale, garantendo la disponibilità continua del database.

  • Le risorse dell'operatore CloudNativePG utilizzano uno spazio dei nomi separato del cluster GKE per un migliore isolamento delle risorse e l'approccio consigliato ai microservizi di un database per cluster PostgreSQL. Il database e il relativo utente (utente dell'app) sono definiti nella risorsa personalizzata Kubernetes che rappresenta il cluster.

  • Lo spazio di archiviazione è un componente fondamentale quando si parla di database. L'archiviazione deve funzionare in modo efficiente, garantire la disponibilità continua e assicurare la coerenza dei dati. Per questi motivi, ti consigliamo la classe di archiviazione premium-rwo, che si basa su dischi SSD. L'operatore CloudNativePG crea automaticamente PersistentVolumeClaims in base alle esigenze durante la configurazione dei pod per il cluster PostgreSQL.

Costi

In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il calcolatore prezzi.

I nuovi utenti di Google Cloud potrebbero avere diritto a una prova senza costi.

Al termine delle attività descritte in questo documento, puoi evitare l'addebito di ulteriori costi eliminando le risorse che hai creato. Per ulteriori informazioni, vedi Pulizia.

Prima di iniziare

Cloud Shell è preinstallato con il software necessario per questo tutorial, tra cui kubectl, gcloud CLI, Helm e Terraform. Se non utilizzi Cloud Shell, devi installare gcloud CLI.

  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. Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

  4. Per inizializzare gcloud CLI, esegui questo comando:

    gcloud init
  5. 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.

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the Compute Engine, IAM, GKE, Resource Manager APIs:

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com cloudresourcemanager.googleapis.com
  8. Install the Google Cloud CLI.

  9. Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

  10. Per inizializzare gcloud CLI, esegui questo comando:

    gcloud init
  11. 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.

  12. Verify that billing is enabled for your Google Cloud project.

  13. Enable the Compute Engine, IAM, GKE, Resource Manager APIs:

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com cloudresourcemanager.googleapis.com
  14. 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 the following:

    • PROJECT_ID: your project ID.
    • USER_IDENTIFIER: the identifier for your user account—for example, myemail@example.com.
    • ROLE: the IAM role that you grant to your user account.
  15. Configura l'ambiente

    Per configurare l'ambiente:

    1. Imposta le variabili di ambiente:

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

      Sostituisci PROJECT_ID con l' Google Cloud ID progetto.

    2. Clona il repository GitHub:

      git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
      
    3. Passa alla directory di lavoro:

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

    Crea l'infrastruttura del cluster

    In questa sezione, esegui uno script Terraform per creare un cluster GKE regionale privato ad alta disponibilità.

    Puoi installare l'operatore utilizzando un cluster standard o Autopilot.

    Standard

    Il seguente diagramma mostra un cluster GKE Standard regionale privato di cui è stato eseguito il deployment in tre zone diverse:

    Per eseguire il deployment di questa infrastruttura, esegui i seguenti comandi:

    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}
    

    Quando richiesto, digita yes. Il completamento di questo comando e la visualizzazione dello stato pronto del cluster potrebbero richiedere diversi minuti.

    Terraform crea le seguenti risorse:

    • Una rete VPC e una subnet privata per i nodi Kubernetes
    • Un router per accedere a internet tramite NAT
    • Un cluster GKE privato nella regione us-central1
    • Un node pool con scalabilità automatica abilitata (da uno a due nodi per zona, minimo un nodo per zona)

    L'output è simile al seguente:

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

    Autopilot

    Il seguente diagramma mostra un cluster GKE Autopilot regionale privato:

    Per eseguire il deployment dell'infrastruttura, esegui questi comandi:

    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}
    

    Quando richiesto, digita yes. Il completamento di questo comando e la visualizzazione dello stato pronto del cluster potrebbero richiedere diversi minuti.

    Terraform crea le seguenti risorse:

    • Una rete VPC e una subnet privata per i nodi Kubernetes
    • Un router per accedere a internet tramite NAT
    • Un cluster GKE privato nella regione us-central1
    • Un ServiceAccount con l'autorizzazione di logging e monitoraggio
    • Google Cloud Managed Service per Prometheus per il monitoraggio del cluster

    L'output è simile al seguente:

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

    Connettiti al cluster

    Configura kubectl per comunicare con il cluster:

    gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${REGION}
    

    Esegui il deployment dell'operatore CloudNativePG

    Esegui il deployment di CloudNativePG nel cluster Kubernetes utilizzando un grafico Helm:

    1. Aggiungi il repository del grafico Helm dell'operatore CloudNativePG:

      helm repo add cnpg https://cloudnative-pg.github.io/charts
      
    2. Esegui il deployment dell'operatore CloudNativePG utilizzando lo strumento a riga di comando Helm:

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

      L'output è simile al seguente:

      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
      ...
      

    Esegui il deployment di Postgres

    Il seguente manifest descrive un cluster PostgreSQL definito dalla risorsa personalizzata dell'operatore CloudNativePG:

    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

    Questo manifest contiene i seguenti campi:

    • spec.instances: il numero di pod del cluster
    • spec.primaryUpdateStrategy: la strategia di aggiornamento in sequenza:
      • Unsupervised: aggiorna autonomamente il nodo del cluster primario dopo i nodi di replica
      • Supervised: è necessario un cambio manuale per il nodo cluster principale
    • spec.postgresql: override dei parametri del file postgres.conf, ad esempio pg-hba regole, LDAP e requisiti per la sincronizzazione delle repliche.
    • spec.storage: impostazioni relative all'archiviazione, come classe di archiviazione, dimensioni del volume e impostazioni del log write-ahead.
    • spec.bootstrap: parametri del database iniziale creato nel cluster, credenziali utente e opzioni di ripristino del database
    • spec.resources: richieste e limiti per i pod del cluster
    • spec.affinity: regole di affinità e anti-affinità dei carichi di lavoro del cluster

    Crea un cluster Postgres di base

    1. Creare uno spazio dei nomi:

      kubectl create ns pg-ns
      
    2. Crea il cluster PostgreSQL utilizzando la risorsa personalizzata:

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

      Il completamento di questo comando potrebbe richiedere diversi minuti.

    3. Controlla lo stato del cluster:

      kubectl get cluster -n pg-ns --watch
      

      Attendi che l'output mostri lo stato Cluster in healthy state prima di procedere con il passaggio successivo.

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

    Esaminare le risorse

    Verifica che GKE abbia creato le risorse per il cluster:

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

    L'output è simile al seguente:

    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
    

    L'operatore crea le seguenti risorse:

    • Una risorsa personalizzata del cluster che rappresenta il cluster PostgreSQL controllato dall'operatore
    • Risorse PersistentVolumeClaim con PersistentVolume corrispondenti
    • Secret con le credenziali utente per accedere al database e alla replica tra i nodi Postgres.
    • Tre servizi di endpoint di database: <name>-rw, <name>-ro e <name>-r per connettersi al cluster. Per saperne di più, consulta la documentazione sull'architettura di PostgreSQL.

    Autenticarsi in Postgres

    Puoi connetterti al database PostgreSQL e controllare l'accesso tramite diversi endpoint di servizio creati dall'operatore. Per farlo, utilizzi un pod aggiuntivo con un client PostgreSQL e le credenziali utente dell'applicazione sincronizzate montate come variabili di ambiente.

    1. Esegui il pod client per interagire con il cluster Postgres:

      kubectl apply -n pg-ns -f manifests/02-auth/pg-client.yaml
      
    2. Esegui un comando exec sul pod pg-client e accedi al servizio gke-pg-cluster-rw:

      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. Accedi al database utilizzando il servizio gke-pg-cluster-rw per stabilire una connessione con privilegi di lettura/scrittura:

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

      Il terminale inizia con il nome del database:

      app=>
      
    4. Creare una tabella:

      CREATE TABLE travel_agency_clients (
      client VARCHAR ( 50 ) UNIQUE NOT NULL,
      address VARCHAR ( 50 ) UNIQUE NOT NULL,
      phone VARCHAR ( 50 ) UNIQUE NOT NULL);
      
    5. Inserisci i dati nella tabella:

      INSERT INTO travel_agency_clients(client, address, phone)
      VALUES ('Tom', 'Warsaw', '+55555')
      RETURNING *;
      
    6. Visualizza i dati che hai creato:

      SELECT * FROM travel_agency_clients ;
      

      L'output è simile al seguente:

      client | address |  phone
      --------+---------+---------
      Tom    | Warsaw  | +55555
      (1 row)
      
    7. Disconnettiti dalla sessione di database corrente:

      exit
      
    8. Accedi al database utilizzando il servizio gke-pg-cluster-ro per verificare l'accesso di sola lettura. Questo servizio consente di eseguire query sui dati, ma limita qualsiasi operazione di scrittura:

      psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-ro.pg-ns/app
      
    9. Tentativo di inserimento di nuovi dati:

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

      L'output è simile al seguente:

      ERROR:  cannot execute INSERT in a read-only transaction
      
    10. Tentativo di lettura dei dati:

      SELECT * FROM travel_agency_clients ;
      

      L'output è simile al seguente:

      client | address |  phone
      --------+---------+---------
      Tom    | Warsaw  | +55555
      (1 row)
      
    11. Disconnettiti dalla sessione di database corrente:

      exit
      
    12. Esci dalla shell del pod:

      exit
      

    Scopri come Prometheus raccoglie le metriche per il tuo cluster Postgres

    Il seguente diagramma mostra come funziona la raccolta delle metriche Prometheus:

    Nel diagramma, un cluster GKE privato contiene:

    • Un pod Postgres che raccoglie metriche sul percorso / e sulla porta 9187
    • Raccoglitori basati su Prometheus che elaborano le metriche del pod Postgres
    • Una risorsa PodMonitoring che invia metriche a Cloud Monitoring

    Per consentire la raccolta delle metriche dai tuoi pod, segui questi passaggi:

    1. Crea la risorsa PodMonitoring:

      kubectl apply -f manifests/03-observability/pod-monitoring.yaml -n pg-ns
      
    2. Nella console Google Cloud , vai alla pagina Esplora metriche:

      Vai a Esplora metriche

      La dashboard mostra una velocità di importazione delle metriche diversa da zero.

    3. In Seleziona una metrica, inserisci Target Prometheus.

    4. Nella sezione Categorie di metriche attive, seleziona Cnpg.

    Crea una dashboard delle metriche

    Per visualizzare le metriche esportate, crea una dashboard delle metriche.

    1. Esegui il deployment di una dashboard:

      gcloud --project "${PROJECT_ID}" monitoring dashboards create --config-from-file manifests/03-observability/gcp-pg.json
      
    2. Nella console Google Cloud , vai alla pagina Dashboard.

      Accedi a Dashboard

    3. Seleziona la dashboard Panoramica di PostgreSQL Prometheus.

      Per esaminare il modo in cui le dashboard monitorano le funzioni, puoi riutilizzare le azioni della sezione Autenticazione del database e applicare richieste di lettura e scrittura al database, quindi esaminare la visualizzazione delle metriche raccolte in una dashboard.

    4. Connettiti al pod client:

      kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
      
    5. Inserisci dati casuali:

      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. Aggiorna la dashboard. I grafici vengono aggiornati con le metriche effettive.

    7. Esci dalla shell del pod:

      exit
      

    Esegui la pulizia

    Elimina il progetto

      Delete a Google Cloud project:

      gcloud projects delete PROJECT_ID

    Elimina singole risorse

    1. Imposta le variabili di ambiente.

      export PROJECT_ID=${PROJECT_ID}
      export KUBERNETES_CLUSTER_PREFIX=postgres
      export REGION=us-central1
      
    2. Esegui il comando terraform destroy:

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

      Sostituisci FOLDER con gke-autopilot o gke-standard.

      Quando richiesto, digita yes.

    3. Trova tutti i dischi scollegati:

      export disk_list=$(gcloud compute disks list --filter="-users:* AND labels.name=${KUBERNETES_CLUSTER_PREFIX}-cluster" --format "value[separator=|](name,zone)")
      
    4. Elimina i dischi:

      for i in $disk_list; do
        disk_name=$(echo $i| cut -d'|' -f1)
        disk_zone=$(echo $i| cut -d'|' -f2|sed 's|.*/||')
        echo "Deleting $disk_name"
        gcloud compute disks delete $disk_name --zone $disk_zone --quiet
      done
      

    Passaggi successivi

    • Esplora architetture di riferimento, diagrammi e best practice su Google Cloud. Consulta il nostro Cloud Architecture Center.