CloudNativePG: продакшен-PostgreSQL в Kubernetes
Published: 2026-03-23
Раньше PostgreSQL в Kubernetes — это StatefulSet, ручной failover и самописные скрипты бэкапов. CloudNativePG (CNPG) — оператор, который декларативно управляет стриминговой репликацией, автоматическим failover, архивацией WAL, резервными копиями и point-in-time recovery. Весь кластер описывается одним CRD.
Установка оператора
yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cloudnative-pg
namespace: cnpg-system
spec:
chart:
spec:
chart: cloudnative-pg
version: "0.x"
sourceRef:
kind: HelmRepository
name: cnpg
namespace: flux-system
values:
monitoring:
podMonitorEnabled: true
grafanaDashboard:
create: true
namespace: monitoring
Определение кластера
yamlapiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pg-main
namespace: app
spec:
instances: 3
imageName: ghcr.io/cloudnative-pg/postgresql:16
primaryUpdateStrategy: unsupervised
storage:
size: 20Gi
storageClass: local-path
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 2Gi
postgresql:
parameters:
max_connections: "200"
shared_buffers: "256MB"
effective_cache_size: "768MB"
work_mem: "4MB"
wal_level: logical
pg_hba:
- host all all 10.0.0.0/8 scram-sha-256
bootstrap:
initdb:
database: myapp
owner: myapp
secret:
name: pg-main-app-secret
backup:
retentionPolicy: "30d"
barmanObjectStore:
destinationPath: s3://pg-backups/pg-main
endpointURL: https://storage.yandexcloud.net
s3Credentials:
accessKeyId:
name: pg-s3-secret
key: ACCESS_KEY_ID
secretAccessKey:
name: pg-s3-secret
key: SECRET_ACCESS_KEY
wal:
compression: gzip
data:
compression: gzip
monitoring:
enablePodMonitor: true
instances: 3 — это 1 primary + 2 реплики. CNPG управляет стриминговой репликацией автоматически. При падении primary наиболее актуальная реплика повышается до primary примерно за 30 секунд.
Расписание бэкапов
yamlapiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
name: pg-main-daily
namespace: app
spec:
schedule: "0 2 * * *"
cluster:
name: pg-main
backupOwnerReference: self
CNPG непрерывно отправляет WAL в S3, ежедневный бэкап служит базовым. Вместе они обеспечивают point-in-time recovery с точностью до секунды в пределах окна хранения.
Point-in-time recovery
yamlapiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pg-main-restored
namespace: app
spec:
instances: 1
bootstrap:
recovery:
source: pg-main
recoveryTarget:
targetTime: "2026-10-17 14:30:00"
externalClusters:
- name: pg-main
barmanObjectStore:
destinationPath: s3://pg-backups/pg-main
endpointURL: https://storage.yandexcloud.net
s3Credentials:
accessKeyId:
name: pg-s3-secret
key: ACCESS_KEY_ID
secretAccessKey:
name: pg-s3-secret
key: SECRET_ACCESS_KEY
Используйте другое имя кластера, чтобы не конфликтовать с production. CNPG воспроизводит WAL до targetTime.
Пул соединений через PgBouncer
yamlapiVersion: postgresql.cnpg.io/v1
kind: Pooler
metadata:
name: pg-main-pooler
namespace: app
spec:
cluster:
name: pg-main
instances: 2
type: rw
pgbouncer:
poolMode: transaction
parameters:
max_client_conn: "1000"
default_pool_size: "25"
type: rw направляет запросы на primary, type: ro — на реплики. Transaction pooling позволяет обслуживать 1000 клиентов при 25 backend-соединениях.
Подключение из приложения
CNPG создаёт сервисы для каждого кластера:
pg-main-rw— primary (read-write)pg-main-ro— реплики (read-only)pg-main-r— все экземпляры
postgresql://myapp:password@pg-main-rw.app.svc.cluster.local:5432/myapp
С PgBouncer:
postgresql://myapp:password@pg-main-pooler.app.svc.cluster.local:5432/myapp
Полезные команды
bash# Статус кластера
kubectl cnpg status pg-main -n app
# Список бэкапов
kubectl get backup -n app
# Ручной базовый бэкап
kubectl cnpg backup pg-main -n app
# Промоут реплики (для тестирования failover)
kubectl cnpg promote pg-main pg-main-2 -n app
# Архивация WAL
kubectl cnpg status pg-main -n app | grep -A5 "WAL Archiving"
# Гибернация (остановить поды, сохранить PVC)
kubectl cnpg hibernate pg-main -n app
Диагностика
Ошибки архивации WAL: проверьте учётные данные S3 и права на bucket. Ошибки видны в kubectl cnpg status.
Реплика отстаёт: проверьте pg_replication_slots на primary. Зависшие слоты блокируют очистку WAL и могут переполнить диск. Удаляются через pg_drop_replication_slot.
Failover не произошёл: CNPG требует кворума. При трёх экземплярах primary считается упавшим, если это подтверждают минимум две реплики.