Хостинг
VDS
Аренда серверов
Домены
Почта
SSL
Хранилище
Сайты
Обзоры
Регламенты
AI Studio
Kubernetes
Архив
Развёртывание PostgreSQL 18 с репликацией и автоматическим failover в Kubernetes

Развёртывание PostgreSQL 18 с репликацией и автоматическим failover в Kubernetes

Содержание

  1. Введение

  2. Требования

  3. Подготовка дисков

  4. Настройка Persistent Volumes

  5. Установка CloudNativePG оператора

  6. Создание кластера PostgreSQL

  7. Настройка паролей

  8. Внешний доступ

  9. Полезные команды


Введение

В данной инструкции описан процесс развёртывания высокодоступного кластера PostgreSQL 18 в Kubernetes с использованием оператора CloudNativePG.

Кластер состоит из трёх нод: одной главной (primary) и двух реплик (replica). При отказе главной ноды одна из реплик автоматически становится главной, обеспечивая непрерывность работы.


Требования

  1. Kubernetes-кластер с минимум 3 worker-нодами

  2. Дополнительный диск на каждой worker-ноде (минимум 10 ГБ)

  3. Установленные инструменты на управляющем хосте:

  4. kubectl
  5. helm

Подготовка дисков

Каждая worker-нода должна иметь смонтированный диск в /mnt/data. Диск форматируется в формате ext4 и права устанавливаются для пользователя postgres (UID 26).

1. Создайте файл disk-mount-daemonset.yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: disk-mount-daemon
  namespace: kube-system
  labels:
    app: disk-mount
spec:
  selector:
    matchLabels:
      app: disk-mount
  template:
    metadata:
      labels:
        app: disk-mount
    spec:
      priorityClassName: system-node-critical
      hostPID: true
      containers:
      - name: disk-mount
        image: ubuntu:24.04
        command:
          - bash
          - -c
          - |
            apt-get update -qq && apt-get install -y -qq e2fsprogs > /dev/null 2>&1
            nsenter -t 1 -m -u -i -n -p mkdir -p /mnt/data
            nsenter -t 1 -m -u -i -n -p mkfs.ext4 -F /dev/vdb 2>/dev/null || true
            nsenter -t 1 -m -u -i -n -p mount /dev/vdb /mnt/data
            nsenter -t 1 -m -u -i -n -p chown -R 26:26 /mnt/data
            nsenter -t 1 -m -u -i -n -p chmod 700 /mnt/data
            echo "Disk mounted on $(hostname)"
            df -h /mnt/data
            tail -f /dev/null
        securityContext:
          privileged: true
        resources:
          requests:
            cpu: 10m
            memory: 64Mi
          limits:
            cpu: 100m
            memory: 256Mi
      tolerations:
        - operator: Exists

2. Примените конфигурацию

kubectl apply -f disk-mount-daemonset.yaml

3. Проверьте состояние

Убедитесь, что поды запущены на всех нодах:

kubectl get pods -n kube-system -l app=disk-mount

Ожидаемый результат:

NAME                      READY   STATUS    NODE
disk-mount-daemon-xxxxx   1/1     Running   worker-1
disk-mount-daemon-xxxxx   1/1     Running   worker-2
disk-mount-daemon-xxxxx   1/1     Running   worker-3

Проверьте логи для подтверждения монтирования:

kubectl logs -n kube-system <имя-pod>

Лог должен содержать:

Filesystem      Size  Used Avail Use% Mounted on
/dev/vdb         10G   24K   9.8G   1% /mnt/data

Примечание: Если на вашей ноде дополнительный диск имеет другое имя (например, /dev/sdb), замените /dev/vdb в YAML-файле на соответствующее значение.


Настройка Persistent Volumes

1. Создайте файл pv-pvc.yaml

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pg-data-worker-1
  labels:
    app: postgres
    node: worker-1
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  storageClassName: local-storage
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /mnt/data
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - worker-1
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pg-data-worker-2
  labels:
    app: postgres
    node: worker-2
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  storageClassName: local-storage
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /mnt/data
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - worker-2
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pg-data-worker-3
  labels:
    app: postgres
    node: worker-3
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  storageClassName: local-storage
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /mnt/data
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - worker-3

Примечание: Если ваши worker-ноды имеют другие имена, замените worker-1, worker-2, worker-3 на соответствующие значения. Узнать имена можно командой kubectl get nodes.

2. Примените конфигурацию

kubectl apply -f pv-pvc.yaml

3. Проверьте создание PV и StorageClass

kubectl get pv
kubectl get sc

Ожидаемый результат:

NAME               CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS
pg-data-worker-1   10Gi       RWO            Retain           Available
pg-data-worker-2   10Gi       RWO            Retain           Available
pg-data-worker-3   10Gi       RWO            Retain           Available

Установка CloudNativePG оператора

CloudNativePG — это Kubernetes-оператор, который управляет кластером PostgreSQL: создаёт ноды, настраивает репликацию, автоматически выполняет failover.

1. Добавьте репозиторий Helm

helm repo add cnpg https://cloudnative-pg.github.io/charts
helm repo update cnpg

2. Установите оператор

helm install cnpg cnpg/cloudnative-pg --namespace cnpg-system --create-namespace

3. Проверьте установку

kubectl get pods -n cnpg-system

Ожидаемый результат:

NAME                                 READY   STATUS
cnpg-cloudnative-pg-xxxxxxxxx-xxxxx  1/1     Running

Создание кластера PostgreSQL

1. Создайте namespace

kubectl create namespace postgresql

2. Создайте секрет с паролем

Придумайте надёжный пароль и замените ВАШ_ПАРОЛЬ на него:

kubectl create secret generic postgres-credentials \
  --namespace=postgresql \
  --from-literal=username=app \
  --from-literal=password='ВАШ_ПАРОЛЬ'

Важно: В секрете ключ username должен быть app — это имя пользователя, который будет владельцем базы данных.

3. Создайте файл pg-cluster.yaml

---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-postgres
  namespace: postgresql
spec:
  instances: 3
  imageName: ghcr.io/cloudnative-pg/postgresql:16.4
  postgresql:
    parameters:
      max_connections: "200"
  storage:
    size: 35Gi
    storageClass: local-storage
  resources:
    requests:
      cpu: "1"
      memory: 1Gi
    limits:
      cpu: "2"
      memory: 1800Mi
  primaryUpdateStrategy: unsupervised
  bootstrap:
    initdb:
      database: appdb
      owner: app
      secret:
        name: postgres-credentials
      postInitApplicationSQL:
        - "CREATE EXTENSION IF NOT EXISTS pg_stat_statements;"
  affinity:
    enablePodAntiAffinity: true
---
apiVersion: v1
kind: Service
metadata:
  name: postgres-external
  namespace: postgresql
spec:
  type: NodePort
  selector:
    postgresql.cnpg.io/cluster: cluster-postgres
    postgresql.cnpg.io/instance-role: primary
  ports:
  - name: postgresql
    port: 5432
    targetPort: 5432
    nodePort: 30432
    protocol: TCP

Настройка ресурсов: значения resources должны соответствовать доступным ресурсам ваших нод. Проверьте доступные ресурсы командой kubectl describe nodes. Если на вашей ноде меньше ресурсов, уменьшите значения requests и limits.

4. Примените конфигурацию

kubectl apply -f pg-cluster.yaml

5. Дождитесь создания кластера

kubectl get cluster -n postgresql -w

Наблюдайте за состоянием кластера. Процесс может занять 2–5 минут. Ожидаемый результат:

NAME               AGE   INSTANCES   READY   STATUS                     PRIMARY
cluster-postgres   5m    3           3       Cluster in healthy state   cluster-postgres-1

Кластер готов, когда STATUS показывает Cluster in healthy state и READY равен 3.

6. Проверьте поды

kubectl get pods -n postgresql -l cnpg.io/podRole=instance -o wide

Каждый под должен находиться на отдельной ноде благодаря enablePodAntiAffinity:

NAME                 READY   STATUS    NODE
cluster-postgres-1   1/1     Running   worker-1
cluster-postgres-2   1/1     Running   worker-2
cluster-postgres-3   1/1     Running   worker-3

Настройка паролей

После создания кластера настройте пароли для пользователей PostgreSQL.

1. Подключитесь к primary под

Узнайте имя primary пода:

kubectl get cluster -n postgresql

Подключитесь к консоли PostgreSQL:

kubectl exec -it <имя-primary-pod> -n postgresql --container postgres -- psql -U postgres -d appdb

2. Установите пароль для суперпользователя

ALTER USER postgres WITH PASSWORD 'ВАШ_ПАРОЛЬ_СУПЕРП';

3. Установите пароль для пользователя приложения

ALTER USER app WITH PASSWORD 'ВАШ_ПАРОЛЬ_APP';

4. Выйдите из консоли

\q

5. Обновите секрет

kubectl delete secret postgres-credentials -n postgresql
kubectl create secret generic postgres-credentials \
  --namespace=postgresql \
  --from-literal=username=app \
  --from-literal=password='ВАШ_ПАРОЛЬ_APP'

Внешний доступ

Сервис postgres-external (NodePort) создан вместе с кластером и предоставляет доступ к primary ноде PostgreSQL с порта 30432.

1. Получите IP-адреса worker-нод

kubectl get nodes -o wide

Запишите внутренние IP-адреса из колонки INTERNAL-IP.

2. Подключитесь извне

psql -h <IP-НОДЫ> -p 30432 -U app -d appdb

Внутренние адреса

Если вы подключаетесь изнутри кластера (из другого пода), используйте:

Сервис Назначение Адрес
cluster-postgres-rw Запись/чтение (только primary) cluster-postgres-rw.postgresql.svc.cluster.local:5432
cluster-postgres-r Все ноды (round-robin) cluster-postgres-r.postgresql.svc.cluster.local:5432
cluster-postgres-ro Только чтение (только replica) cluster-postgres-ro.postgresql.svc.cluster.local:5432

Полезные команды

Статус кластера

kubectl get cluster -n postgresql

Статус подов PostgreSQL

kubectl get pods -n postgresql -l cnpg.io/podRole=instance

Логи пода

kubectl logs <имя-pod> -n postgresql -f

Подключение к консоли PostgreSQL

kubectl exec <имя-primary-pod> -n postgresql --container postgres -- psql -U postgres -d appdb

Перезапуск всех нод кластера

kubectl patch cluster cluster-postgres -n postgresql --type merge --patch '{"spec":{"instances":3}}'

Нам доверяют тысячи компаний и разработчиков

22 года
Предоставляем услуги профессионального хостинга
35 000+
Клиентов доверяют нам размещение своих сайтов
99.99%
Подтвержденный uptime наших серверов хостинга
Callibri
Крылья
Tele-Club
Linline
Премьер зал
УГМК-Здоровье
Магнум
Алатырь
Туристер
Callibri
Крылья
Tele-Club
Linline
Премьер зал
УГМК-Здоровье
Магнум
Алатырь
Туристер
ВК49865