Ce guide fournit une procédure complète pour déployer une pile PostgreSQL disponibilité élevée sur trois zones dans un environnement Google Distributed Cloud (GDC) air-gapped. Vous apprendrez à préparer les artefacts logiciels nécessaires, à amorcer les VM cibles et à utiliser Autobase pour automatiser l'ensemble du processus de provisionnement. Tout au long de ce guide, Patroni est utilisé comme couche de gestion principale pour orchestrer le cycle de vie de PostgreSQL et gérer les basculements automatiques.
Architecture
L'architecture se compose d'un environnement de trois VM réparties sur trois zones de disponibilité.

Chaque VM est identique et exécute une pile de services colocalisée :
- PostgreSQL 17 : moteur de base de données relationnelle de base.
- Patroni : le gestionnaire de haute disponibilité. Il gère le cycle de vie du processus PostgreSQL et effectue des basculements automatiques. Il expose une API REST HTTPS sur le port
8008(point de terminaison/primary) utilisée par l'équilibreur de charge pour identifier le leader actuel. - etcd : magasin de configurations distribuées (DCS, Distributed Configuration Store). Il fournit la couche de consensus pour l'élection du leader et stocke la configuration de Patroni.
- PgBouncer : un outil de regroupement de connexions qui se place devant PostgreSQL pour stabiliser les coûts de connexion. Il fournit le point d'entrée recommandé pour le trafic de l'application sur le port
6432.
La pile inclut également un équilibreur de charge L4 global GDC air-gapped, qui est un service géré par la plate-forme fournissant une adresse IP virtuelle (VIP) stable. Les applications se connectent à l'adresse IP virtuelle stable sur le port 6432, que l'équilibreur de charge achemine vers PgBouncer sur la VM leader actuelle. PgBouncer transmet ensuite la requête à l'instance PostgreSQL locale. Pour gérer le flux de trafic, l'équilibreur de charge interroge en continu les points de terminaison HTTPS Patroni en tant que vérification de l'état.
La vérification de l'état de la VM leader renvoie HTTP 200 OK pour signaler que la VM est prête à recevoir du trafic, tandis que les vérifications de l'état des VM d'instance répliquée renvoient HTTP 503 Service Unavailable pour signaler à l'équilibreur de charge de les contourner. Si le leader échoue, un nouveau leader est élu et son instance Patroni commence à renvoyer HTTP 200 OK, ce qui amène l'équilibreur de charge à rediriger automatiquement le trafic vers le port PgBouncer de la nouvelle VM.
Pour assurer une haute disponibilité et éviter la perte de données, la pile s'appuie sur le concept de quorum. Avec trois VM, le système nécessite qu'une majorité d'au moins deux membres soient opérationnels et en communication pour élire un leader et rester opérationnels. Ce consensus basé sur la majorité, géré par etcd et Patroni, permet à la pile de tolérer automatiquement la défaillance totale d'une VM ou d'une zone.
Considérations sur les performances
Lorsque vous planifiez votre déploiement, tenez compte des facteurs concrets suivants pour optimiser les performances et la fiabilité :
- Dimensionnement du matériel : bien que les exigences varient selon la charge de travail, utilisez ces profils standards comme point de départ pour chaque VM :
- Développement/Démonstration de faisabilité : 2 vCPU, 8 Go de RAM (minimum pour un fonctionnement stable).
- Petite production : 4 vCPU, 16 Go de RAM. Convient aux outils internes avec une simultanéité modérée.
- Production standard : 8 vCPU, 32 Go de RAM. La référence recommandée pour les applications critiques.
- Haut débit : 16 vCPU ou plus, 64 Go de RAM ou plus. Pour les charges de travail nécessitant une mise en cache importante des données en mémoire (tampons partagés PostgreSQL).
- Performances de stockage : un stockage hautes performances est essentiel. Les disques SSD sont vivement recommandés pour la stabilité d'etcd. etcd est extrêmement sensible à la latence d'écriture sur le disque. Les consignes matérielles officielles d'etcd recommandent une latence fdatasync WAL de disque p99 inférieure à 10 ms.
- Latence du réseau : la latence entre les VM a un impact direct sur les performances de réplication :
- Quorum etcd : le délai aller-retour (DAR) moyen doit être inférieur à 50 ms (idéalement inférieur à 10 ms) pour éviter les délais d'expiration des élections et l'instabilité du cluster.
- Réplication synchrone : si elle est configurée, chaque transaction d'écriture doit attendre l'accusé de réception d'une instance répliquée. La latence interzone dans GDC sous air gap est généralement inférieure à 1 ms, ce qui est excellent pour limiter les surcoûts d'écriture (généralement de 10 à 30 %).
- Rôle de PgBouncer : PostgreSQL crée un processus d'OS pour chaque connexion, ce qui consomme environ 10 Mo de RAM et entraîne des coûts de changement de contexte du processeur. PgBouncer réduit cette surcharge en maintenant un pool de connexions persistantes, ce qui permet à la base de données de gérer des milliers de connexions d'applications avec beaucoup moins de processus backend.
- Composants side-car : Patroni et etcd sont légers, mais nécessitent une disponibilité constante du processeur. Dans les scénarios à charge élevée, assurez-vous que les VM ne sont pas surabonnées au niveau de l'hyperviseur pour éviter de "voler" les cycles de processeur requis pour les pulsations et la maintenance du leader.
- Réglage du noyau : l'automatisation Autobase applique automatiquement des optimisations bénéfiques pour PostgreSQL, telles que la configuration des paramètres sysctl (par exemple,
vm.swappiness,net.core.somaxconn) et la désactivation des pages géantes transparentes (THP). Ces modifications réduisent les frais généraux de gestion de la mémoire et améliorent le débit réseau pour les instances de base de données à fort trafic.
Avant de commencer
Avant de commencer le déploiement, vous devez vous assurer que votre environnement répond aux exigences suivantes.
Examiner les exigences liées aux VM
Pour les besoins de ce tutoriel, vous devez créer trois VM dans votre projet GDC sous air gap. Vous devez prendre en compte les points et exigences suivants pour les VM :
- Distribution par zone : pour que ce déploiement soit véritablement résilient aux défaillances de zone, vous devez répartir les VM sur trois zones de disponibilité différentes. Toutefois, le déploiement reste identique si les VM se trouvent dans deux zones ou même dans une seule zone. L'important est que toutes les VM puissent communiquer entre elles sur le réseau avec leurs adresses IP internes.
- Système d'exploitation : ce tutoriel suppose que vous utilisez des images Ubuntu 22.04. Les étapes suivantes de ce guide peuvent différer si vous utilisez une autre distribution.
- Ressources : vous devez provisionner au moins deux processeurs et 8 Go de mémoire par VM pour ce tutoriel. En production, vous devez provisionner des ressources adaptées à vos charges de travail spécifiques (voir Considérations sur les performances).
- Adresses IP réseau : vous devez noter les adresses IP internes et externes de chaque VM. Dans ce guide, vous utilisez des adresses IP externes pour le contrôle Ansible, car vous exécutez des commandes à partir d'un poste de travail externe. Les adresses IP internes sont utilisées pour la communication et la liaison entre les services. Si vous avez provisionné une VM d'amorçage dans le réseau, vous n'avez besoin que des adresses IP internes.
- Accès : un accès sudo sans mot de passe est requis pour l'utilisateur de déploiement, car l'automatisation Ansible doit effectuer des tâches d'administration (installer des packages, modifier les configurations système) sans être bloquée par des invites de mot de passe.
- SSH : l'authentification basée sur des clés doit être activée pour permettre à Ansible de se connecter aux VM cibles de manière sécurisée et non interactive.
Préparer le logiciel de poste de travail local
Pour gérer le déploiement et préparer les artefacts sous air gap, vous devez installer un ensemble d'outils d'automatisation et de conteneurisation sur votre poste de travail local.
- Ansible 2.17.0 ou version ultérieure : moteur d'automatisation qui exécute les playbooks et les rôles de déploiement.
- Docker : permet d'extraire et d'empaqueter les dépendances de l'OS dans un environnement identique à celui des VM cibles (Ubuntu 22.04).
- Client PostgreSQL (
psql) : requis pour exécuter les requêtes de test et vérifier la réplication des données depuis votre poste de travail local. Le dépôt Autobase :
- Clonez le dépôt pour accéder aux playbooks et aux rôles d'automatisation : https://github.com/vitabaks/autobase
Extrayez une version spécifique (ce guide utilise la version 2.5.2) :
git checkout 2.5.2Les étapes suivantes de ce guide peuvent différer si vous utilisez une autre distribution.
Pour exécuter les playbooks de ce guide, vous devez installer le code source
autobaselocal en tant que collection Ansible afin que les préfixes de rôle puissent être résolus :cd autobase/automation ansible-galaxy collection install . --force
Créez des variables d'environnement.
Tout au long de ce guide, vous utiliserez les variables d'environnement suivantes pour simplifier les commandes. Ces variables stockent des paramètres critiques tels que l'ID de votre projet, les zones de disponibilité de vos VM, leurs noms d'hôte et les étiquettes utilisées par l'équilibreur de charge pour identifier votre cluster. Définissez-les dans votre session de shell actuelle avec les valeurs réelles de votre environnement (assurez-vous que les zones sont séparées par des espaces).
Notez que même si vous pouvez définir les noms de votre choix pour vos VM, ce guide utilise postgres-vm-1, postgres-vm-2 et postgres-vm-3 comme exemples de noms arbitraires pour les nœuds du cluster :
export PROJECT_ID="your-project-id"
export ZONES="zone1 zone2 zone3"
export VM1_NAME="postgres-vm-1"
export VM2_NAME="postgres-vm-2"
export VM3_NAME="postgres-vm-3"
export VM_LABEL="app=my-postgres-cluster"
export CLUSTER_NAME="my-postgres-cluster"
Configurer Ansible
Définissez votre environnement de VM dans le fichier inventory.ini à l'aide du modèle suivant :
[master]
postgres-vm-1 ansible_host=XX.XX.XX.XX hostname=postgres-vm-1 bind_address=XX.XX.XX.XX
[replica]
postgres-vm-2 ansible_host=XX.XX.XX.XX hostname=postgres-vm-2 bind_address=XX.XX.XX.XX
postgres-vm-3 ansible_host=XX.XX.XX.XX hostname=postgres-vm-3 bind_address=XX.XX.XX.XX
[postgres_cluster:children]
master
replica
[etcd_cluster]
postgres-vm-1
postgres-vm-2
postgres-vm-3
[all:vars]
ansible_user=...
ansible_ssh_private_key_file=~/.ssh/...
postgresql_version=17
with_haproxy_load_balancing=false
patroni_superuser_password=...
etcd_package_repo="file:///tmp/packages/etcd-v3.5.25-linux-amd64.tar.gz"
installation_method="packages"
install_postgresql_repo=false
install_timescale_repo=false
install_citus_repo=false
apt_repository=[]
yum_repository=[]
install_system_packages=false
patroni_installation_method=deb
Comprendre la configuration :
[master]et[replica]: définissent les VM de base de données principale et secondaire. Veillez à utiliser les noms de VM réels définis dans les variables d'environnementVM1_NAME,VM2_NAMEetVM3_NAME.[postgres_cluster:children]: groupe qui regroupe les nœuds maître et réplique, ce qui permet à Ansible de cibler l'ensemble du cluster de base de données avec une seule commande.[etcd_cluster]: définit les nœuds qui participeront au cluster de consensus etcd. Cela inclut les trois nœuds de base de données pour garantir une haute disponibilité.ansible_host: (pour chaque VM) adresse IP d'entrée externe de la VM utilisée par Ansible pour s'y connecter. RemplacezXX.XX.XX.XXpar l'adresse IP externe réelle.bind_address: (pour chaque VM) adresse IP interne de la VM. RemplacezXX.XX.XX.XXpar l'adresse IP interne réelle.ansible_user: utilisateur distant qu'Ansible utilise pour se connecter aux VM cibles avec SSH. Remplacez...par le nom d'utilisateur réel.ansible_ssh_private_key_file: chemin d'accès local à la clé SSH privée utilisée pour l'authentification auprès des VM cibles. Remplacez~/.ssh/...par le chemin d'accès réel.patroni_superuser_password: mot de passe de l'utilisateurpostgres.with_haproxy_load_balancing=false: désactive HAProxy local, car vous utilisez l'équilibreur de charge L4 natif de la plate-forme.etcd_package_repo: pointe vers le chemin d'accès local du binaire etcd dans le répertoire d'amorçage de la VM.installation_method="packages": indique à l'automatisation d'installer les composants avec des packages d'OS plutôt que de les compiler à partir de la source ou d'utiliser Python pip.install_..._repo=falseet_repository=[]: ces remplacements empêchent Ansible d'essayer d'accéder à Internet pour ajouter des dépôts externes ou mettre à jour des listes de packages.install_system_packages=false: empêche l'automatisation d'essayer de télécharger et d'installer des packages que vous avez déjà provisionnés lors de la phase d'initialisation ou d'amorçage.patroni_installation_method=deb: indique spécifiquement au rôle d'utiliser le package.debque vous avez installé.
Initialiser les VM
La pile de base de données nécessite plusieurs packages et bibliothèques d'OS qui ne sont peut-être pas inclus dans votre image Ubuntu de base. Comme les VM se trouvent dans un environnement sous air gap sans accès à Internet, elles ne peuvent pas télécharger elles-mêmes ces dépendances.
Pour résoudre ce problème, procédez comme suit :
Utilisez un conteneur Docker sur votre poste de travail local pour télécharger tous les fichiers nécessaires. La commande suivante utilise
apt-rdependspour identifier de manière récursive chaque bibliothèque partagée et chaque dépendance requise par les applications cibles. Il configure le dépôt PostgreSQL officiel dans le conteneur pour récupérer les artefacts de la version 17, puis parcourt la liste des dépendances pour télécharger des fichiers.debindividuels tout en filtrant les bibliothèques système de base (commelibc6ouhostname) afin d'éviter les conflits de version sur les VM cibles. Enfin, il récupère le binaire etcd autonome directement depuis GitHub.Commencez par créer un répertoire pour stocker les packages :
mkdir -p ./packagesExécutez ensuite la commande Docker pour télécharger tous les packages requis et le binaire etcd :
docker run --rm --platform linux/amd64 -v "$(pwd)/packages:/packages" \ ubuntu:22.04 bash -c " set -e apt-get update apt-get install -y ca-certificates curl gnupg apt-rdepends # Add PostgreSQL Repository curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \ gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg echo 'deb http://apt.postgresql.org/pub/repos/apt jammy-pgdg main' > \ /etc/apt/sources.list.d/pgdg.list apt-get update # Define Application Targets + Explicit dependencies needed for air-gap TARGETS='unzip tar pgbouncer patroni netdata postgresql-17 \ postgresql-client-17 postgresql-contrib-17 \ postgresql-server-dev-17 postgresql-17-dbgsym \ python3-psycopg2 python3-click python3-yaml python3-prettytable \ python3-urllib3 python3-tz python3-pip python3-setuptools \ python3-cryptography moreutils vim jq acl zstd libjq1 \ libpython3.10-stdlib libexpat1-dev zlib1g-dev libipc-run-perl \ libtime-duration-perl libjson-perl libpython3-dev \ libjs-sphinxdoc python3-wheel' # Resolve all recursive dependencies ALL_DEPS=\$(apt-cache depends --recurse --no-recommends --no-suggests \ --no-conflicts --no-breaks --no-replaces --no-enhances \$TARGETS | \ grep '^\w' | sort -u) cd /packages for pkg in \$ALL_DEPS; do if apt-cache show \"\$pkg\" > /dev/null 2>&1; then # Filter system core to avoid VM conflicts/breaks # We exclude core OS libraries (libc, systemd, etc.) because these # often cause version conflicts if the VM's patch level differs # from the online container. FILTER='base-files|debianutils|coreutils|findutils|diffutils|sed' FILTER+='|grep|gzip|hostname|ncurses|perl-base|libc6|binutils' FILTER+='|linux-libc|libc-bin|libc-dev-bin|systemd|dpkg|init' if [[ ! \"\$pkg\" =~ \$FILTER ]]; then apt-get download \"\$pkg\" || echo \"Failed \$pkg\" fi fi done # Download etcd binary if [ ! -f etcd-v3.5.25-linux-amd64.tar.gz ]; then curl -L https://github.com/etcd-io/etcd/releases/download/v3.5.25/\ etcd-v3.5.25-linux-amd64.tar.gz -o etcd-v3.5.25-linux-amd64.tar.gz fi "Utilisez Ansible pour importer l'archive sur les trois VM cibles simultanément :
ansible all -i inventory.ini -m copy -a "src=packages.tar.gz dest=/tmp/" -bEffacez toutes les données de package existantes sur les VM et extrayez le nouveau fichier tar :
ansible all -i inventory.ini -m shell -a "rm -rf /tmp/packages && \ mkdir -p /tmp/packages && tar -xzf /tmp/packages.tar.gz -C /tmp/packages" -bEffectuez une installation non interactive de tous les packages
.debtéléchargés. Pour éviter les problèmes liés à des prédépendances spécifiques dans un environnement sous air gap, utilisez l'option--force-dependssuivie deapt-get install -fypour résoudre l'arborescence de dépendances localement :ansible all -i inventory.ini -m shell -a "DEBIAN_FRONTEND=noninteractive \ NEEDRESTART_MODE=a dpkg -i --force-depends /tmp/packages/*.deb" -b ansible all -i inventory.ini -m shell -a "DEBIAN_FRONTEND=noninteractive \ NEEDRESTART_MODE=a apt-get install -fy" -bArrêtez immédiatement tous les services pour éviter qu'ils ne démarrent avec des états par défaut non configurés avant que l'automatisation ne soit prête :
ansible all -i inventory.ini -m shell -a \ "systemctl stop patroni etcd pgbouncer postgresql || true" -bEnfin, supprimez les clusters PostgreSQL par défaut et toutes les données etcd existantes pour permettre une initialisation propre :
ansible all -i inventory.ini -m shell -a \ "pg_dropcluster 17 main --stop || true" -b ansible all -i inventory.ini -m shell -a \ "rm -rf /var/lib/postgresql/17/main/* /var/lib/etcd/default.etcd/*" -b
Provisionner l'infrastructure de base de données
Une fois les VM amorcées et l'inventaire configuré, vous pouvez utiliser les playbooks d'automatisation Autobase avec Ansible pour déployer la pile PostgreSQL à disponibilité élevée.
Tout d'abord, exécutez les vérifications préalables pour vous assurer que l'environnement est prêt :
ansible-playbook vitabaks.autobase.deploy_pgcluster -i inventory.ini \
--tags pre_checks
Si les vérifications réussissent, procédez au déploiement complet :
ansible-playbook vitabaks.autobase.deploy_pgcluster -i inventory.ini
Résultat attendu : le playbook doit se terminer par un message "PLAY RECAP" indiquant que toutes les VM cibles ont été atteintes et mises à jour :
PLAY RECAP ********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=254 rescued=0 ignored=0
postgres-vm-1 : ok=160 changed=53 unreachable=0 failed=0 skipped=514 rescued=0 ignored=2
postgres-vm-2 : ok=116 changed=40 unreachable=0 failed=0 skipped=505 rescued=0 ignored=2
postgres-vm-3 : ok=116 changed=40 unreachable=0 failed=0 skipped=505 rescued=0 ignored=2
Vérifier le déploiement
Une fois le déploiement terminé, vous devez effectuer plusieurs vérifications pour vous assurer que tous les composants fonctionnent correctement.
Vérifier l'état de la haute disponibilité
Vérifiez l'état du gestionnaire de haute disponibilité pour voir les rôles attribués à chaque VM :
ansible master -i inventory.ini -m shell -a "patronictl list" -b
Exemple de résultat :
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Leader | running | 1 | | | | |
| postgres-vm-2 | 10.253.1.253 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
Vérifier les points de terminaison de vérification de l'état d'état
Vérifiez que Patroni identifie correctement le leader et les instances répliquées à l'aide de son API REST.
La vérification de l'état de la VM leader doit renvoyer 200 OK, tandis que les vérifications de l'état des VM d'instance répliquée doivent renvoyer 503 Service Unavailable :
ansible ${VM1_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
ansible ${VM2_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
ansible ${VM3_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
Vérifier l'état d'une VM individuelle
Vérifiez la disponibilité de toutes les instances PostgreSQL :
ansible postgres_cluster -i inventory.ini -m shell -a "pg_isready -p 5432" -b
Exemple de résultat :
postgres-vm-1 | CHANGED | rc=0 >>
/var/run/postgresql:5432 - accepting connections
postgres-vm-2 | CHANGED | rc=0 >>
/var/run/postgresql:5432 - accepting connections
postgres-vm-3 | CHANGED | rc=0 >>
/var/run/postgresql:5432 - accepting connections
Vérifier l'état d'etcd
Vérifiez l'état de la couche de consensus sur toutes les VM en utilisant localhost comme point de terminaison :
ansible all -i inventory.ini -m shell -a "ETCDCTL_API=3 etcdctl \
--endpoints=https://localhost:2379 \
--cacert=/etc/etcd/tls/ca.crt \
--cert=/etc/etcd/tls/server.crt \
--key=/etc/etcd/tls/server.key \
endpoint health" -b
Exemple de résultat :
postgres-vm-1 | CHANGED | rc=0 >>
https://localhost:2379 is healthy: successfully committed proposal: \
took = 28.78311ms
postgres-vm-2 | CHANGED | rc=0 >>
https://localhost:2379 is healthy: successfully committed proposal: \
took = 33.081265ms
postgres-vm-3 | CHANGED | rc=0 >>
https://localhost:2379 is healthy: successfully committed proposal: \
took = 24.414291ms
Configurer l'équilibreur de charge global
Pour fournir une adresse IP virtuelle (VIP) stable pour la pile de base de données, configurez l'équilibreur de charge L4 global natif de la plate-forme à l'aide de la CLI gdcloud.
Prérequis :
- Assurez-vous de disposer du rôle
load-balancer-admindans votre projet. Appliquez un libellé à vos VM afin que l'équilibreur de charge puisse cibler correctement les instances qu'il doit diffuser (remplacez les valeurs de paramètre
kubeconfigpar les fichierskubeconfigde l'API Management correspondants pour chaque zone) :kubectl --kubeconfig=ZONE_A_MANAGEMENT_API label VirtualMachine \ -n ${PROJECT_ID} \ ${VM1_NAME} \ ${VM_LABEL} kubectl --kubeconfig=ZONE_B_MANAGEMENT_API label VirtualMachine \ -n ${PROJECT_ID} \ ${VM2_NAME} \ ${VM_LABEL} kubectl --kubeconfig=ZONE_C_MANAGEMENT_API label VirtualMachine \ -n ${PROJECT_ID} \ ${VM3_NAME} \ ${VM_LABEL}
- Assurez-vous de disposer du rôle
Définissez le niveau d'accès de l'équilibrage de charge. Définissez
EXTERNALsi vous devez vous connecter depuis l'extérieur du réseau du projet, ouINTERNALsi l'accès n'est requis que depuis le VPC. Pour ce tutoriel, nous allons utiliser une configuration externe :export LB_SCHEME=EXTERNALCréez une vérification d'état. L'équilibreur de charge utilise l'API REST de Patroni pour identifier le leader :
gdcloud compute health-checks create https ${CLUSTER_NAME}-hc \ --project=${PROJECT_ID} \ --port=8008 \ --request-path="/primary" \ --check-interval=10 \ --timeout=5 \ --healthy-threshold=2 \ --unhealthy-threshold=3 \ --globalCréez un backend zonal distinct pour chaque zone où se trouvent vos VM :
for zone in $(echo $ZONES); do gdcloud compute backends create ${CLUSTER_NAME}-backend-${zone} \ --project=${PROJECT_ID} \ --zone=${zone} \ --labels="${VM_LABEL}" doneCréez un service de backend global :
gdcloud compute backend-services create ${CLUSTER_NAME}-bes \ --project=${PROJECT_ID} \ --health-check="${CLUSTER_NAME}-hc" \ --globalAjoutez vos backends zonaux au service global :
for zone in $(echo $ZONES); do gdcloud compute backend-services add-backend ${CLUSTER_NAME}-bes \ --project=${PROJECT_ID} \ --backend=${CLUSTER_NAME}-backend-${zone} \ --backend-zone=${zone} \ --global doneCréez une règle de transfert globale (l'adresse IP virtuelle). Cette règle expose la base de données sur le port
6432:gdcloud compute forwarding-rules create ${CLUSTER_NAME}-fr \ --project=${PROJECT_ID} \ --load-balancing-scheme=${LB_SCHEME} \ --backend-service=${CLUSTER_NAME}-bes \ --ip-protocol-port="TCP:6432" \ --globalRécupérez l'adresse VIP :
LB_IP=$(gdcloud compute forwarding-rules describe ${CLUSTER_NAME}-fr \ --project=${PROJECT_ID} \ --load-balancing-scheme=${LB_SCHEME} \ --global \ --format=json \ | jq -r '.metadata.annotations["networking.gke.io/forwardingRuleCIDR"]' \ | cut -d '/' -f 1) echo "The load balancer IP is: ${LB_IP}"Créez une
ProjectNetworkPolicy(PNP) pour autoriser le trafic entrant vers le port PgBouncer (remplacez la valeur du paramètrekubeconfigpar le fichierkubeconfigde l'API globale correspondant à votre environnement).kubectl --kubeconfig=GLOBAL_API_KUBECONFIG apply -f - <<EOF apiVersion: networking.global.gdc.goog/v1 kind: ProjectNetworkPolicy metadata: name: allow-pgbouncer namespace: ${PROJECT_ID} spec: ingress: - ports: - port: 6432 protocol: TCP policyType: Ingress subject: subjectType: UserWorkload EOF
Vérifier la réplication des données
Pour confirmer que la pile de haute disponibilité fonctionne comme prévu, vous pouvez créer des exemples de données sur le leader et vérifier leur présence sur les instances répliquées.
Insérer des exemples de données
L'automatisation génère un mot de passe aléatoire pour l'utilisateur postgres lors du premier déploiement si aucun mot de passe n'est fourni dans inventory.ini. Vous pouvez le récupérer à partir de n'importe quelle VM :
export PG_PASSWORD=$(ansible master -i inventory.ini -m shell -a \
"grep -A10 'authentication:' /etc/patroni/patroni.yml | \
grep -A3 'superuser' | grep 'password:' | awk '{ print \$2 }'" -b | \
tail -n 1)
echo $PG_PASSWORD
Connectez-vous à l'adresse IP virtuelle de l'équilibreur de charge sur le port PgBouncer (6432) et créez un exemple de table :
PGPASSWORD="${PG_PASSWORD}" psql -h ${LB_IP} -p 6432 -U postgres -c "
CREATE TABLE employees (first_name TEXT, last_name TEXT);
INSERT INTO employees (first_name, last_name) VALUES ('John', 'Doe');
"
Résultat attendu :
INSERT 0 1
Vérifier l'état de la réplication
Exécutez une requête SELECT sur toutes les VM pour vous assurer que les données ont été répliquées du leader vers toutes les instances répliquées :
ansible postgres_cluster -i inventory.ini -m shell -a "psql -U postgres -c \
'SELECT * FROM employees;'" -b
Exemple de résultat :
postgres-vm-1 | CHANGED | rc=0 >>
first_name | last_name
------------+-----------
John | Doe
(1 row)
postgres-vm-2 | CHANGED | rc=0 >>
first_name | last_name
------------+-----------
John | Doe
(1 row)
postgres-vm-3 | CHANGED | rc=0 >>
first_name | last_name
------------+-----------
John | Doe
(1 row)
Tester la commutation manuelle
Une commutation manuelle vous permet de déplacer de manière fluide le rôle de leader vers une VM candidate spécifique. Cette opération est généralement effectuée pour la maintenance planifiée, les mises à niveau logicielles ou pour équilibrer l'utilisation des ressources entre les zones.
Identifier le leader actuel
Vérifiez le rôle et l'état actuels des VM :
ansible master -i inventory.ini -m shell -a "patronictl list" -b
Exemple de résultat :
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Leader | running | 1 | | | | |
| postgres-vm-2 | 10.253.1.253 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 1 | 0/6000000 | 0 | 0/6000000 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
Effectuer le basculement
Déclenchez un basculement du leader actuel vers une autre VM (dans ce cas, respectivement de postgres-vm-1 vers postgres-vm-2). La commande utilise --force pour ignorer les invites de confirmation manuelle :
ansible master -i inventory.ini -m shell -a "patronictl switchover \
--leader ${VM1_NAME} --candidate ${VM2_NAME} --force" -b
Exemple de résultat :
Successfully switched over to "postgres-vm-2"
+ Cluster: postgres-cluster (7607933704953386478) -+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+---------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Replica | stopped | | unknown | | unknown | |
| postgres-vm-2 | 10.253.1.253 | Leader | running | 1 | | | | |
| postgres-vm-3 | 10.253.1.252 | Replica | running | 1 | 0/70000A0 | 0 | 0/70000A0 | 0 |
+---------------+--------------+---------+---------+----+-------------+-----+------------+-----+
Vérifier le changement de vérification de l'état
Après la commutation, vérifiez que l'état de la vérification de l'état d'état est passé au nouveau leader :
ansible ${VM1_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
ansible ${VM2_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
L'ancien leader (postgres-vm-1) doit renvoyer 503, tandis que le nouveau leader (postgres-vm-2) doit renvoyer 200.
Tester le basculement automatique
Contrairement à une commutation manuelle, un basculement automatique se produit lorsque la VM leader devient indisponible. Ce test confirme que Patroni élit un nouveau leader et que l'équilibreur de charge redirige le trafic sans intervention manuelle. Supposons que postgres-vm-2 soit le leader actuel après le basculement manuel effectué précédemment.
Identifier le leader actuel
Vérifiez le rôle et l'état actuels des VM :
ansible master -i inventory.ini -m shell -a "patronictl list" -b
Exemple de résultat :
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Replica | streaming | 2 | 0/8000000 | 0 | 0/8000000 | 0 |
| postgres-vm-2 | 10.253.1.253 | Leader | running | 2 | | | | |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 2 | 0/8000000 | 0 | 0/8000000 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
Simuler une défaillance de VM
Arrêtez le service patroni sur la VM leader pour simuler un plantage ou une défaillance matérielle :
ansible master -i inventory.ini -m shell -a "systemctl stop patroni" -b
Observer la nouvelle élection
Attendez 10 à 20 secondes, puis vérifiez l'état à partir d'une autre VM pour voir la promotion d'un nouveau leader :
ansible replica -i inventory.ini -m shell -a "patronictl list" -b
Exemple de résultat :
postgres-vm-3 | CHANGED | rc=0 >>
+ Cluster: postgres-cluster (7607933704953386478) ---+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| postgres-vm-1 | 10.253.1.254 | Leader | running | 3 | | | | |
| postgres-vm-2 | 10.253.1.253 | Replica | stopped | | unknown | | unknown | |
| postgres-vm-3 | 10.253.1.252 | Replica | streaming | 3 | 0/90003F8 | 0 | 0/90003F8 | 0 |
+---------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
Vous devriez voir que l'une des autres VM (postgres-vm-1 ou postgres-vm-3) est devenue le leader et que l'ancien leader (postgres-vm-2) est marqué comme arrêté.
Vérifier le changement de vérification de l'état
Vérifiez que les vérifications d'état de l'équilibreur de charge identifient désormais correctement le leader nouvellement élu :
ansible ${VM1_NAME} -i inventory.ini -m shell -a \
"curl -ks -o /dev/null -w '%{http_code}' https://localhost:8008/primary" -b
Le nouveau leader doit renvoyer 200 OK.
Récupérer la VM défaillante
Redémarrez le service patroni sur la VM d'origine pour qu'elle rejoigne la pile en tant qu'instance répliquée et rattrape les données manquantes :
ansible ${VM2_NAME} -i inventory.ini -m shell -a \
"systemctl start patroni" -b