Миграция с Bitnami на CloudNative-PG в Kubernetes
Многие инженеры и платформенные команды в течение долгого времени использовали популярные Helm-чарты от Bitnami для разворачивания PostgreSQL в кластерах Kubernetes. Однако перенос коммерчески готовых чартов и готовых контейнерных образов Bitnami в платную подписку заставляет искать открытые и зрелые альтернативы. Наиболее сильным решением в экосистеме стал оператор CloudNative-PG (CNPG), принятый в статус инкубации Cloud Native Computing Foundation (CNCF).
Оператор полностью берет на себя управление жизненным циклом PostgreSQL — от декларативного создания баз данных и управления ролями пользователей до автоматического переключения при сбоях (high availability) и репликации. Одно из его ключевых преимуществ — встроенная возможность прозрачного импорта данных из существующих инстансов СУБД, что делает переход с инфраструктуры Bitnami предсказуемым процедурным шагом.
В этом материале разберем пошаговый процесс установки оператора CloudNative-PG, составления базовых манифестов кластера, настройки пула соединений через PgBouncer, организации автоматического импорта базы данных и итоговой проверки целостности данных.
Шаг 1. Подготовка и установка оператора CloudNative-PG
Первым шагом необходимо установить сам оператор в кластер Kubernetes. Оператор регистрирует пользовательские ресурсы (Custom Resource Definitions, CRD), такие как Cluster, Pooler и PodMonitor, позволяющие управлять базой данных декларативным путем.
Установка выполняется одной командой через официальный манифест релиза:
kubectl apply --server-side -f \
https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.27/releases/cnpg-1.27.0.yaml
Обратите внимание на флаг --server-side: манифест оператора содержит объёмные схемы CRD. Использование серверной валидации предотвращает ошибки превышения лимита размера аннотаций (kubectl.kubernetes.io/last-applied-configuration), которые часто возникают в утилитах непрерывной доставки (ArgoCD или FluxCD).
Документация и релизные сборки оператора доступны на официальном сайте CloudNative-PG и в репозитории проекта на GitHub.
Шаг 2. Описание декларативного манифеста кластера и импорта данных
Служба CloudNative-PG создает отказоустойчивую конфигурацию из трёх узлов (один основной узел чтения-записи и два узла потоковой репликации в режиме ожидания), а также автоматически берет на себя выкачивание данных из внешнего источника.
Ниже приведен готовый манифест, состоящий из трех связанных ресурсов:
Cluster— описание целевого кластера PostgreSQL 17, ролей, хранилища и параметров подключения к старой базе Bitnami.Pooler— пулер соединений на базе PgBouncer для балансировки нагрузки и предотвращения шторма подключений.PodMonitor— конфигурация сбора метрик для системы мониторинга Prometheus.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgres
spec:
instances: 3
imageName: ghcr.io/cloudnative-pg/postgresql:17.5
managed:
roles:
- name: test
ensure: present
externalClusters:
- name: source-db
connectionParameters:
host: test-postgresql-ha-pgpool.test.svc.cluster.local
user: postgres
sslmode: disable
dbname: test
password:
name: test-postgresql
key: PASSWORD
bootstrap:
initdb:
database: test
owner: test
import:
type: microservice
databases:
- test
source:
externalCluster: source-db
enableSuperuserAccess: true
storage:
size: 8Gi
storageClass: gp3
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 1000m
memory: 1Gi
---
apiVersion: postgresql.cnpg.io/v1
kind: Pooler
metadata:
name: pooler-postgres
spec:
cluster:
name: postgres
instances: 2
pgbouncer:
poolMode: session
type: rw
---
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: postgres
labels:
cnpg.io/cluster: postgres
release: kube-prometheus-stack
spec:
selector:
matchLabels:
cnpg.io/cluster: postgres
cnpg.io/podRole: instance
podMetricsEndpoints:
- port: metrics
Разберем ключевые блоки этого манифеста:
externalClusters: регистрирует внешний источник (существующий сервис PostgreSQL Bitnami). Ссылка на пароль указывается через секрет Kubernetestest-postgresql, где хранится ключPASSWORD.bootstrap.initdb.import: дает команду оператору автоматизировать инициализацию: выкачать структуру и данные указанной базы (test) с внешнего кластера при развертывании первого пода. Режимtype: microserviceпредназначен для переноса одной конкретной базы данных.Pooler: поднимает два реплицированных пода PgBouncer с режимом пулаsession, направляющих трафик на лидирующий под кластера (type: rw).PodMonitor: настраивает Prometheus на автоматическое считывание встроенных метрик с портаmetrics.
Шаг 3. Запуск и отслеживание статуса миграции
Сохраните приведенный YAML-код в файл migration.yaml и примените его в нужном пространстве имен кластера:
kubectl apply -f migration.yaml
Отслеживать статус создания подов кластера и процесс репликации можно с помощью консольной утилиты kubectl:
kubectl get cluster postgres -w
Оператор поочередно создаст первичный узел postgres-1, инициирует копирование данных через pg_dump/pg_restore по внутреннему DNS Kubernetes (test-postgresql-ha-pgpool.test.svc.cluster.local), после чего поднимет реплики postgres-2 и postgres-3 и переведет их в режим потоковой синхронизации.
Шаг 4. Проверка корректности импорта данных
После того как статус кластера станет Cluster in healthy state, необходимо удостовериться, что таблицы и записи перенесены в полном объёме.
Для подключения к сервису PgBouncer узнаем имя сгенерированного секрета с административными доступом. По умолчанию CloudNative-PG сохраняет пароль суперпользователя в секрет <cluster-name>-superuser:
PGPASSWORD=$(kubectl get secret postgres-superuser --template={{.data.password}} | base64 -d)
Запустим временный под с клиентом psql для выполнения тестового запроса и получения списка таблиц:
kubectl run psql-client --rm -it --image=postgres --command -- \
psql "postgresql://postgres:${PGPASSWORD}@pooler-postgres:5432/test" -c "\dt"
Если в выводе команды отобразятся все пользовательские таблицы из старой базы Bitnami, миграция первичного снимка данных завершена успешно.
Меры предосторожности и продуктовый переключатель
Перед финальным переключением пользовательского трафика на новую базу выполните следующие шаги:
- Метки для Prometheus: Убедитесь, что метка
release: kube-prometheus-stackв ресурсеPodMonitorсовпадает с настройками вашего оператора мониторинга, иначе графики работы базы не появятся в Grafana. - Безопасность секретов: При указании внешнего источника CloudNative-PG требует строгой структуры ключей внутри
Secret(значенияusernameиpassword). Хранение паролей в чистом виде в репозитории недопустимо — используйте инструменты вроде Sealed Secrets или Vault. - Технологическое окно: Поскольку импорт базы создаёт статический снимок данных на момент старта инициализации, перед переключением сервисов переведите исходную приложение-клиент в режим обслуживания (maintenance mode) или остановите запись в старую СУБД Bitnami, чтобы исключить расхождение данных.
После проверки останется перенаправить строки подключения сервисов на новый внутренний сервис pooler-postgres:5432 и остановить старый Helm-релиз Bitnami.

