Postgres-Operator#
Sur notre infrastructure nous utilisons l'operator postgres de Zalando.
Version actuelle 1.6.1
Fonctionnement#
Implémentation#
Vous trouverez un service postgres-operator dans le namespace postgres-operator dans chaque zone qui communique directement avec les clusters postgres de chaque service
Déploiement#
Le déploiement s'effectue avec la couche kustomize qui est piloté via un playbook ansible
Logical Backup#
Cette fonction permet de créer des dump des base et de les uploder sur un bucket S3, permet de décentraliser les data et apporte une solution de PRA (plan de reprise d’activité)
La couche terraforme créé les bucket S3 sur FE avec l'implémentation des secret dans vault accessible grace au service account.
Un rétention est directement définie sur le bucket S3 car l'operator postgres ne permet pas de supprimer de la data sur le bucket.
Le nom du bucket : postgres-backup-{{ zone_name }}
Visualisation des dump sur le bucket S3 FE :
Fixme
Missing content
Restore#
Il n’existe pas de service de roolback avec l'operator mais des solution sont possibles:
- Créer un clone d'un cluster via un dump disponible sur un bucket S3
- Importer le dump après la création d'un cluster vierge
Retour d’expérience#
| Incident | Cause | Résolution | Impacte |
|---|---|---|---|
| L'operator ne peux pas généré le STS | Modification du STS non pris en charge pas l'operator (label) | l est possible de l'ajouté manuellement en ajoutant la modification dans l'objet postgresql et dans le sts, sinon vous devez détrure le sts (cluster postgres) et l'operator va regénéré le sts avec les nouveaux paramètres. | Le cluster est fonctionnelle mais mais plus sync avec l'operator, risque de divergence des slaves |
| Cluster postgres qui n'est plus sync | STS pas a jour, erreur de configuration du cluster, divergence des replicas | Vérification des log du cluster, reinit les pod replica, recréation du sts, vérification du déploiement | Le cluster n'est pas forcement opérationnelle, risque de divergence des slaves voir destruction |
| Cache hit ratio < 90% | manque de mémoire (RAM) dans le cluster | Augmentation de la RAM dans le cluster | Performance du cluster |
Commandes utiles#
Visualisation des schedule logical backup#
kubectl get cronjob -A | grep logical-
Création d'un JOB pour backup un cluster manuellement#
kubectl create job --from=cronjob/NOM_DU_CRON NOM_DU_JOB -n NAME_SPACE
## exemple pour clair
kubectl create job --from=cronjob/logical-backup-clair-postgresql-cluster logical-backup-clair-postgresql-cluster -n clair
Vérification de l’état d'un clusteur#
kubectl get postgresql -A
NAMESPACE NAME TEAM VERSION PODS VOLUME CPU-REQUEST MEMORY-REQUEST AGE STATUS
clair clair-postgresql-cluster clair 11 3 50Gi 100m 400Mi 4d Running
concourse-infra concourse-postgresql concourse 11 2 50Gi 100m 256Mi 54d Running
gitea gitea-postgresql-cluster gitea 11 3 20Gi 100m 100Mi 17h Running
keycloak pocwatt-keycloak-cluster pocwatt 11 3 2Gi 100m 200Mi 59d Running
quay quay-postgresql-cluster quay 11 3 50Gi 100m 200Mi 23h Running
## Vérification dans le cluster via patroni
kubectl exec -it -n quay quay-postgresql-cluster-1 -- bash -c "patronictl list"
+ Cluster: quay-postgresql-cluster (6869646851055235153) -----+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+---------------------------+--------------+--------+---------+----+-----------+
| quay-postgresql-cluster-0 | 172.16.0.118 | Leader | running | 2 | |
| quay-postgresql-cluster-1 | 172.16.1.4 | | running | 2 | 0 |
| quay-postgresql-cluster-2 | 172.16.0.192 | | running | 2 | 0 |
+---------------------------+--------------+--------+---------+----+-----------+
Création d'un dump sql d'une base#
## Vérification du pod master
kubectl get -A pod -l application=spilo,spilo-role=master
## Exécution du dump sur le master (exemple keycloak)
kubectl exec -it -n keycloak pocwatt-keycloak-cluster-2 -- bash -c "pg_dump -Fc -cC -U keycloak -d keycloak" > dump-keycloak.sql
Récupération d'un dump sql depuis le bucket S3#
Les dumps sont rangés sur le bucket propre à chaque zone, selon la règle de nommage suivante :
s3://postgres-backup-${ZONE_NAME}/snapshots/YYYY-MM-AA/postgres-dump-${ZONE_NAME}-${DB_USER}-${DB_NAME}-YYYYMMAA-HHmm.sql
Les identifiants de connexion sont rangés dans le vault propre à la zone :
export VAULT_ADDR=https://vault.ocb-test01.caascad.com
vault login -method oidc
export AWS_ACCESS_KEY_ID=$(vault kv get -field=access_key secret/bucket/postgres-backup)
export AWS_SECRET_ACCESS_KEY=$(vault kv get -field=secret_key secret/bucket/postgres-backup)
env | aws s3 ls s3://postgres-backup-ocb-test01/snapshots/2021-06-13/ \
--endpoint-url=https://oss.eu-west-0.prod-cloud-ocb.orange-business.com \
--region=eu-west-0
env | aws s3 cp s3://postgres-backup-ocb-test01/snapshots/2021-06-13/postgres-dump-ocb-test01-keycloak-keycloak-20210613-0009.sql.gz ./dump.sql.gz \
--endpoint-url=https://oss.eu-west-0.prod-cloud-ocb.orange-business.com \
--region=eu-west-0
Suppression d'un cluster et PVC#
## Exemple avec quay
kubectl delete postgresql -n quay quay-postgresql-cluster
cela peut prendre du temps, si le clusteur n'est plus sync vous pouvez le faire a la main
Importation d'un dump .sql (backup manuel ou importation S3)#
Warning
les fichiers dump.sql contiennent la plupart du temps des commandes qui nécessitent qu'aucune connexion ne soit active sur la base, typiquement DROP DATABASE.
Afin de couper les connexions, exécutez les commandes suivantes :
## récupération du pod Leader de tous les clusters
kubectl get -A pod -l application=spilo,spilo-role=master
NAMESPACE NAME READY STATUS RESTARTS AGE
keycloak pocwatt-keycloak-cluster-1 2/2 Running 0 6d22h
## connexion à la base via le pod Leader
kubectl exec -it -n keycloak pocwatt-keycloak-cluster-1 -- bash -c "psql -U keycloak -d keycloak"
## commande SQL pour lister les connexions
SELECT pg_stat_activity.pid
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'keycloak' -- nom de la database a fournir ici
AND pid <> pg_backend_pid();
## commande SQL pour supprimer les connexions
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'keycloak'
AND pid <> pg_backend_pid();
Pour importer le fichier dump.sql, passer par le Leader également :
## exécution du script via le pod Leader (apres que les connexions aient été coupées)
cat database.sql | kubectl exec -it -n keycloak pocwatt-keycloak-cluster-1 -- bash -c "pg_restore -Fc -v ON_ERROR_STOP=1 -U keycloak -d keycloak"
L'option ON_ERROR_STOP=1 est préconisée pour l'import.
Changement de master#
## Vérification du cluster via patroni
kubectl exec -it -n quay quay-postgresql-cluster-1 -- bash -c "patronictl list"
## changement de master
kubectl exec -it -n quay quay-postgresql-cluster-1 -- bash -c "patronictl switchover"
Reinit d'un pod master suite à une erreur de synchro entre les membres (beaucoup de fichiers WAL)#
Warning
Tout d'abord, essayer de réinitialiser le pod slave : rubrique suivante
Si cela ne résoud pas le soucis. Se connecter au pod, et lancer les commandes suivantes
Note
Prenons l'exemple d'un problème d'espace disque avec le master postgres Gitea dans le namespace gitea
kubectl exec -it -n gitea gitea-postgresql-cluster-0 -c postgres -- bash
____ _ _
/ ___| _ __ (_) | ___
\___ \| '_ \| | |/ _ \
___) | |_) | | | (_) |
|____/| .__/|_|_|\___/
|_|
This container is managed by runit, when stopping/starting services use sv
Examples:
sv stop cron
sv restart patroni
Current status: (sv status /etc/service/*)
down: /etc/service/patroni: 2828s, normally up
down: /etc/service/pgqd: 2829s, normally up
Détection leader.
root@gitea-postgresql-cluster-0:/home/postgres# patronictl list
+ Cluster: clair-postgresql-cluster (7025907046366744645) -----+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+----------------------------+--------------+--------+---------+----+-----------+
| clair-postgresql-cluster-0 | 172.16.1.8 | | stopped | | unknown |
| clair-postgresql-cluster-1 | 172.16.0.247 | | stopped | | unknown |
| clair-postgresql-cluster-2 | 172.16.1.18 | Leader | running | 7 | |
+----------------------------+--------------+--------+---------+----+-----------+
Revalidation du leader pour éviter les cas de split-brain et de maintenance en cours.
kubectl exec -it -n gitea gitea-postgresql-cluster-2 -c postgres -- bash -c "patronictl list"
+ Cluster: clair-postgresql-cluster (7025907046366744645) -----+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+----------------------------+--------------+--------+---------+----+-----------+
| clair-postgresql-cluster-0 | 172.16.1.8 | | stopped | | unknown |
| clair-postgresql-cluster-1 | 172.16.0.247 | | stopped | | unknown |
| clair-postgresql-cluster-2 | 172.16.1.18 | Leader | running | 7 | |
+----------------------------+--------------+--------+---------+----+-----------+
Choisir un point d'historique à partir du quel vous purgez.
Prendre un fichier de 16M (16777216) suivi directement d'un fichier .history.
Ce même fichier de 16M sera donc votre fichier devant être fourni à la ligne de commande d'archivage.
kubectl exec -it -n gitea gitea-postgresql-cluster-2 -c postgres -- bash -c "ls -al /home/postgres/pgdata/pgroot/data/pg_wal/ | more"
total 245796
drwx------. 3 postgres postgres 4096 Nov 25 09:14 .
drwx------. 19 postgres postgres 4096 Nov 25 14:30 ..
-rw-------. 1 postgres postgres 42 Nov 17 08:52 00000002.history
-rw-------. 1 postgres postgres 85 Nov 17 08:57 00000003.history
-rw-------. 1 postgres postgres 128 Nov 17 09:16 00000004.history
-rw-------. 1 postgres postgres 171 Nov 17 09:18 00000005.history
-rw-------. 1 postgres postgres 214 Nov 17 09:20 00000006.history
-rw-------. 1 postgres postgres 16777216 Nov 25 08:28 000000060000000200000077
-rw-------. 1 postgres postgres 257 Nov 25 08:29 00000007.history
-rw-------. 1 postgres postgres 16777216 Nov 25 08:59 000000070000000200000077
-rw-------. 1 postgres postgres 16777216 Nov 25 09:04 000000070000000200000078
-rw-------. 1 postgres postgres 16777216 Nov 25 09:04 000000070000000200000079
-rw-------. 1 postgres postgres 16777216 Nov 25 09:05 00000007000000020000007A
-rw-------. 1 postgres postgres 16777216 Nov 25 09:05 00000007000000020000007B
-rw-------. 1 postgres postgres 16777216 Nov 25 09:07 00000007000000020000007C
-rw-------. 1 postgres postgres 16777216 Nov 25 09:10 00000007000000020000007D
-rw-------. 1 postgres postgres 16777216 Nov 25 09:10 00000007000000020000007E
-rw-------. 1 postgres postgres 16777216 Nov 25 09:40 00000007000000020000007F
-rw-------. 1 postgres postgres 16777216 Nov 25 02:59 000000070000000200000080
-rw-------. 1 postgres postgres 16777216 Nov 25 02:56 000000070000000200000081
-rw-------. 1 postgres postgres 16777216 Nov 25 02:54 000000070000000200000082
-rw-------. 1 postgres postgres 16777216 Nov 25 02:59 000000070000000200000083
-rw-------. 1 postgres postgres 16777216 Nov 25 03:29 000000070000000200000084
drwx------. 2 postgres postgres 4096 Nov 25 09:40 archive_status
Stopper la base de données et jouer la commande d'archivage
kubectl exec -it -n gitea gitea-postgresql-cluster-2 -c postgres -- bash -c "sv stop /etc/service/pgqd"
ok: down: /etc/service/pgqd: 695083s, normally up
kubectl exec -it -n gitea gitea-postgresql-cluster-2 -c postgres -- bash -c "pg_archivecleanup /home/postgres/pgdata/pgroot/data/pg_wal 000000060000000200000077"
Forcer la recréation du pod, pour qu'il prenne en compte la purge et se déverouille. L'option agit comme un kill -9
kubectl delete -n gitea gitea-postgresql-cluster-2 --force
Votre master est de nouveau opérationnel, vous pouvez le voir grâce à votre exporter ou votre application qui devrait réussir sa connexion.
Warning
Lorsque le master est de nouveau opérationnel, voir si le(s) slave(s) doivent être également réinitialisés. C'est le cas s'ils sont aussi en erreur (start failed / stopped).
En cas d'échec, seule la restoration depuis une sauvegarde pourra convenir :
-
tous les noeuds sont en erreurs
-
le master ne redémarre (postgres UP, leader patroni et base accessible via l'exporter) pas malgré l'archivage des fichiers WAL
-
le master ne redémarre pas malgré la suppression du pod
Reinit d'un pod slave suite à une erreur de synchro avec le master (beaucoup de fichiers WAL)#
Warning
Vérifier l'état de santé du master. En cas d'anomalie essayer de réinitialiser le pod master : rubrique précédente
Tout d'abord, essayer de réinitialiser le pod slave, se connecter au pod, et lancer la commande suivante :
kubectl exec -it -n concourse-infra concourse-postgresql-0 -- bash -c "patronictl reinit concourse-postgresql concourse-postgresql-1"
Si la réinitialisation ne fonctionne pas correctement, détruire le pod AVANT (avec un kubectl delete), attendre qu'il se lance, puis faire la commande de réinitialisation patroni.
Procédure de restauration manuelle d'une BDD#
De manière optionnelle et afin d'éviter des erreurs applicatives il est possible de supprimer l'application qui consomme la BDD
kubectl delete deployment {{Application}}
Copie du backup sur un des pods du cluster postgresql :
kubectl cp backup.sql ${PSQL_POD_NAME}:/tmp
Connexion au pod :
kubectl exec -it ${PSQL_POD_NAME} -- bash
su - postgres
psql
Isolation de la db pour restauration :
REVOKE CONNECT ON DATABASE <db_name> FROM public;
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = '<db_name>';
exit;
psql -f /tmp/backup.sql
Déverrouillage de la base:
psql
GRANT CONNECT ON DATABASE keycloak FROM public;
