Поделиться через


Развертывание высокодоступной базы данных PostgreSQL в Службе Azure Kubernetes (AKS)

В этой статье описано, как развернуть высокодоступную базу данных PostgreSQL в AKS.

Important

Программное обеспечение с открытым кодом упоминается во всей документации и примерах AKS. Программное обеспечение, которое вы развертываете, не покрывается соглашениями об уровне обслуживания AKS, ограниченной гарантией и поддержкой Azure. При использовании технологии с открытым исходным кодом вместе с AKS ознакомьтесь с вариантами поддержки, доступными от соответствующих сообществ и обслуживающих проектов для разработки плана.

Корпорация Майкрософт несет ответственность за создание пакетов с открытым кодом, которые мы развертываем в AKS. Эта ответственность включает полное управление процессами сборки, сканирования, подписывания, проверки и исправления ошибок, а также контроль над двоичными файлами в образах контейнеров. Для получения дополнительной информации см. Управление уязвимостями в AKS и Покрытие поддержки AKS.

Создание пароля для пользователя Bootstrap приложения

  1. Создайте секрет для проверки развертывания PostgreSQL с помощью интерактивного входа для пользователя начального приложения, используя команду kubectl create secret.

Important

Корпорация Майкрософт рекомендует использовать самый безопасный поток проверки подлинности. Поток проверки подлинности, описанный в этой процедуре, требует высокого уровня доверия к приложению и несет риски, которые отсутствуют в других потоках. Этот поток следует использовать только в том случае, если другие более безопасные потоки, такие как идентификации с управлением, не являются приемлемыми.

PG_DATABASE_APPUSER_SECRET=$(echo -n | openssl rand -base64 16)

kubectl create secret generic db-user-pass \
    --from-literal=username=app \
     --from-literal=password="${PG_DATABASE_APPUSER_SECRET}" \
     --namespace $PG_NAMESPACE \
     --context $AKS_PRIMARY_CLUSTER_NAME
  1. Убедитесь, что секрет был успешно создан с помощью kubectl get команды.

    kubectl get secret db-user-pass --namespace $PG_NAMESPACE --context $AKS_PRIMARY_CLUSTER_NAME
    

Установите переменные среды для кластера PostgreSQL

  • Разверните ConfigMap, чтобы настроить оператор CNPG с помощью следующей kubectl apply команды. Эти значения заменяют устаревший переключатель ENABLE_AZURE_PVC_UPDATES, который больше не требуется, а также помогают распределить обновления и ускорить повторное подключение реплик. Прежде чем развертывать эту конфигурацию в рабочую среду, убедитесь, что все существующие DRAIN_TAINTS параметры, на которые вы полагаетесь, остаются совместимыми с вашей средой Azure.

    cat <<EOF | kubectl apply --context $AKS_PRIMARY_CLUSTER_NAME -n $PG_NAMESPACE -f -
    apiVersion: v1
    kind: ConfigMap
    metadata:
        name: cnpg-controller-manager-config
    data:
        CLUSTERS_ROLLOUT_DELAY: '120'
        STANDBY_TCP_USER_TIMEOUT: '10'
    EOF
    

Установка PodMonitors Prometheus

Prometheus собирает данные из CNPG с помощью правил извлечения, хранящихся в репозитории образцов GitHub CNPG. Так как управляемый оператором PodMonitor устарел, создайте и управляйте ресурсом PodMonitor самостоятельно, чтобы вы могли адаптировать его к стеку мониторинга.

  1. Добавьте репозиторий Prometheus Community Helm с помощью helm repo add команды.

    helm repo add prometheus-community \
        https://prometheus-community.github.io/helm-charts
    
  2. Обновите репозиторий Prometheus Community Helm и установите его в основном кластере с помощью команды helm upgrade с флагом --install.

    helm upgrade --install \
        --namespace $PG_NAMESPACE \
        -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/main/docs/src/samples/monitoring/kube-stack-config.yaml \
        prometheus-community \
        prometheus-community/kube-prometheus-stack \
        --kube-context=$AKS_PRIMARY_CLUSTER_NAME
    
  3. Создайте PodMonitor для кластера. Команда CNPG прекращает поддержку управления PodMonitor через оператор, поэтому теперь вы управляете им напрямую.

    cat <<EOF | kubectl apply --context $AKS_PRIMARY_CLUSTER_NAME --namespace $PG_NAMESPACE -f -
    apiVersion: monitoring.coreos.com/v1
    kind: PodMonitor
    metadata:
      name: $PG_PRIMARY_CLUSTER_NAME
      namespace: ${PG_NAMESPACE}
      labels:
        cnpg.io/cluster: ${PG_PRIMARY_CLUSTER_NAME}
    spec:
      selector:
        matchLabels:
          cnpg.io/cluster: ${PG_PRIMARY_CLUSTER_NAME}
      podMetricsEndpoints:
        - port: metrics
    EOF
    

Создать федеративную учетную запись

В этом разделе вы создаете федеративные учетные данные удостоверения для резервного копирования PostgreSQL, чтобы предоставить CNPG возможность использовать удостоверение рабочей нагрузки AKS для аутентификации в целевой учетной записи хранения для резервных копий. Оператор CNPG создает учетную запись службы Kubernetes с тем же именем, что и кластер, который называется в манифесте развертывания кластера CNPG.

  1. Получите URL-адрес издателя OIDC кластера с помощью az aks show команды.

    export AKS_PRIMARY_CLUSTER_OIDC_ISSUER="$(az aks show \
        --name $AKS_PRIMARY_CLUSTER_NAME \
        --resource-group $RESOURCE_GROUP_NAME \
        --query "oidcIssuerProfile.issuerUrl" \
        --output tsv)"
    
  2. Создайте федеративные учетные данные удостоверения с помощью команды az identity federated-credential create.

    az identity federated-credential create \
        --name $AKS_PRIMARY_CLUSTER_FED_CREDENTIAL_NAME \
        --identity-name $AKS_UAMI_CLUSTER_IDENTITY_NAME \
        --resource-group $RESOURCE_GROUP_NAME \
        --issuer "${AKS_PRIMARY_CLUSTER_OIDC_ISSUER}" \
        --subject system:serviceaccount:"${PG_NAMESPACE}":"${PG_PRIMARY_CLUSTER_NAME}" \
        --audience api://AzureADTokenExchange
    

Развертывание кластера PostgreSQL с высоким уровнем доступности

В этом разделе описано, как развернуть высокодоступный кластер PostgreSQL с помощью настраиваемого определения ресурсов кластера CNPG (CRD).

Параметры CRD кластера

В следующей таблице описаны ключевые свойства, заданные в манифесте развертывания YAML для кластера CRD:

Property Definition
imageName Указывает на образ контейнера операнда CloudNativePG. Используйте ghcr.io/cloudnative-pg/postgresql:18-system-trixie с встроенной интеграцией резервного копирования, показанной в этом руководстве, или переключитесь на 18-standard-trixie, если вы планируете использовать плагин Barman Cloud.
inheritedMetadata Зависит от оператора CNPG. Оператор CNPG применяет метаданные к каждому объекту, связанному с кластером.
annotations Включает метку DNS, необходимую при предоставлении конечных точек кластера, и позволяет alpha.cnpg.io/failoverQuorum для отказоустойчивости на основе кворума.
labels: azure.workload.identity/use: "true" Указывает, что AKS должен внедрять зависимости удостоверений рабочей нагрузки в модули pod, в которые размещаются экземпляры кластера PostgreSQL.
topologySpreadConstraints Требуются разные зоны и узлы с меткой "workload=postgres".
resources Настраивает класс Quality of Service (QoS) гарантированный. В рабочей среде эти значения являются ключевыми для максимизации использования базовой виртуальной машины узла и зависят от используемого SKU виртуальной машины Azure.
probes Заменяет устаревшую конфигурацию startDelay . Пробы запуска и готовности потоковой передачи помогают обеспечить работоспособность реплик перед обслуживанием трафика.
smartShutdownTimeout Позволяет длительным транзакциям плавно завершаться во время обновлений вместо использования агрессивных задержек остановки.
bootstrap Зависит от оператора CNPG. Инициализируется с пустой базой данных приложения.
storage Определяет параметры PersistentVolume для базы данных. Благодаря управляемым дискам Azure, упрощенный синтаксис позволяет сохранять данные и WAL на одном томе объемом 64 ГиБ, что обеспечивает более высокие уровни пропускной способности для управляемых дисков. Настройте, если вам нужны отдельные тома WAL.
postgresql.synchronous minSyncReplicas / maxSyncReplicas Заменяет и позволяет указать синхронное поведение репликации с помощью более новой схемы.
postgresql.parameters Зависит от оператора CNPG. Сопоставляет параметры для postgresql.conf, pg_hba.confи pg_ident.conf. В примере подчеркиваются наблюдаемость и параметры хранения WAL по умолчанию, которые подходят для сценария идентификации рабочей нагрузки AKS, но должны быть настроены в зависимости от особенностей каждой рабочей нагрузки.
serviceAccountTemplate Содержит шаблон, необходимый для создания учетных записей службы и сопоставляет учетные данные федеративного удостоверения AKS с UAMI, чтобы включить проверку подлинности удостоверения рабочей нагрузки AKS из модулей pod, на которых размещены экземпляры PostgreSQL, с внешними ресурсами Azure.
barmanObjectStore Зависит от оператора CNPG. Настраивает набор инструментов barman-cloud с помощью идентификации рабочей нагрузки AKS для аутентификации в хранилище объектов Azure Blob.

Для дальнейшей изоляции рабочих нагрузок PostgreSQL можно добавить метку (например, node-role.kubernetes.io/postgres=:NoSchedule) для узлов плоскости данных и заменить шаблон nodeSelector/tolerations значениями, рекомендуемыми CloudNativePG. Если вы используете этот подход, пометьте узлы соответствующим образом и убедитесь, что политики автомасштабирования AKS соответствуют топологии.

Параметры производительности PostgreSQL

Производительность PostgreSQL значительно зависит от базовых ресурсов и рабочей нагрузки кластера. В следующей таблице приведены базовые рекомендации по кластеру с тремя узлами, работающим на узлах standard D4s версии 3 (16-ГиБ памяти). Обработайте эти значения как отправную точку и измените их после понимания профиля рабочей нагрузки:

Property Рекомендуемое значение Definition
wal_compression lz4 Сжимает полностраничные записи в WAL-файле с указанным методом.
max_wal_size 6 ГБ Задает размер WAL, который активирует контрольную точку
checkpoint_timeout 15 минут Задает максимальное время между автоматическими контрольными точками WAL
checkpoint_completion_target 0,9 Балансирует работу контрольных точек в окне контрольных точек
checkpoint_flush_after 2 МБ Количество страниц, после которых ранее выполненные операции записи сбрасываются на диск
wal_writer_flush_after 2 МБ Объем данных, записанных WAL-писателем, который запускает очистку.
min_wal_size 2 ГБ Задает минимальный размер для сжатия WAL до
max_slot_wal_keep_size 10 ГБ Верхняя граница для wal слева на слоты репликации службы
shared_buffers 4 ГБ Задает количество буферов общей памяти, используемых сервером (25% памяти узла в этом примере)
effective_cache_size 12 ГБ Задает предположение планировщика об общем размере кэшей данных
work_mem 1/256-й объем памяти узла Задает максимальный объем памяти, используемый для рабочих областей запросов
maintenance_work_mem 6.25% памяти узла Задает максимальный объем памяти, используемый для операций обслуживания
autovacuum_vacuum_cost_limit 2400 Объем затрат вакуума, доступный перед перерывом, для автовакуума
random_page_cost 1.1 Задает оценку планировщика стоимости не последовательно извлекаемой страницы диска.
effective_io_concurrency 64 Задает количество одновременных запросов, которые подсистема диска может эффективно обрабатывать
maintenance_io_concurrency 64 Вариант "effective_io_concurrency", используемый для обслуживания

Развертывание PostgreSQL

  1. Разверните кластер PostgreSQL с помощью Cluster CRD, используя команду kubectl apply.

    cat <<EOF | kubectl apply --context $AKS_PRIMARY_CLUSTER_NAME -n $PG_NAMESPACE -v 9 -f -
    apiVersion: postgresql.cnpg.io/v1
    kind: Cluster
    metadata:
      name: $PG_PRIMARY_CLUSTER_NAME
      annotations:
        alpha.cnpg.io/failoverQuorum: "true"
    spec:
      imageName: ghcr.io/cloudnative-pg/postgresql:18-system-trixie
      inheritedMetadata:
        annotations:
          service.beta.kubernetes.io/azure-dns-label-name: $AKS_PRIMARY_CLUSTER_PG_DNSPREFIX
        labels:
          azure.workload.identity/use: "true"
    
      instances: 3
      smartShutdownTimeout: 30
    
      probes:
        startup:
          type: streaming
          maximumLag: 32Mi
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 120
        readiness:
          type: streaming
          maximumLag: 0
          periodSeconds: 10
          failureThreshold: 6
    
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            cnpg.io/cluster: $PG_PRIMARY_CLUSTER_NAME
    
      affinity:
        nodeSelector:
          workload: postgres
    
      resources:
        requests:
          memory: '8Gi'
          cpu: 2
        limits:
          memory: '8Gi'
          cpu: 2
    
      bootstrap:
        initdb:
          database: appdb
          owner: app
          secret:
            name: db-user-pass
          dataChecksums: true
    
      storage:
        storageClass: $POSTGRES_STORAGE_CLASS
        size: 64Gi
    
      postgresql:
        synchronous:
          method: any
          number: 1
        parameters:
          wal_compression: lz4
          max_wal_size: 6GB
          max_slot_wal_keep_size: 10GB
          checkpoint_timeout: 15min
          checkpoint_completion_target: '0.9'
          checkpoint_flush_after: 2MB
          wal_writer_flush_after: 2MB
          min_wal_size: 2GB
          shared_buffers: 4GB
          effective_cache_size: 12GB
          work_mem: 62MB
          maintenance_work_mem: 1GB
          autovacuum_vacuum_cost_limit: "2400"
          random_page_cost: "1.1"
          effective_io_concurrency: "64"
          maintenance_io_concurrency: "64"
          log_checkpoints: 'on'
          log_lock_waits: 'on'
          log_min_duration_statement: '1000'
          log_statement: 'ddl'
          log_temp_files: '1024'
          log_autovacuum_min_duration: '1s'
          pg_stat_statements.max: '10000'
          pg_stat_statements.track: 'all'
          hot_standby_feedback: 'on'
        pg_hba:
          - host all all all scram-sha-256
    
      serviceAccountTemplate:
        metadata:
          annotations:
            azure.workload.identity/client-id: "$AKS_UAMI_WORKLOAD_CLIENTID"
          labels:
            azure.workload.identity/use: "true"
    
      backup:
        barmanObjectStore:
          destinationPath: "https://${PG_PRIMARY_STORAGE_ACCOUNT_NAME}.blob.core.windows.net/backups"
          azureCredentials:
            inheritFromAzureAD: true
        retentionPolicy: '7d'
    EOF
    

Замечание

В примере манифеста используется образ ghcr.io/cloudnative-pg/postgresql:18-system-trixie, так как он работает с интеграцией в основной системе Barman Cloud, показанной позже. Когда вы будете готовы перейти на подключаемый модуль Barman Cloud, обновите spec.imageName на ghcr.io/cloudnative-pg/postgresql:18-standard-trixie и следуйте инструкциям по настройке подключаемого модуля прежде чем развертывать кластер.

Important

Пример pg_hba записи разрешает доступ, отличный от TLS. Если вы храните эту конфигурацию, задокументируйте последствия безопасности для вашей команды и предпочитайте зашифрованные подключения везде, где это возможно.

  1. Убедитесь, что основной кластер PostgreSQL успешно создан с помощью kubectl get команды. CrD кластера CNPG указал три экземпляра, которые можно проверить, просматривая модули pod после создания и объединения каждого экземпляра для репликации. Будьте терпеливы, так как может занять некоторое время, чтобы все три экземпляра стали доступными и присоединились к кластеру.

    kubectl get pods --context $AKS_PRIMARY_CLUSTER_NAME --namespace $PG_NAMESPACE -l cnpg.io/cluster=$PG_PRIMARY_CLUSTER_NAME
    

    Пример результата

    NAME                         READY   STATUS    RESTARTS   AGE
    pg-primary-cnpg-r8c7unrw-1   1/1     Running   0          4m25s
    pg-primary-cnpg-r8c7unrw-2   1/1     Running   0          3m33s
    pg-primary-cnpg-r8c7unrw-3   1/1     Running   0          2m49s
    

Important

Если вы используете локальный NVMe с хранилищем контейнеров Azure, а pod остаётся в состоянии инициализации с ошибкой множественного подключения, pod всё ещё пытается найти том на потерянном узле. После запуска pod он переходит в состояние CrashLoopBackOff, так как CNPG создает новую реплику на новом узле без данных и не может найти каталог pgdata. Чтобы устранить эту проблему, удалите затронутый экземпляр и создайте новый экземпляр. Выполните следующую команду:

kubectl cnpg destroy [cnpg-cluster-name] [instance-number]  

Убедитесь, что PodMonitor Prometheus работает

Созданный вручную podMonitor связывает конфигурацию слома kube-prometheus-stack с развернутыми ранее модулями POD CNPG.

Убедитесь, что podMonitor выполняется с помощью kubectl get команды.

kubectl --namespace $PG_NAMESPACE \
    --context $AKS_PRIMARY_CLUSTER_NAME \
    get podmonitors.monitoring.coreos.com \
    $PG_PRIMARY_CLUSTER_NAME \
    --output yaml

Пример результата

kind: PodMonitor
metadata:
  labels:
    cnpg.io/cluster: pg-primary-cnpg-r8c7unrw
  name: pg-primary-cnpg-r8c7unrw
  namespace: cnpg-database
spec:
  podMetricsEndpoints:
  - port: metrics
  selector:
    matchLabels:
      cnpg.io/cluster: pg-primary-cnpg-r8c7unrw

Если вы используете Azure Monitor для Managed Prometheus, необходимо добавить еще один монитор Pod с помощью пользовательского имени группы. Управляемый Prometheus не интегрирует пользовательские определения ресурсов (CRD) из сообщества Prometheus. За исключением названия группы, CRD совпадают. Эта конструкция позволяет мониторам подов для Managed Prometheus работать одновременно с мониторами подов, которые используют CRD сообщества. Если вы не используете Управляемый Prometheus, можно пропустить этот раздел. Создайте новый монитор pod:

cat <<EOF | kubectl apply --context $AKS_PRIMARY_CLUSTER_NAME --namespace $PG_NAMESPACE -f -
apiVersion: azmonitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: cnpg-cluster-metrics-managed-prometheus
  namespace: ${PG_NAMESPACE}
  labels:
    azure.workload.identity/use: "true"
    cnpg.io/cluster: ${PG_PRIMARY_CLUSTER_NAME}
spec:
  selector:
    matchLabels:
      azure.workload.identity/use: "true"
      cnpg.io/cluster: ${PG_PRIMARY_CLUSTER_NAME}
  podMetricsEndpoints:
    - port: metrics
EOF

Убедитесь, что монитор pod создан (обратите внимание на разницу в имени группы).

kubectl --namespace $PG_NAMESPACE \
    --context $AKS_PRIMARY_CLUSTER_NAME \
    get podmonitors.azmonitoring.coreos.com \
    -l cnpg.io/cluster=$PG_PRIMARY_CLUSTER_NAME \
    -o yaml

Вариант A - Рабочая область Azure Monitor

После развертывания кластера Postgres и монитора pod можно просмотреть метрики с помощью портала Azure в рабочей области Azure Monitor.

Снимок экрана: метрики кластера Postgres в рабочей области Azure Monitor на портале Azure.

Вариант B — управляемый сервис Grafana

Кроме того, после развертывания кластера Postgres и мониторов pod можно создать панель мониторинга метрик на управляемом экземпляре Grafana, созданном скриптом развертывания, чтобы визуализировать метрики, экспортированные в рабочую область Azure Monitor. Вы можете получить доступ к Managed Grafana через портал Azure. Перейдите к управляемому экземпляру Grafana, созданному скриптом развертывания, и выберите ссылку "Конечная точка", как показано ниже:

Снимок экрана: метрики кластера Postgres в экземпляре Управляемой Grafana Azure на портале Azure.

При выборе ссылки "Конечная точка" откроется новое окно браузера, в котором можно создать панели мониторинга в Managed Grafana. Следуя инструкциям по настройке источника данных Azure Monitor, вы можете добавить визуализации для создания панели мониторинга метрик из кластера Postgres. После настройки подключения к источнику данных в главном меню выберите параметр "Источники данных". Вы увидите набор параметров источника данных для подключения к источнику данных, как показано ниже.

Снимок экрана: параметры источника данных Azure Monitor на портале Azure.

В параметре Managed Prometheus выберите параметр для создания панели мониторинга, чтобы открыть редактор панели мониторинга. После открытия окна редактора выберите параметр "Добавить визуализацию", а затем выберите параметр Managed Prometheus, чтобы просмотреть метрики из кластера Postgres. После выбора метрики, которую вы хотите визуализировать, нажмите кнопку "Выполнить запросы", чтобы получить данные для визуализации, как показано ниже:

Снимок экрана: панель мониторинга Managed Prometheus с метриками кластера Postgres.

Щелкните значок "Сохранить", чтобы добавить панель на панель мониторинга. Вы можете добавить другие панели, нажав кнопку "Добавить" в редакторе панели мониторинга и повторив этот процесс, чтобы визуализировать другие метрики. При добавлении визуализаций метрик, вы должны получить что-то, что выглядит так:

Снимок экрана: сохраненная панель мониторинга Managed Prometheus на портале Azure.

Щелкните значок "Сохранить", чтобы сохранить панель мониторинга.


Дальнейшие шаги

Contributors

Корпорация Майкрософт поддерживает эту статью. Первоначальная версия была написана следующими участниками:

  • Кен Килти | Ведущий TPM
  • Рассел де Пина | Главный технический менеджер программ
  • Адриан Джоан | Старший инженер клиента
  • Дженни Хейс | Старший разработчик содержимого
  • Кэрол Смит | Старший разработчик содержимого
  • Эрин Шаффер | Разработчик содержимого 2
  • Адам Шариф | Инженер клиента 2

Подтверждения

Эта документация была совместно разработана с EnterpriseDB, обслуживающим оператор CloudNativePG. Мы благодарим Габриэль Бартолини за просмотр предыдущих проектов этого документа и предложение технических улучшений.