Déployer PostgreSQL sur GKE à l'aide de CloudNativePG

Ce guide vous explique comment déployer des clusters PostgreSQL sur Google Kubernetes Engine (GKE) à l'aide de l'opérateur CloudNativePG.

PostgreSQL est une base de données Open Source de type objet-relationnel avec plusieurs décennies de développement actif, garantissant la stabilité des performances du client. Elle offre un large éventail de fonctionnalités, y compris la réplication, la récupération à un moment précis, ainsi que des fonctionnalités de sécurité et d'extension. PostgreSQL est compatible avec les principaux systèmes d'exploitation et répond parfaitement aux normes ACID (atomicité, cohérence, isolation, durabilité).

Ce guide est destiné aux administrateurs de plate-forme, aux architectes cloud et aux professionnels des opérations qui souhaitent déployer des clusters Postgres sur GKE. L'exécution de Postgres dans GKE au lieu d'utiliser Cloud SQL peut offrir plus de flexibilité et de contrôle de configuration aux administrateurs de base de données expérimentés.

Avantages

CloudNativePG est un opérateur Open Source développé par EBD sous une licence Apache 2. Il apporte les fonctionnalités suivantes au déploiement de PostgreSQL :

  • Moyen déclaratif et Kubernetes natif de gérer et de configurer les clusters PostgreSQL
  • Gestion des sauvegardes à l'aide d'instantanés de volume ou de Cloud Storage
  • Connexion TLS chiffrée en transit, possibilité d'utiliser votre propre autorité de certification et votre intégration au gestionnaire de certificats pour l'émission et la rotation automatisées des certificats TLS
  • Mises à jour progressives pour les versions mineures de PostgreSQL
  • Utilisation du serveur d'API Kubernetes pour maintenir l'état d'un cluster PostgreSQL et les basculements pour la haute disponibilité sans outils supplémentaires
  • Configuration d'un exportateur Prometheus intégré via des métriques définies par l'utilisateur et écrites en SQL

Configurer votre environnement

Pour configurer votre environnement, procédez comme suit :

  1. Définissez les variables d'environnement :

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

    Remplacez PROJECT_ID par l'ID de votre projet Google Cloud .

  2. Clonez le dépôt GitHub.

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  3. Accédez au répertoire de travail :

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

Créer l'infrastructure de votre cluster

Dans cette section, vous allez exécuter un script Terraform pour créer un cluster GKE régional, privé et à disponibilité élevée.

Vous pouvez installer l'opérateur à l'aide d'un cluster Standard ou Autopilot.

Standard

Le schéma suivant présente un cluster GKE standard régional privé déployé sur trois zones différentes :

Pour déployer cette infrastructure, exécutez les commandes suivantes :

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}

Lorsque vous y êtes invité, saisissez yes. L'exécution de cette commande et le passage du cluster à l'état prêt peuvent prendre plusieurs minutes.

Terraform crée les ressources suivantes :

  • Un réseau VPC et un sous-réseau privé pour les nœuds Kubernetes.
  • Un routeur pour accéder à Internet via NAT.
  • Un cluster GKE privé dans la région us-central1.
  • Un pool de nœuds avec autoscaling activé (un à deux nœuds par zone, un nœud par zone au minimum).

Le résultat ressemble à ce qui suit :

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

Autopilot

Le schéma suivant présente un cluster GKE Autopilot régional privé :

Pour déployer l'infrastructure, exécutez les commandes suivantes :

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}

Lorsque vous y êtes invité, saisissez yes. L'exécution de cette commande et le passage du cluster à l'état prêt peuvent prendre plusieurs minutes.

Terraform crée les ressources suivantes :

  • Un réseau VPC et un sous-réseau privé pour les nœuds Kubernetes.
  • Un routeur pour accéder à Internet via NAT.
  • Un cluster GKE privé dans la région us-central1.
  • Un objet ServiceAccount avec une autorisation de journalisation et de surveillance.
  • Google Cloud Managed Service pour Prometheus pour la surveillance du cluster.

Le résultat ressemble à ce qui suit :

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

Se connecter au cluster

Configurez kubectl pour communiquer avec le cluster :

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

Déployer l'opérateur CloudNativePG

Déployez CloudNativePG sur votre cluster Kubernetes à l'aide d'un chart Helm :

  1. Ajoutez le dépôt du chart Helm de l'opérateur CloudNativePG :

    helm repo add cnpg https://cloudnative-pg.github.io/charts
    
  2. Déployez l'opérateur CloudNativePG à l'aide de l'outil de ligne de commande Helm :

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

    Le résultat ressemble à ce qui suit :

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

Déployer Postgres

Le fichier manifeste suivant décrit un cluster PostgreSQL tel que défini par la ressource personnalisée de l'opérateur 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

Ce fichier manifeste contient les champs suivants :

  • spec.instances : nombre de pods du cluster
  • spec.primaryUpdateStrategy: stratégie de mise à jour progressive :
    • Unsupervised : met à jour de manière autonome le nœud du cluster principal après les nœuds répliqués.
    • Supervised : le basculement manuel est requis pour le nœud de cluster principal.
  • spec.postgresql : remplacements de paramètres du fichier postgres.conf, tels que les règles pg-hba, LDAP et les exigences pour la synchronisation des instances dupliquées.
  • spec.storage : paramètres liés au stockage, tels que la classe de stockage, la taille du volume et les paramètres des journaux WAL (Write-Ahead Logging).
  • spec.bootstrap : paramètres de la base de données initiale créée dans le cluster, identifiants utilisateur et options de restauration de la base de données.
  • spec.resources : requêtes et limites pour les pods de cluster
  • spec.affinity : règles d'affinité et d'anti-affinité des charges de travail du cluster

Créer un cluster Postgres de base

  1. Créez un espace de noms :

    kubectl create ns pg-ns
    
  2. Créez le cluster PostgreSQL à l'aide de la ressource personnalisée :

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

    Cette commande peut prendre plusieurs minutes.

  3. Vérifiez l'état du cluster :

    kubectl get cluster -n pg-ns --watch
    

    Attendez que le résultat affiche l'état Cluster in healthy state avant de passer à l'étape suivante.

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

Inspecter les ressources

Vérifiez que GKE a créé les ressources pour le cluster :

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

Le résultat ressemble à ce qui suit :

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'opérateur crée les ressources suivantes :

  • Ressource personnalisée de cluster représentant le cluster PostgreSQL contrôlé par l'opérateur
  • Ressources PersistentVolumeClaim avec les PersistentVolumes correspondants
  • Des secrets avec des identifiants utilisateur pour accéder à la base de données et effectuer la réplication entre les nœuds Postgres.
  • Trois services de point de terminaison de base de données : <name>-rw, <name>-ro et <name>-r pour se connecter au cluster. Pour en savoir plus, consultez la section Architecture PostgreSQL.

S'authentifier auprès de Postgres

Vous pouvez vous connecter à la base de données PostgreSQL et vérifier l'accès via différents points de terminaison de service créés par l'opérateur. Pour ce faire, vous utilisez un pod supplémentaire avec un client PostgreSQL et des identifiants d'utilisateur d'application synchronisés montés en tant que variables d'environnement.

  1. Exécutez le pod client pour interagir avec votre cluster Postgres :

    kubectl apply -n pg-ns -f manifests/02-auth/pg-client.yaml
    
  2. Exécutez une commande exec sur le pod pg-client et connectez-vous au service 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. Connectez-vous à la base de données à l'aide du service gke-pg-cluster-rw pour établir une connexion avec des droits de lecture/écriture :

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

    Le terminal commence par le nom de votre base de données :

    app=>
    
  4. Créez une table :

    CREATE TABLE travel_agency_clients (
    client VARCHAR ( 50 ) UNIQUE NOT NULL,
    address VARCHAR ( 50 ) UNIQUE NOT NULL,
    phone VARCHAR ( 50 ) UNIQUE NOT NULL);
    
  5. Insérez des données dans la table.

    INSERT INTO travel_agency_clients(client, address, phone)
    VALUES ('Tom', 'Warsaw', '+55555')
    RETURNING *;
    
  6. Affichez les données que vous avez créées :

    SELECT * FROM travel_agency_clients ;
    

    Le résultat ressemble à ce qui suit :

    client | address |  phone
    --------+---------+---------
    Tom    | Warsaw  | +55555
    (1 row)
    
  7. Déconnectez-vous de la session de base de données en cours :

    exit
    
  8. Connectez-vous à la base de données à l'aide du service gke-pg-cluster-ro pour vérifier l'accès en lecture seule. Ce service permet d'interroger des données, mais limite les opérations d'écriture :

    psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-ro.pg-ns/app
    
  9. Essayez d'insérer de nouvelles données :

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

    Le résultat ressemble à ce qui suit :

    ERROR:  cannot execute INSERT in a read-only transaction
    
  10. Essayez de lire les données :

    SELECT * FROM travel_agency_clients ;
    

    Le résultat ressemble à ce qui suit :

    client | address |  phone
    --------+---------+---------
    Tom    | Warsaw  | +55555
    (1 row)
    
  11. Déconnectez-vous de la session de base de données en cours :

    exit
    
  12. Quittez le shell du pod :

    exit
    

Comprendre comment Prometheus collecte les métriques pour votre cluster Postgres

Le schéma suivant illustre le fonctionnement de la collecte de métriques Prometheus :

Dans le schéma, un cluster privé GKE contient :

  • Un pod Postgres qui collecte des métriques sur le chemin / et le port 9187
  • Collecteurs basés sur Prometheus qui traitent les métriques à partir du pod Postgres
  • Une ressource PodMonitoring qui envoie des métriques à Cloud Monitoring

Pour activer la collecte de métriques à partir de vos pods, procédez comme suit :

  1. Créez la ressource PodMonitoring :

    kubectl apply -f manifests/03-observability/pod-monitoring.yaml -n pg-ns
    
  2. Dans la console Google Cloud , accédez à la page Explorateur de métriques :

    Accéder à l'explorateur de métriques

    Le tableau de bord affiche un taux d'ingestion de métriques différent de zéro.

  3. Dans Sélectionner une métrique, saisissez Cible Prometheus.

  4. Dans la section Catégories de métriques actives, sélectionnez Cnpg.

Créer un tableau de bord des métriques

Pour visualiser les métriques exportées, créez un tableau de bord des métriques.

  1. Déployer un tableau de bord :

    gcloud --project "${PROJECT_ID}" monitoring dashboards create --config-from-file manifests/03-observability/gcp-pg.json
    
  2. Dans la console Google Cloud , accédez à la page Tableaux de bord.

    Accéder à la page "Tableaux de bord"

  3. Sélectionnez le tableau de bord Présentation de PostgreSQL-Prometheus.

    Pour examiner comment les tableaux de bord surveillent les fonctions, vous pouvez réutiliser les actions de la section Authentification de la base de données, appliquer des requêtes de lecture et d'écriture sur la base de données, puis examiner la visualisation des métriques collectées dans un tableau de bord.

  4. Connectez-vous au pod client :

    kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
    
  5. Insérer des données aléatoires :

    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. Actualisez le tableau de bord. Les graphiques sont mis à jour avec les métriques actualisées.

  7. Quittez le shell du pod :

    exit