Base de datos con CloudNativePG¶
Con postgres.mode: cnpg el chart crea, junto a kubelatch, un cluster de Postgres que lleva el operador CloudNativePG. Nadie escribe ni copia una contraseña: kubelatch lee la conexión del Secret que genera el operador.
Los comandos usan $MGMT_KUBECONFIG y $KUBELATCH_VERSION, como en Instalar. Todos los values postgres.cnpg, con su valor por defecto, están en Values de Helm.
Qué crea el chart¶
| Objeto | Qué es |
|---|---|
Cluster kubelatch-db |
Postgres 17 (postgres.cnpg.imageName), postgres.cnpg.instances instancias, base de datos kubelatch cuyo dueño es kubelatch. Lleva helm.sh/resource-policy: keep: helm uninstall lo deja en su sitio, con sus volúmenes. |
Secret kubelatch-db-app |
Lo crea el operador. kubelatch toma DATABASE_URL de su clave uri, que apunta al servicio de lectura y escritura kubelatch-db-rw. |
Secret kubelatch-db-ca |
Lo crea el operador: su CA. kubelatch monta solo ca.crt, de solo lectura, para comprobar el certificado del servidor (TLS hacia la base de datos). |
NetworkPolicy kubelatch-db |
El puerto 5432 solo desde los pods de kubelatch, desde las otras instancias y desde los pods del operador: los que llevan la etiqueta app.kubernetes.io/name: cloudnative-pg en postgres.cnpg.operatorNamespace (cnpg-system por defecto). El puerto 8000, el de estado del instance manager, desde las instancias y el operador. Como la de kubelatch, necesita un CNI que aplique NetworkPolicy. |
ObjectStore kubelatch-db y ScheduledBackup kubelatch-db-daily |
Solo con las copias activadas (Copias de seguridad). Se conservan como el Cluster. |
Instalar el operador¶
El chart no instala operadores: CloudNativePG va antes, una vez por cluster. kubelatch se prueba con CloudNativePG 1.30.1; las copias necesitan la 1.26 o superior.
kubectl --kubeconfig "$MGMT_KUBECONFIG" apply --server-side -f \
https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.30/releases/cnpg-1.30.1.yaml
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n cnpg-system rollout status deploy/cnpg-controller-manager
Su webhook de admisión responde unos segundos después del rollout: dale un momento antes del helm install.
Sin el operador, helm install se para con postgres.mode=cnpg needs the CloudNativePG operator y no crea nada. Si el tuyo vive en otro namespace, ponlo en postgres.cnpg.operatorNamespace para que la NetworkPolicy lo deje pasar. Sus pods deben llevar la etiqueta app.kubernetes.io/name: cloudnative-pg: la ponen tanto el manifiesto del operador como su chart de Helm.
Instalar kubelatch con la base de datos¶
Sigue Instalar con dos cambios:
-
En
kubelatch-secrets, solo la clave de cifrado (o ningún Secret, consecrets.existingSecret: ""ysecrets.generateEncryptionKey: true). El chart toma siempreDATABASE_URLdekubelatch-db-app: una enkubelatch-secretsse ignora, y una ensecrets.env(consecrets.create) detiene la instalación.kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch create secret generic kubelatch-secrets \ --from-literal=KUBELATCH_ENCRYPTION_KEY="$(head -c32 /dev/urandom | base64)" -
En
values.yaml:postgres: mode: cnpg cnpg: storage: size: 10Gi
El operador crea la base de datos mientras kubelatch arranca; el pod de kubelatch espera a los Secrets del operador y se reinicia hasta que puede conectar. Espera a los dos:
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch wait --for=condition=Ready clusters.postgresql.cnpg.io/kubelatch-db --timeout=5m
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch rollout status deploy/kubelatch --timeout=5m
TLS hacia la base de datos¶
kubelatch conecta siempre con TLS y comprueba el certificado del servidor y el nombre del host (PGSSLMODE=verify-full) contra la CA del operador. Del Secret kubelatch-db-ca el chart monta solo ca.crt, nunca la clave privada de la CA, en /etc/kubelatch/db-ca/ca.crt (PGSSLROOTCERT).
CloudNativePG renueva su CA por su cuenta (por defecto cada 90 días). kubelatch vuelve a leer el fichero cada vez que cambia, así que las conexiones nuevas comprueban contra la CA renovada sin reiniciar. Si el fichero no se puede leer, las conexiones nuevas fallan: kubelatch nunca recurre a una conexión sin comprobar.
Dimensionado¶
| Value | Por defecto | Guía |
|---|---|---|
postgres.cnpg.instances |
1 |
Una para evaluación y equipos pequeños; tres para alta disponibilidad (De una instancia a tres). |
postgres.cnpg.storage.size |
10Gi |
La auditoría ocupa casi todo: ver Auditoría y retención. CloudNativePG puede ampliar el volumen después si la StorageClass lo permite. |
postgres.cnpg.storage.storageClass |
la del cluster | Una clase con discos replicados o con snapshots. |
postgres.cnpg.resources |
ninguno | Por ejemplo {requests: {cpu: 250m, memory: 512Mi}, limits: {memory: 1Gi}}. La carga de kubelatch es pequeña: una escritura por petición a través del proxy. |
postgres.cnpg.affinity |
la del operador | El bloque affinity de CloudNativePG, por ejemplo {topologyKey: topology.kubernetes.io/zone} para repartir las instancias entre zonas. |
idle_in_transaction_session_timeout se queda en 0 (lo de Postgres por defecto), como necesita el reconciliador de kubelatch (Ajustes de Postgres).
Copias de seguridad¶
Las copias están desactivadas por defecto, y las notas de la instalación lo recuerdan. Activadas, el chart configura el archivado continuo del WAL y una copia base diaria a un almacenamiento de objetos (S3, GCS o Azure Blob) con el Barman Cloud Plugin, la vía soportada de CloudNativePG. El plugin necesita cert-manager y va en el namespace del operador. El test de instalación no cubre las copias: valídalas en tu cluster.
kubectl --kubeconfig "$MGMT_KUBECONFIG" apply -f \
https://github.com/cloudnative-pg/plugin-barman-cloud/releases/download/v0.15.0/manifest.yaml
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n cnpg-system rollout status deploy/barman-cloud
Pon las credenciales del almacenamiento en un Secret (S3 en este ejemplo) y activa las copias:
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch create secret generic kubelatch-backup \
--from-literal=ACCESS_KEY_ID=<id-de-la-clave> --from-literal=ACCESS_SECRET_KEY=<secreto>
postgres:
mode: cnpg
cnpg:
backup:
enabled: true
destinationPath: s3://<bucket>/kubelatch
credentials:
s3Credentials:
accessKeyId: {name: kubelatch-backup, key: ACCESS_KEY_ID}
secretAccessKey: {name: kubelatch-backup, key: ACCESS_SECRET_KEY}
retentionPolicy: 30d
Para GCS y Azure, credentials lleva googleCredentials o azureCredentials, como los documenta el plugin. schedule (a diario a las 03:00 por defecto) usa la sintaxis cron de CloudNativePG, con segundos.
Comprueba que el WAL se archiva y que las copias terminan:
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch get clusters.postgresql.cnpg.io kubelatch-db -o jsonpath='{.status.conditions[?(@.type=="ContinuousArchiving")].status}'
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch get backups.postgresql.cnpg.io
La clave no está en la copia
Una copia de Postgres sin KUBELATCH_ENCRYPTION_KEY no permite usar los tokens de los clusters. Guarda la clave en tu gestor de secretos, aparte del almacenamiento de objetos.
El ObjectStore kubelatch-db y el ScheduledBackup kubelatch-db-daily llevan helm.sh/resource-policy: keep, como el Cluster. Se quedan tras helm uninstall, al dejar postgres.mode: cnpg y al desactivar las copias. Un Cluster que se queda sigue archivando el WAL en ese almacenamiento: sin él, el archivado fallaría y pg_wal llenaría el volumen. Para parar las copias del todo, sigue Desinstalar y los datos.
Restaurar desde una copia¶
Una restauración crea un Cluster nuevo a partir del almacenamiento de objetos. El Cluster del chart se llama siempre kubelatch-db, así que el dañado va primero.
-
Comprueba desde qué vas a restaurar. Al menos una copia debe estar
completed, y el archivado del WAL debe decirTrue:kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch get backups.postgresql.cnpg.io kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch get clusters.postgresql.cnpg.io kubelatch-db -o jsonpath='{.status.conditions[?(@.type=="ContinuousArchiving")].status}'Si la base de datos todavía se puede leer, haz además un volcado: el paso siguiente borra sus volúmenes para siempre.
primary=$(kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch get clusters.postgresql.cnpg.io kubelatch-db -o jsonpath='{.status.currentPrimary}') kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch exec "$primary" -c postgres -- pg_dump -Fc kubelatch > kubelatch.dump -
Para kubelatch y borra el
Clusterdañado (sus volúmenes se van con él):kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch scale deploy/kubelatch --replicas=0 kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch delete clusters.postgresql.cnpg.io kubelatch-db -
Añade la recuperación a tus values. El
Clusternuevo lee las copias viejas (serverName: kubelatch-db) y archiva en una carpeta nueva (backup.serverName). Cada restauración usa una carpeta nueva (kubelatch-db-2, luegokubelatch-db-3…), porque CloudNativePG se niega a archivar en una carpeta que ya tiene un archivo:postgres: mode: cnpg cnpg: bootstrap: recovery: source: origin # A un momento concreto: recoveryTarget: {targetTime: "2026-09-26 10:00:00+00"} externalClusters: - name: origin plugin: name: barman-cloud.cloudnative-pg.io parameters: barmanObjectName: kubelatch-db serverName: kubelatch-db backup: enabled: true serverName: kubelatch-db-2 # destinationPath y credentials como antespostgres.cnpg.bootstraplleva exactamente un método:initdb,recoveryopg_basebackup. Deja fueradatabase,ownerysecret: el chart ponekubelatchen los dos primeros y rechaza cualquier otro valor (Solución de problemas).initdbconimportsirve también para llevar un Postgres existente a CloudNativePG: apuntapostgres.cnpg.externalClustersa tu base de datos actual y sigue la documentación de importación de CloudNativePG. -
Aplícalo y espera:
helm --kubeconfig "$MGMT_KUBECONFIG" upgrade kubelatch oci://ghcr.io/picaportelabs/charts/kubelatch \ --version "$KUBELATCH_VERSION" -n kubelatch -f values.yaml kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch wait --for=condition=Ready clusters.postgresql.cnpg.io/kubelatch-db --timeout=30m kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch rollout status deploy/kubelatchEl upgrade devuelve
replicasal valor del chart. El operador escribe una contraseña nueva enkubelatch-db-app: si los pods arrancaron antes, reinícialos conkubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch rollout restart deploy/kubelatch. -
Haz enseguida una copia base. Hasta entonces la carpeta nueva solo tiene WAL y no se puede restaurar desde ella, y el
ScheduledBackupdiario solo hizo su copia inmediata cuando se creó:kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch create -f - <<'EOF' apiVersion: postgresql.cnpg.io/v1 kind: Backup metadata: generateName: kubelatch-db-after-restore- spec: cluster: name: kubelatch-db method: plugin pluginConfiguration: name: barman-cloud.cloudnative-pg.io EOF kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch get backups.postgresql.cnpg.io -
Deja
bootstrapyexternalClustersen tus values: CloudNativePG solo los lee al crear elCluster. La próxima vez, restaura desdekubelatch-db-2y archiva enkubelatch-db-3.
Prueba el procedimiento antes de necesitarlo, en otro namespace u otro cluster, con la misma clave de cifrado y un backup.serverName desechable (u otro bucket o ruta). Una restauración de prueba nunca debe archivar en una carpeta que producción usa o va a usar después: CloudNativePG se niega a archivar en una carpeta que ya tiene un archivo, así que el Cluster que llegue segundo no consigue archivar el WAL y su pg_wal llena el volumen.
Actualizar Postgres¶
- Versión menor (17.5 → 17.6): cambia
postgres.cnpg.imageNamea la etiqueta nueva y ejecutahelm upgrade. El operador reinicia las instancias una a una; con tres, mueve antes el primario (unos segundos sin escrituras). La etiqueta móvil por defecto (17-standard-trixie) no reinicia nada por su cuenta: fija una versión menor (17.6-standard-trixie) para decidir cuándo. - Versión mayor (17 → 18): cambia
imageNamea una imagen 18 y ejecutahelm upgrade. CloudNativePG (1.26 o superior) actualiza en el sitio conpg_upgrade: para las instancias, así que kubelatch responde503hasta que termina. Haz antes una copia; no puedes volver a la 17 sin restaurarla.
De una instancia a tres¶
postgres:
mode: cnpg
cnpg:
instances: 3
helm upgrade añade dos réplicas, clonadas del primario. Si el primario falla, el operador promueve una réplica y mueve a ella el servicio kubelatch-db-rw; kubelatch vuelve a conectar solo (las peticiones durante el cambio reciben 503). El operador crea también el PodDisruptionBudget de las instancias.
Desinstalar y los datos¶
helm uninstall deja en su sitio el Cluster kubelatch-db, sus volúmenes y sus Secrets, y también la clave de cifrado generada. Con las copias activadas se quedan además el ObjectStore y el ScheduledBackup, que siguen archivando el WAL y haciendo la copia diaria. Instalar de nuevo con el mismo nombre de release y el mismo namespace los recupera, con todos los datos.
El keep de Helm solo protege frente a helm uninstall. Las herramientas GitOps aplican los manifiestos por su cuenta, así que el chart pone además en estos objetos el argocd.argoproj.io/sync-options: Delete=false,Prune=false de Argo CD. Con otra herramienta, comprueba que nunca poda el Cluster ni el Secret de la clave.
La NetworkPolicy kubelatch-db no se conserva: tras helm uninstall, cualquier pod puede llegar al puerto de la base de datos (sigue pidiendo la contraseña) hasta que instales de nuevo o borres el Cluster.
Para borrar la base de datos del todo, después de exportar lo que necesites:
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch delete clusters.postgresql.cnpg.io kubelatch-db
Con las copias activadas, páralas en este orden, para que no empiece ninguna copia base nueva y el archivado del WAL termine antes de que desaparezca la definición del almacenamiento de objetos:
-
Borra la copia diaria:
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch delete scheduledbackups.postgresql.cnpg.io kubelatch-db-daily -
Si conservas el
Cluster, ponpostgres.cnpg.backup.enabled: falsey ejecutahelm upgradecon los mismos values: el chart quita el plugin delClustery el archivado del WAL se para. Si no, borra elClustercomo arriba. -
Borra la definición del almacenamiento de objetos:
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch delete objectstores.barmancloud.cnpg.io kubelatch-db
Las copias que ya están en el almacenamiento de objetos se quedan allí hasta que las borres.