Введение: зачем запускать 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. Эти меры переведут вашу базу из категории «работает» в категорию «работает надежно».