Развертывание PostgreSQL в Kubernetes: StatefulSet, хранилище и отказоустойчивость | AdminWiki

Развертывание PostgreSQL в Kubernetes: StatefulSet, хранилище и отказоустойчивость

25 августа 2026 8 мин. чтения
Содержание статьи

Введение: зачем запускать PostgreSQL в Kubernetes?

PostgreSQL - объектно-реляционная СУБД с открытым исходным кодом, которая развивается более 35 лет. За это время она получила репутацию надежной, функциональной и производительной системы. Kubernetes стал стандартом оркестрации контейнеров, и запрос на запуск баз данных внутри кластера растет: команды хотят единый способ управления инфраструктурой, автоматическое восстановление и предсказуемое масштабирование.

Запуск PostgreSQL в Kubernetes решает три задачи: стабильное хранилище данных через PersistentVolume, управление состоянием через StatefulSet и отказоустойчивость через репликацию и резервное копирование. Но stateful-приложения в оркестрации требуют иного подхода, чем stateless-сервисы. Ошибка с хранилищем или контроллером приводит к потере данных.

В этой статье разберем практический путь: от планирования архитектуры до настройки мониторинга. Вы получите готовые манифесты, команды и рекомендации, проверенные в production-средах. Материал рассчитан на DevOps-инженеров и системных администраторов, которые хотят запустить PostgreSQL в Kubernetes без типичных ошибок.

Если вы только начинаете работать со stateful-нагрузками, рекомендую сначала изучить полное руководство по StatefulSet с примерами для PostgreSQL и MySQL. Оно закрывает базовые вопросы по PVC, обновлению и удалению подов без потери данных.

Планирование развертывания: требования и архитектура

До создания манифестов определите архитектуру. Типовая production-схема для PostgreSQL в Kubernetes включает: StatefulSet с одним primary и несколькими replicas, headless service для стабильных сетевых имен подов, ClusterIP service для доступа приложений, PersistentVolumeClaims для данных каждого экземпляра.

Ключевое решение на этом этапе - будете ли вы использовать оператор или настраивать всё вручную. Операторы вроде CloudNativePG или Patroni автоматизируют failover, бэкапы и обновления. Ручная настройка дает полный контроль, но требует больше усилий. Для старта и понимания механик ручной подход полезен, для production-среды чаще выбирают оператор. Сравнение операторов для баз данных в Kubernetes с критериями выбора собрано в этом материале.

Выбор версии PostgreSQL и образа контейнера

Используйте официальный образ postgres или образы Bitnami. Официальный образ поддерживается сообществом PostgreSQL и обновляется оперативно. Bitnami-образы удобны встроенными настройками безопасности и совместимостью с Helm-чартами.

Следите за жизненным циклом версий. PostgreSQL 14 перестанет получать исправления 12 ноября 2026 года. Если вы работаете на этой версии в production, запланируйте обновление до PostgreSQL 16 или 17. Для новых развертываний выбирайте актуальную стабильную версию. Проверить даты окончания поддержки можно на официальном сайте PostgreSQL.

Определение ресурсов и лимитов

Неправильные requests и limits - частая причина нестабильной работы PostgreSQL. Память критична: параметр shared_buffers по умолчанию составляет 128MB, для production обычно выделяют 25% от доступной памяти пода. Если лимит памяти меньше, чем требуется shared_buffers и рабочим процессам, под получит OOMKilled.

Для стартовой конфигурации задайте requests на уровне ожидаемой средней нагрузки, limits - с запасом 20-30%. Пример для среднего production: requests 2 CPU и 4Gi памяти, limits 4 CPU и 8Gi памяти. Нагрузочное тестирование поможет уточнить цифры под ваш профиль запросов.

Настройка хранилища: PersistentVolume и StorageClass

Данные PostgreSQL должны жить на PersistentVolume. Если под удалится или переедет на другой узел, данные останутся. Для баз данных критичны три параметра хранилища: IOPS, latency и возможность расширения тома.

Типы хранилищ для Kubernetes:

  • Локальные - быстрые, но привязаны к узлу. Если узел недоступен, под не переедет.
  • Сетевые - NFS, Ceph/RBD. Медленнее локальных, но доступны с любого узла.
  • Облачные - AWS EBS, Google Persistent Disk, Azure Disk. Хороший баланс скорости и доступности.

Для production выбирайте облачные или Ceph-хранилища с CSI-драйвером. Локальные тома подходят для тестовых сред, где допустим простой. Подробнее про оркестрацию хранилища и настройку CSI-драйверов читайте в руководстве по проектированию production-ready кластеров.

Выбор StorageClass для production

StorageClass определяет, как Kubernetes выделяет PersistentVolume. Для PostgreSQL важны: volumeBindingMode: WaitForFirstConsumer (том создается рядом с подом), поддержка расширения (allowVolumeExpansion: true), подходящие параметры производительности.

Пример StorageClass для облачного хранилища с высокими IOPS:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: postgres-fast
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iops: "3000"
  throughput: "125"
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer

Создание PersistentVolumeClaim для PostgreSQL

В StatefulSet PVC создается через volumeClaimTemplates. Отдельный PVC для каждого пода гарантирует изоляцию данных. Пример шаблона:

volumeClaimTemplates:
- metadata:
    name: data
  spec:
    accessModes: ["ReadWriteOnce"]
    storageClassName: postgres-fast
    resources:
      requests:
        storage: 50Gi

Размер тома планируйте с запасом под рост базы и WAL-файлы. Для production 100Gi - разумный минимум.

Развертывание PostgreSQL с помощью StatefulSet

StatefulSet - правильный контроллер для PostgreSQL. Он обеспечивает стабильные имена подов (postgres-0, postgres-1), упорядоченное развертывание и стабильное хранилище для каждого экземпляра. Deployment не подходит: он создает поды со случайными именами и не гарантирует привязку PVC к конкретному экземпляру.

Создание StatefulSet: пошаговый манифест

Полный манифест StatefulSet для PostgreSQL:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres-headless
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:16
        ports:
        - containerPort: 5432
        env:
        - name: POSTGRES_DB
          value: myapp
        - name: POSTGRES_USER
          valueFrom:
            secretKeyRef:
              name: postgres-secret
              key: username
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: postgres-secret
              key: password
        volumeMounts:
        - name: data
          mountPath: /var/lib/postgresql/data
        resources:
          requests:
            cpu: "2"
            memory: 4Gi
          limits:
            cpu: "4"
            memory: 8Gi
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: postgres-fast
      resources:
        requests:
          storage: 100Gi

Ключевые параметры: serviceName указывает на headless service, volumeClaimTemplates создает отдельный PVC для каждого пода, секреты хранят учетные данные вне манифеста.

Настройка сервисов для доступа к PostgreSQL

Headless service обеспечивает стабильные DNS-имена подов. Это нужно для репликации, когда standby обращается к primary по имени postgres-0.postgres-headless. Манифест:

apiVersion: v1
kind: Service
metadata:
  name: postgres-headless
spec:
  clusterIP: None
  selector:
    app: postgres
  ports:
  - port: 5432
    targetPort: 5432

Для доступа приложений создайте обычный ClusterIP service:

apiVersion: v1
kind: Service
metadata:
  name: postgres
spec:
  selector:
    app: postgres
  ports:
  - port: 5432
    targetPort: 5432

Приложения подключаются к postgres:5432, а внутренняя репликация использует headless service.

Настройка репликации и высокая доступность

Один экземпляр PostgreSQL - точка отказа. Для production нужна репликация. Есть два подхода: встроенная потоковая репликация primary-standby и использование Patroni для автоматического failover.

Потоковая репликация проще в настройке, но при сбое primary требуется ручное переключение. Patroni автоматизирует выбор нового primary и управление конфигурацией, но требует развертывания etcd или Consul. Для большинства production-сред Patroni - оправданный выбор.

Потоковая репликация: настройка primary и standby

На primary в postgresql.conf задайте:

wal_level = replica
max_wal_senders = 10
hot_standby = on

На standby создайте файл recovery.conf (для PostgreSQL 12+ используйте standby.signal и параметры в postgresql.conf):

primary_conninfo = 'host=postgres-0.postgres-headless port=5432 user=replicator password=secret'
restore_command = 'cp /wal_archive/%f %p'

Для репликации создайте отдельного пользователя с правами REPLICATION.

Использование Patroni для автоматического failover

Patroni - это шаблон для управления PostgreSQL-кластерами с автоматическим failover. Архитектура: Patroni-агент в каждом поде, распределенное хранилище конфигурации (etcd или Consul), REST API для управления.

Преимущества Patroni: автоматический выбор нового primary при сбое, переключение без ручного вмешательства, централизованное управление конфигурацией. Недостаток - дополнительная сложность: нужно развернуть и обслуживать etcd.

Для быстрого старта используйте готовые Helm-чарты Patroni. Они включают настройку etcd, инициализацию кластера и базовые проверки здоровья.

Резервное копирование и восстановление

Репликация защищает от сбоя узла, но не от ошибочного DROP TABLE или повреждения данных. Резервное копирование обязательно для любой production-базы.

Два типа бэкапов: логические (pg_dump) и физические (pg_basebackup, pgBackRest). Логические - это SQL-дампы, удобны для выборочного восстановления. Физические копируют файлы данных целиком, быстрее для больших баз. Для production рекомендуем pgBackRest: он поддерживает инкрементальные бэкапы, сжатие и проверку целостности.

Настройка pgBackRest в Kubernetes

pgBackRest работает как sidecar-контейнер рядом с PostgreSQL. Он выполняет бэкапы по расписанию и хранит их в отдельном репозитории - PersistentVolume или объектном хранилище S3.

Базовая конфигурация pgBackRest:

[global]
repo1-type=s3
repo1-path=/postgres-backup
repo1-s3-bucket=my-backups
repo1-s3-region=eu-west-1

[mycluster]
pg1-path=/var/lib/postgresql/data
pg1-user=postgres

Для регулярных бэкапов создайте CronJob в Kubernetes, который запускает pgbackrest backup --stanza=mycluster --type=full раз в сутки и --type=incr каждый час.

Восстановление из резервной копии

Процесс восстановления: остановите поды PostgreSQL, выполните pgbackrest restore на primary, перезапустите кластер. Для point-in-time recovery укажите целевое время или точку WAL. Регулярно тестируйте восстановление - бэкап, который не проверяли, не считается бэкапом.

Мониторинг и алертинг

Без мониторинга вы узнаете о проблемах от пользователей. Для PostgreSQL в Kubernetes стандартный стек - Prometheus, Grafana и postgres_exporter.

Настройка postgres_exporter и Prometheus

postgres_exporter собирает метрики из PostgreSQL и отдает их в формате Prometheus. Запустите его как sidecar-контейнер в том же поде, что и PostgreSQL:

- name: postgres-exporter
  image: prometheuscommunity/postgres-exporter:latest
  env:
  - name: DATA_SOURCE_NAME
    value: "postgresql://postgres:secret@localhost:5432/postgres?sslmode=disable"
  ports:
  - containerPort: 9187

Для сбора метрик Prometheus создайте ServiceMonitor, если используете Prometheus Operator. Он автоматически обнаружит exporter и начнет собирать метрики.

Создание дашбордов и алертов в Grafana

В Grafana используйте готовые дашборды с grafana.com - например, PostgreSQL Overview. Ключевые метрики для алертов: количество активных подключений, задержка репликации, использование дискового пространства, количество медленных запросов.

Настройте алерты на: использование диска выше 80%, задержку репликации более 30 секунд, количество подключений близко к max_connections. Алерты должны приходить в Slack, Telegram или почту.

Типичные ошибки и их устранение

Разберем ошибки, которые встречаются чаще всего при развертывании PostgreSQL в Kubernetes.

Ошибка: потеря данных из-за неправильного PVC

Симптом: удалили StatefulSet, пересоздали - данные пропали. Причина: PVC был создан отдельно, а не через volumeClaimTemplates, или политика удаления PVC настроена на автоматическое удаление.

Решение: всегда используйте volumeClaimTemplates в StatefulSet. PVC, созданные через шаблон, переживают удаление StatefulSet. Для дополнительной защиты настройте persistentVolumeReclaimPolicy: Retain в StorageClass.

Ошибка: недостаточные ресурсы для PostgreSQL

Симптомы: под перезапускается с OOMKilled, запросы выполняются медленно, репликация отстает. Причина: limits занижены, requests не соответствуют реальной нагрузке.

Решение: увеличьте лимиты памяти с учетом shared_buffers и рабочих процессов. Настройте мониторинг потребления ресурсов и корректируйте значения по факту. Для высоконагруженных баз выделите отдельный узел с гарантированными ресурсами.

Заключение: итоги и дальнейшие шаги

Развертывание PostgreSQL в Kubernetes - это последовательность шагов: выбор версии и образа, настройка StorageClass и PVC, создание StatefulSet с headless service, настройка репликации, резервного копирования и мониторинга. Каждый шаг важен: пропуск одного из них создает риск для данных.

Для упрощения управления рассмотрите операторы - CloudNativePG или Percona Operator. Они автоматизируют failover, бэкапы и обновления. Сравнение операторов с критериями выбора для production-сред собрано в отдельном материале.

Если вам нужна облачная инфраструктура для тестирования этих сценариев, Timeweb Cloud предоставляет Kubernetes, базы данных и хранилище с гибким изменением ресурсов. Для автоматизации рутинных задач с конфигурациями можно использовать AiTunnel - агрегатор API нейросетей, который помогает генерировать и проверять манифесты.

Дальнейшие шаги: настройте Patroni для автоматического failover, внедрите pgBackRest с тестированием восстановления, подключите алерты в Grafana. Эти меры переведут вашу базу из категории «работает» в категорию «работает надежно».

Поделиться:
Сохранить гайд? В закладки браузера