Ce guide vous explique comment utiliser l'opérateur Zalando Postgres pour déployer des clusters Postgres sur Google Kubernetes Engine (GKE).
PostgreSQL est un système de base de données Open Source de type objet-relationnel à fort potentiel de développement actif depuis plusieurs décennies, qui lui a permis d'acquérir une solide réputation pour la fiabilité, la robustesse des fonctionnalités et les performances.
Ce guide est destiné aux administrateurs de plate-forme, aux architectes cloud et aux professionnels des opérations qui souhaitent exécuter PostgreSQL en tant qu'application de base de données sur GKE au lieu d'utiliser Cloud SQL pour PostgreSQL.
Configurer votre environnement
Pour configurer votre environnement, procédez comme suit :
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.Clonez le dépôt GitHub.
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
Accédez au répertoire de travail :
cd kubernetes-engine-samples/databases/postgres-zalando
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 :
Déployez l'infrastructure suivante :
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).
- Un
ServiceAccount
avec les autorisations de journalisation et de surveillance. - Sauvegarde pour GKE pour la reprise après sinistre.
- Google Cloud Managed Service pour Prometheus pour la surveillance du cluster.
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é :
Déployez l'infrastructure :
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 Zalando sur votre cluster
Déployez l'opérateur Zalando sur votre cluster Kubernetes à l'aide d'un chart Helm.
Ajoutez le dépôt du chart Helm de l'opérateur Zalando :
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator
Créez un espace de noms pour l'opérateur Zalando et le cluster Postgres :
kubectl create ns postgres kubectl create ns zalando
Déployez l'opérateur Zalando à l'aide de l'outil de ligne de commande Helm :
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"
Vous ne pouvez pas configurer les paramètres
podAntiAffinity
directement sur la ressource personnalisée représentant le cluster Postgres. À la place, définissez les paramètrespodAntiAffinity
de manière globale pour tous les clusters Postgres dans les paramètres de l'opérateur.Vérifiez l'état de déploiement de l'opérateur Zalando à l'aide de Helm :
helm ls -n zalando
Le résultat ressemble à ce qui suit :
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
Déployer Postgres
La configuration de base de l'instance de cluster Postgres inclut les composants suivants :
- Trois instances répliquées Postgres : une instance répliquée principale et deux instances répliquées de secours.
- Allocation de ressources de processeur pour une requête de processeur et deux limites de processeur, avec 4 Go de demandes et limites de mémoire.
- Les tolérances,
nodeAffinities
ettopologySpreadConstraints
configurées pour chaque charge de travail, garantissant une répartition appropriée entre les nœuds Kubernetes, en utilisant leurs pools de nœuds respectifs et différentes zones de disponibilité.
Cette configuration représente la configuration minimale requise pour créer un cluster Postgres prêt pour la production.
Le fichier manifeste suivant décrit un cluster Postgres :
Ce fichier manifeste contient les champs suivants :
spec.teamId
: préfixe des objets de cluster que vous choisissez.spec.numberOfInstances
: nombre total d'instances pour un clusterspec.users
: liste des utilisateurs dotés de droitsspec.databases
: liste de la base de données au formatdbname: ownername
spec.postgresql
: paramètres postgresspec.volume
: paramètres de disque persistantspec.tolerations
: tolérances de modèle de pod permettant de planifier les pods du cluster sur des nœudspool-postgres
.spec.nodeAffinity
:nodeAffinity
de modèle de pod qui indique à GKE que les pods du cluster préfèrent être programmés sur des nœudspool-postgres
.spec.resources
: requêtes et limites pour les pods de clusterspec.sidecars
: liste de conteneurs side-car, contenantpostgres-exporter
Pour plus d'informations, consultez la documentation de référence sur les fichiers manifestes de cluster dans la documentation Postgres.
Créer un cluster Postgres de base
Créez un cluster Postgres en utilisant la configuration de base :
kubectl apply -n postgres -f manifests/01-basic-cluster/my-cluster.yaml
Cette commande crée une ressource personnalisée PostgreSQL de l'opérateur Zalando avec :
- Demandes et limites de ressources mémoire et de processeur
- Rejets et affinités permettant de répartir les instances répliquées de pods provisionnées entre les nœuds GKE
- Une base de données
- Deux utilisateurs disposant des autorisations de propriétaire de base de données
- Un utilisateur qui ne dispose d'aucune autorisation
Attendez que GKE démarre les charges de travail requises :
kubectl wait pods -l cluster-name=my-cluster --for condition=Ready --timeout=300s -n postgres
L'exécution de cette commande peut prendre quelques minutes.
Vérifiez que GKE a créé les charges de travail Postgres :
kubectl get pod,svc,statefulset,deploy,pdb,secret -n postgres
Le résultat ressemble à ce qui suit :
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
L'opérateur crée les ressources suivantes :
- Un StatefulSet Postgres, qui contrôle trois instances répliquées de pods pour Postgres
- Un
PodDisruptionBudgets
, assurant au moins une instance répliquée disponible - Le service
my-cluster
, qui ne cible que l'instance répliquée principale - Le service
my-cluster-repl
, qui expose le port Postgres pour les connexions entrantes et pour la réplication entre les instances répliquées Postgres - Le service headless
my-cluster-config
, pour obtenir la liste des instances répliquées des pods Postgres en cours d'exécution - Des secrets avec des identifiants utilisateur pour accéder à la base de données et effectuer la réplication entre les nœuds Postgres.
S'authentifier auprès de Postgres
Vous pouvez créer des utilisateurs Postgres et leur attribuer des autorisations de base de données. Par exemple, le fichier manifeste suivant décrit une ressource personnalisée qui attribue des utilisateurs et des rôles :
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
users:
mydatabaseowner:
- superuser
- createdb
myuser: []
databases:
mydatabase: mydatabaseowner
Dans le fichier manifeste :
- L'utilisateur
mydatabaseowner
dispose des rôlesSUPERUSER
etCREATEDB
, qui accordent des droits d'administrateur complets (par exemple, gérer la configuration Postgres, créer des bases de données, tables et utilisateurs). Vous ne devez pas partager cet utilisateur avec des clients. Par exemple, Cloud SQL n'autorise pas les clients à accéder aux utilisateurs disposant du rôleSUPERUSER
. - Aucun rôle n'a été attribué à l'utilisateur
myuser
. Ceci suit les bonnes pratiques d'utilisation deSUPERUSER
pour créer des utilisateurs avec le moins de privilèges possible. Des droits précis sont accordés àmyuser
parmydatabaseowner
. Pour des raisons de sécurité, vous ne devez partager les identifiantsmyuser
qu'avec les applications clientes.
Stocker les mots de passe
Nous vous recommandons d'utiliser la méthode recommandée pour stocker les mots de passe scram-sha-256
. Par exemple, le fichier manifeste suivant décrit une ressource personnalisée qui spécifie le chiffrement scram-sha-256
à l'aide du champ postgresql.parameters.password_encryption
:
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
postgresql:
parameters:
password_encryption: scram-sha-256
Alterner les identifiants utilisateur
Vous pouvez effectuer une rotation des identifiants utilisateur stockés dans les secrets Kubernetes avec Zalando. Par exemple, le fichier manifeste suivant décrit une ressource personnalisée qui définit la rotation des identifiants utilisateur à l'aide du champ usersWithSecretRotation
:
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
usersWithSecretRotation:
- myuser
- myanotheruser
- ...
Exemple d'authentification : se connecter à Postgres
Cette section vous explique comment déployer un exemple de client Postgres et vous connecter à la base de données à l'aide du mot de passe d'un secret Kubernetes.
Exécutez le pod client pour interagir avec votre cluster Postgres :
kubectl apply -n postgres -f manifests/02-auth/client-pod.yaml
Les identifiants des utilisateurs
myuser
etmydatabaseowner
sont issus des secrets associés et installés en tant que variables d'environnement sur le pod.Connectez-vous au pod lorsque celui-ci est prêt :
kubectl wait pod postgres-client --for=condition=Ready --timeout=300s -n postgres kubectl exec -it postgres-client -n postgres -- /bin/bash
Connectez-vous à Postgres et essayez de créer une table à l'aide des identifiants
myuser
:PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);"
La commande doit échouer et renvoyer une erreur semblable à celle-ci :
ERROR: permission denied for schema public LINE 1: CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR...
La commande échoue, car les utilisateurs ne disposant pas de droits d'accès par défaut ne peuvent que se connecter à Postgres et répertorier les bases de données.
Créez une table avec les identifiants
mydatabaseowner
et accordez tous les droits sur la table àmyuser
: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;"
Le résultat ressemble à ce qui suit :
CREATE TABLE GRANT GRANT
Insérez des données aléatoires dans la table à l'aide des identifiants
myuser
: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');" done
Le résultat ressemble à ce qui suit :
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 1
Récupérez les valeurs que vous avez insérées :
PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "SELECT * FROM test;"
Le résultat ressemble à ce qui suit :
id | randomdata ----+--------------- 1 | jup9HYsAjwtW4 2 | 9rLAyBlcpLgNT 3 | wcXSqxb5Yz75g 4 | KoDRSrx3muD6T 5 | b9atC7RPai7En 6 | 20d7kC8E6Vt1V 7 | GmgNxaWbkevGq 8 | BkTwFWH6hWC7r 9 | nkLXHclkaqkqy 10 | HEebZ9Lp71Nm3 (10 rows)
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 port9187
- Collecteurs basés sur Prometheus qui traitent les métriques à partir du pod Postgres
- Une ressource
PodMonitoring
qui envoie des métriques à Cloud Monitoring
Le service Google Cloud Managed Service pour Prometheus accepte la collecte de métriques au format Prometheus. Cloud Monitoring utilise un tableau de bord intégré pour les métriques Postgres.
Zalando expose les métriques de cluster au format Prometheus en utilisant le composant postgres_exporter en tant que conteneur side-car.
Créez la ressource
PodMonitoring
pour récupérer les métriques parlabelSelector
:kubectl apply -n postgres -f manifests/03-prometheus-metrics/pod-monitoring.yaml
Dans la console Google Cloud , accédez à la page Tableau de bord des clusters GKE.
Accéder au tableau de bord des clusters GKE
Le tableau de bord affiche un taux d'ingestion de métriques différent de zéro.
Dans la console Google Cloud , accédez à la page Tableaux de bord.
Ouvrez le tableau de bord "Présentation de PostgreSQL-Prometheus. Le tableau de bord indique le nombre de lignes récupérées. Le provisionnement automatique du tableau de bord peut prendre plusieurs minutes.
Connectez-vous au pod client :
kubectl exec -it postgres-client -n postgres -- /bin/bash
Insérer des données aléatoires :
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');" done
Actualisez la page. Les graphiques Lignes et Blocs sont mis à jour pour afficher l'état réel de la base de données.
Quittez le shell du pod :
exit