1️⃣ cluster.yaml

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: postgresql
  namespace: default
spec:
  imageName: ghcr.io/cloudnative-pg/postgresql:17.0

  # Nombre d'instances (1 primaire + 2 réplicas pour HA)
  instances: 3

  # Stockage persistant
  storage:
    size: 20Gi
    storageClass: nfs-client  # adapte selon ton environnement

  # Initialisation du cluster PostgreSQL
  bootstrap:
    initdb:
      database: appdb
      owner: appuser
      secret:
        name: postgresql-appuser-secret

  # Configuration PostgreSQL
  postgresql:
    parameters:
      max_connections: "200"
      shared_buffers: "256MB"
      work_mem: "16MB"
      maintenance_work_mem: "64MB"
      wal_level: "replica"
      archive_mode: "on"
      archive_timeout: "60s"

  # Stratégie de mise à jour
  primaryUpdateStrategy: unsupervised

  # Sauvegarde automatique vers S3/MinIO
  backup:
    barmanObjectStore:
      destinationPath: s3://postgresql-backup/
      s3Credentials:
        accessKeyId:
          name: s3-credentials
          key: ACCESS_KEY_ID
        secretAccessKey:
          name: s3-credentials
          key: ACCESS_SECRET_KEY
      wal:
        compression: gzip
    retentionPolicy: "14d"

  # Activation du monitoring Prometheus
  monitoring:
    enablePodMonitor: true

  # Ressources
  resources:
    requests:
      cpu: "250m"
      memory: "512Mi"
    limits:
      cpu: "1"
      memory: "1Gi"

2️⃣ secret-appuser.yaml

---
apiVersion: v1
kind: Secret
metadata:
  name: postgresql-appuser-secret
  namespace: default
type: kubernetes.io/basic-auth
stringData:
  username: appuser
  password: motdepassefort

3️⃣ secret-s3.yaml

---
apiVersion: v1
kind: Secret
metadata:
  name: s3-credentials
  namespace: default
type: Opaque
stringData:
  ACCESS_KEY_ID: ton-access-key
  ACCESS_SECRET_KEY: ta-secret-key

4️⃣ backup.yaml

---
apiVersion: postgresql.cnpg.io/v1
kind: Backup
metadata:
  name: postgresql-manual-backup
  namespace: default
spec:
  cluster:
    name: postgresql

5️⃣ scheduled-backup.yaml

---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: postgresql-restore
  namespace: default
spec:
  imageName: ghcr.io/cloudnative-pg/postgresql:17.0
  instances: 3
  storage:
    size: 20Gi
    storageClass: nfs-client
  bootstrap:
    recovery:
      source: postgresql

6️⃣ restore-cluster.yaml

---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: postgresql-restore
  namespace: default
spec:
  imageName: ghcr.io/cloudnative-pg/postgresql:17.0
  instances: 3
  storage:
    size: 20Gi
    storageClass: nfs-client
  bootstrap:
    recovery:
      source: postgresql

2️⃣Provoquer un failover manuel*

Option 1 : Switchover planifié (manuel propre)

kubectl patch cluster postgresql -n default \
  --type merge \
  -p '{"spec":{"manualSwitchover":{"target":"postgresql-1","scheduledAt":"2025-10-28T14:00:00Z"}}}'

Option 2 : Failover forcé (rapide, test de panne)****

kubectl delete pod postgresql-0 -n default

Vérifie la connexion PostgreSQL :

kubectl exec -it postgresql-1 -n default -- psql -U appuser -d appdb -c "SELECT pg_is_in_recovery();"
kubectl describe cluster postgresql -n default | grep -A3 "Last Transition"
kubectl get events -n default --sort-by=.metadata.creationTimestamp | grep postgresql
kubectl patch cluster postgresql -n default \
--type merge  -p '{"spec":{"manualSwitchover":{"target":"postgresql-0","scheduledAt":"2025-10-28T14:10:00Z"}}}'
kubectl get pods -n default -l cnpg.io/cluster=postgresql -L role

Pour minio:*

kubectl patch cluster postgresql-lab -n test --type merge -p '{
  "spec": {
    "backup": {
      "barmanObjectStore": {
        "destinationPath": "s3://postgresnstest/",
        "endpointURL": "http://10.200.2.30:9000",
        "s3Credentials": {
          "accessKeyId": {"name": "minio-secret", "key": "MINIO_ACCESS_KEY"},
          "secretAccessKey": {"name": "minio-secret", "key": "MINIO_SECRET_KEY"}
        },
        "wal": {"compression": "gzip"}
      },
      "retentionPolicy": "1d"
    }
  }
}'

*** Test Postgres SQL

[root@prd-k8s-m01 lab_cluste_postgress]# kubectl exec -it svc/postgresql-lab-rw -n test -- bash

Defaulted container "postgres" out of: postgres, bootstrap-controller (init)
postgres@postgresql-lab-1:/$ psql -U postgres
psql (17.0 (Debian 17.0-1.pgdg110+1))
Type "help" for help.

postgres=# \l
                                                List of databases
   Name    |  Owner   | Encoding | Locale Provider | Collate | Ctype | Locale | ICU Rules |   Access privileges
-----------+----------+----------+-----------------+---------+-------+--------+-----------+-----------------------
 appdb     | appuser  | UTF8     | libc            | C       | C     |        |           |
 postgres  | postgres | UTF8     | libc            | C       | C     |        |           |
 template0 | postgres | UTF8     | libc            | C       | C     |        |           | =c/postgres          +
           |          |          |                 |         |       |        |           | postgres=CTc/postgres
 template1 | postgres | UTF8     | libc            | C       | C     |        |           | =c/postgres          +
           |          |          |                 |         |       |        |           | postgres=CTc/postgres
(4 rows)

postgres=# \l
                                                List of databases
   Name    |  Owner   | Encoding | Locale Provider | Collate | Ctype | Locale | ICU Rules |   Access privileges
-----------+----------+----------+-----------------+---------+-------+--------+-----------+-----------------------
 appdb     | appuser  | UTF8     | libc            | C       | C     |        |           |
 postgres  | postgres | UTF8     | libc            | C       | C     |        |           |
 template0 | postgres | UTF8     | libc            | C       | C     |        |           | =c/postgres          +
           |          |          |                 |         |       |        |           | postgres=CTc/postgres
 template1 | postgres | UTF8     | libc            | C       | C     |        |           | =c/postgres          +
           |          |          |                 |         |       |        |           | postgres=CTc/postgres
(4 rows)

postgres=# \c labdb
connection to server on socket "/controller/run/.s.PGSQL.5432" failed: FATAL:  database "labdb" does not exist
Previous connection kept
postgres=# \c appdb
You are now connected to database "appdb" as user "postgres".
appdb=# CREATE TABLE sauvegarde_test (
    id SERIAL PRIMARY KEY,
    nom VARCHAR(100),
    date_creation TIMESTAMP DEFAULT NOW()
);

INSERT INTO sauvegarde_test (nom) VALUES ('Sauvegarde test 1'), ('Sauvegarde test 2');

SELECT * FROM sauvegarde_test;
CREATE TABLE
INSERT 0 2
 id |        nom        |       date_creation
----+-------------------+----------------------------
  1 | Sauvegarde test 1 | 2025-10-29 15:26:47.567904
  2 | Sauvegarde test 2 | 2025-10-29 15:26:47.567904
(2 rows)

appdb=# INSERT INTO sauvegarde_test (nom) VALUES ('Sauvegarde test 4'), ('Sauvegarde test 3');
INSERT 0 2
appdb=# CREATE TABLE sauvegarde_test (
    id SERIAL PRIMARY KEY,
    nom VARCHAR(100),
    date_creation TIMESTAMP DEFAULT NOW()
);

INSERT INTO sauvegarde_test (nom) VALUES ('Sauvegarde test 1'), ('Sauvegarde test 2');

SELECT * FROM sauvegarde_test;^C
appdb=# SELECT * FROM sauvegarde_test;
 id |        nom        |       date_creation
----+-------------------+----------------------------
  1 | Sauvegarde test 1 | 2025-10-29 15:26:47.567904
  2 | Sauvegarde test 2 | 2025-10-29 15:26:47.567904
  3 | Sauvegarde test 4 | 2025-10-29 15:27:06.816419
  4 | Sauvegarde test 3 | 2025-10-29 15:27:06.816419
(4 rows)

appdb=# ex
Retour à la liste