Сервис развивается: тестируем формат, собираем идеи, улучшаем сервис. Есть идеи?

Написать
Войти
Дайджесты
Иллюстрация к статье

Миграция с Bitnami на CloudNative-PG в Kubernetes

Практический разбор переноса PostgreSQL с коммерциализируемых Helm-чартов Bitnami на Kubernetes-оператор CloudNative-PG. Подробно разбираем установку оператора через серверные CRD, составление YAML-манифестов для HA-кластера, подключение PgBouncer и пошаговый импорт существующих данных из старой базы.

Миграция с 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 создает отказоустойчивую конфигурацию из трёх узлов (один основной узел чтения-записи и два узла потоковой репликации в режиме ожидания), а также автоматически берет на себя выкачивание данных из внешнего источника.

Ниже приведен готовый манифест, состоящий из трех связанных ресурсов:

  1. Cluster — описание целевого кластера PostgreSQL 17, ролей, хранилища и параметров подключения к старой базе Bitnami.
  2. Pooler — пулер соединений на базе PgBouncer для балансировки нагрузки и предотвращения шторма подключений.
  3. 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). Ссылка на пароль указывается через секрет Kubernetes test-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, миграция первичного снимка данных завершена успешно.


Меры предосторожности и продуктовый переключатель

Перед финальным переключением пользовательского трафика на новую базу выполните следующие шаги:

  1. Метки для Prometheus: Убедитесь, что метка release: kube-prometheus-stack в ресурсе PodMonitor совпадает с настройками вашего оператора мониторинга, иначе графики работы базы не появятся в Grafana.
  2. Безопасность секретов: При указании внешнего источника CloudNative-PG требует строгой структуры ключей внутри Secret (значения username и password). Хранение паролей в чистом виде в репозитории недопустимо — используйте инструменты вроде Sealed Secrets или Vault.
  3. Технологическое окно: Поскольку импорт базы создаёт статический снимок данных на момент старта инициализации, перед переключением сервисов переведите исходную приложение-клиент в режим обслуживания (maintenance mode) или остановите запись в старую СУБД Bitnami, чтобы исключить расхождение данных.

После проверки останется перенаправить строки подключения сервисов на новый внутренний сервис pooler-postgres:5432 и остановить старый Helm-релиз Bitnami.