Lyon, le 3 janvier 2025
CloudNativePG ou comment embarquer un éléphant sur un porte-conteneurs ! Voici le premier article d’une série pour découvrir l’opérateur CloudNativePG, ses fonctionnalités, comprendre comment il vous permet de déployer PostgreSQL mais également voir quels sont les changements à appréhender en embarquant un éléphant sur un porte-conteneurs !
Au programme de ce premier article : l’installation de l’opérateur et le déploiement d’une instance PostgreSQL avec un secondaire !
Un opérateur ? Quésaco ?
Un opérateur est un outil logiciel qui élargit les fonctionnalités de Kubernetes afin de gérer spécifiquement un type de ressource ou d’application. Plusieurs centaines d’opérateurs existent. Une dizaine existe pour PostgreSQL, et la plupart sont référencés sur operatorhub.io.
Il y en a pour tous les goûts : logging, stockage, networking, big data,
… et en l’occurrence, CloudNativePG est un opérateur qui permet de gérer
…
(petit indice : vous êtes sur le blog de Dalibo)
…
des instances PostgreSQL 🐘! Incroyable !
Cet opérateur s’est fait connaître au grand jour en 2022, lorsque EnterpriseDB a décidé de libérer le projet.
Grâce à lui, il nous est possible de déployer facilement une instance PostgreSQL dans notre cluster Kubernetes. D’ailleurs comment fait-on cela ?
Déployer une instance
Pas si vite ! Avant de déployer une instance, il est nécessaire d’installer
l’opérateur CloudNativePG mais il nous faut surtout un cluster Kubernetes.
Sentez-vous libres de choisir la distribution et le fournisseur Kubernetes de
votre choix. Pour cette série d’articles, j’utiliserai principalement l’outil
minikube
qui me permet de déployer
un cluster Kubernetes en local sur ma machine.
minikube start
Maintenant que j’ai un cluster Kubernetes, je vais pouvoir déployer l’opérateur.
Différentes méthodes d’installation existent. Il est possible par exemple de
l’installer via helm
ou avec kubectl
. Je me contenterai de déployer
l’opérateur en appliquant les différents fichiers yaml
(fournis par le projet
CloudNativePG) avec l’outil kubectl
. L’idée est de ne pas vous égarer avec
l’utilisation de multiples outils (moi-même, je serai capable de me perdre 😅).
kubectl
, à l’instar de pg_ctl
pour PostgreSQL, permet d’interagir avec un
cluster Kubernetes.
$ kubectl apply --server-side -f \
https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.24/releases/cnpg-1.24.1.yaml
Cette commande permet d’installer CloudNativePG en récupérant un fichier yaml
disponible sur internet. Ce fichier contient la définition de différentes
ressources. Lorsqu’il est appliqué sur le cluster, Kubernetes comprend ce
qu’il doit faire, et va notamment :
- créer le
Deployment
cnpg-controller-manager
, qui est en charge de déployer une image de CloudNativePG, l’application qui va bichonner nos instances ;kubectl get deployment -n cnpg-system NAME READY UP-TO-DATE AVAILABLE AGE cnpg-controller-manager 1/1 1 1 30s
Notre controller est prêt (
READY
). - créer un ensemble de nouvelles ressources, étendant ainsi l’API de
Kubernetes.
kubectl api-resources --api-group=postgresql.cnpg.io -o name backups.postgresql.cnpg.io clusterimagecatalogs.postgresql.cnpg.io clusters.postgresql.cnpg.io databases.postgresql.cnpg.io imagecatalogs.postgresql.cnpg.io poolers.postgresql.cnpg.io publications.postgresql.cnpg.io scheduledbackups.postgresql.cnpg.io subscriptions.postgresql.cnpg.io
Ce sont ces ressources-là qui vont nous intéresser. Elles correspondent à
des ressources PostgreSQL comme Cluster
ou encore Subscription
que nous
allons pouvoir créer.
Déployer une instance (cette fois-ci c’est la bonne)
Nous voici avec un cluster Kubernetes dans lequel fonctionne l’opérateur CloudNativePG. Il me semble que nous avons tout ce qu’il nous faut !
Voici un exemple de fichier yaml
qui permet de déployer une instance
PostgreSQL en version 17.0 :
$ cat ~/cluster.yaml
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgresql
spec:
imageName: ghcr.io/cloudnative-pg/postgresql:17.0
instances: 1
storage:
size: 20Gi
Appliquez ce fichier avec kubectl apply -f ~/cluster.yaml
et votre instance
PostgreSQL sera déployée. Il se passe beaucoup de choses derrière cette
phrase. Cela fera certainement l’objet d’un autre article de blog complet,
voire deux 😏. Pour le moment, contentons-nous d’apprécier ce qu’il se passe.
$ kubectl apply -f cluster.yaml
cluster.postgresql.cnpg.io/postgresql created
Quelques temps après, votre cluster PostgreSQL est up & running :
kubectl get cluster
NAME AGE INSTANCES READY STATUS PRIMARY
postgresql 4m49s 1 1 Cluster in healthy state postgresql-1
Déployer une instance secondaire
Une instance primaire est généralement accompagnée par une deuxième instance répliquée grâce au mécanisme interne de PostgreSQL. C’est une architecture très courante dans les projets où est utilisé PostgreSQL.
L’opérateur CloudNativePG vous permet de déployer un secondaire en modifiant uniquement le nombre
d’instances que vous souhaitez avoir. Il suffit donc juste de modifier 1
par 2
dans la définition yaml
.
[...]
instances: 2
[...]
À l’application de ce fichier, l’opérateur comprend la modification et va faire le nécessaire pour nous.
kubectl apply -f cluster.yaml
cluster.postgresql.cnpg.io/postgresql configured
Nous avons alors un cluster PostgreSQL avec deux instances. Par défaut, la seconde instance
est configurée pour fonctionner en réplication asynchrone. Le primaire correspond au
Pod
postgresql-1
comme l’indique la colonne PRIMARY
.
kubectl get cluster
NAME AGE INSTANCES READY STATUS PRIMARY
postgresql 7m46s 2 2 Cluster in healthy state postgresql-1
Bien évidemment, cette instance a pu être déployée aussi vite car l’instance ne contenait aucune donnée. Dans un cas réel, les données devront être récupérées depuis le primaire et copiées pour le secondaire.
Perte de l’instance primaire
Nos deux instances fonctionnent bien jusqu’au jour où l’instance primaire connaît un problème. Véritable cauchemar du DBA, qui, malgré les différentes protections et outils mis en place, ne veut pas vivre cette situation. Est-ce que l’opérateur CloudNativePG permet au DBA de dormir un peu plus sur ces deux oreilles ?
C’est ce que nous allons voir en détruisant l’instance primaire. Attention, vous êtes ici en présence de professionels, ne reproduisez pas cela à la maison 😂!
kubectl delete pod postgresql-1
pod "postgresql-1" deleted
Automatiquement, l’opérateur a promu l’instance postgresql-2
comme nouveau primaire :
kubectl get cluster
NAME AGE INSTANCES READY STATUS PRIMARY
postgresql 44h 2 2 Cluster in healthy state postgresql-2
Et en parallèle a recréé l’instance postgresql-1
:
kubectl get pod
NAME READY STATUS RESTARTS AGE
postgresql-1 1/1 Running 0 3s
postgresql-2 1/1 Running 0 44h
L’opérateur a eu l’information que le primaire connaissait un problème, notamment
via le système de Probes
. Il a décidé de promouvoir le second en primaire. Un
nouveau Pod
a été recréé pour remplacer l’ancien et a pu rejoindre le cluster
PostgreSQL existant. La bascule s’est donc faite automatiquement. Par un système
de labels
, les Services
qui permettent d’accéder aux instances ont été mis à
jour automatiquement et redirigent les connexions vers votre instance .
Cette dernière partie est trop obscure pour vous ? Ne vous en faites pas d’autres articles sont prévus pour expliquer tout cela.
Conclusion
Nous venons de voir comment l’opérateur CloudNativePG nous permet de déployer rapidement une instance PostgreSQL dans un cluster Kubernetes. La mise en place d’un secondaire se fait très facilement et lorsqu’un problème survient sur le primaire, une bascule automatique est initiée. Effet waouh garanti !
L’opérateur CloudNativePG nous permet d’envisager sereinement le déploiement de PostgreSQL dans Kubernetes. Au delà de cet effet et de son côté magique, de nombreux mécanismes de PostgreSQL, de CloudNativePG et de Kubernetes sont mis en place. Leur connaissance est essentielle et c’est bien le but de cette série d’articles.
Des questions, des commentaires ? Écrivez-nous !