Compartir a través de


Implementación de una base de datos PostgreSQL de alta disponibilidad en Azure Kubernetes Service (AKS)

En este artículo, implementará una base de datos PostgreSQL de alta disponibilidad en AKS.

Important

El software de código abierto se menciona en toda la documentación y ejemplos de AKS. El software que implemente se excluye de los contratos de nivel de servicio de AKS, la garantía limitada y el Soporte técnico de Azure. A medida que usa la tecnología de código abierto junto con AKS, consulte las opciones de soporte técnico disponibles en las comunidades y los mantenedores de proyectos respectivos para desarrollar un plan.

Microsoft asume la responsabilidad de crear los paquetes de código abierto que implementamos en AKS. Esa responsabilidad incluye tener la propiedad completa del proceso de compilación, examen, firma, validación y revisión, junto con el control sobre los archivos binarios en imágenes de contenedor. Para más información, consulte Administración de vulnerabilidades para AKS y Cobertura de soporte técnico de AKS.

Creación de un secreto para el usuario de la aplicación de arranque

  1. Genere un secreto para validar la implementación de PostgreSQL mediante el inicio de sesión interactivo de un usuario de aplicación de arranque mediante el comando kubectl create secret.

Important

Microsoft recomienda usar el flujo de autenticación más seguro disponible. El flujo de autenticación descrito en este procedimiento requiere un alto grado de confianza en la aplicación y conlleva riesgos que no están presentes en otros flujos. Solo debe usar este flujo cuando otros flujos más seguros, como las identidades administradas, no sean viables.

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. Compruebe que el secreto se creó correctamente mediante el comando kubectl get.

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

Establecimiento de variables de entorno para el clúster de PostgreSQL

  • Implemente un configMap para configurar el operador CNPG mediante el siguiente kubectl apply comando. Estos valores reemplazan el interruptor heredado ENABLE_AZURE_PVC_UPDATES, que ya no es necesario, y ayudan a escalonar las actualizaciones y acelerar las reconexiones de réplicas. Antes de implementar esta configuración en producción, compruebe que cualquier configuración existente DRAIN_TAINTS que confíe siga siendo compatible con el entorno de 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
    

Instalación de PodMonitors de Prometheus

Prometheus extrae datos de CNPG mediante las reglas de grabación almacenadas en el repositorio de ejemplos de CNPG en GitHub. Dado que el PodMonitor administrado por el operador está quedando obsoleto, cree y gestione usted mismo el recurso PodMonitor para adaptarlo adecuadamente a su pila de supervisión.

  1. Agregue el repositorio de Helm de la comunidad de Prometheus mediante el comando helm repo add.

    helm repo add prometheus-community \
        https://prometheus-community.github.io/helm-charts
    
  2. Actualice el repositorio de Helm de la comunidad de Prometheus e instálelo en el clúster principal mediante el comando helm upgrade con la marca --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. Cree un PodMonitor para el clúster. El equipo de CNPG está dejando de usar el PodMonitor gestionado por el operador, por lo que ahora lo gestiona directamente:

    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
    

Creación de una credencial federada

En esta sección, creará una credencial de identidad federada para la copia de seguridad de PostgreSQL para permitir que CNPG use la identidad de carga de trabajo de AKS para autenticarse en el destino de la cuenta de almacenamiento para las copias de seguridad. El operador CNPG crea una cuenta de servicio de Kubernetes con el mismo nombre que el clúster denominado usado en el manifiesto de implementación del clúster CNPG.

  1. Obtenga la dirección URL del emisor de OIDC del clúster mediante el comando 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. Cree una credencial de identidad federada mediante el comando 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
    

Implementación de un clúster de PostgreSQL de alta disponibilidad

En esta sección, implementará un clúster de PostgreSQL de alta disponibilidad mediante la definición de recursos personalizados (CRD) del clúster CNPG.

Parámetros de CRD de clúster

En la tabla siguiente se describen las propiedades clave establecidas en el manifiesto de implementación de YAML para el CRD de clúster:

Property Definition
imageName Apunta a la imagen de contenedor del operando CloudNativePG. Use ghcr.io/cloudnative-pg/postgresql:18-system-trixie con la integración de copia de seguridad en núcleo que se muestra en esta guía o cambie a 18-standard-trixie cuando adopte el complemento Barman Cloud.
inheritedMetadata Específico del operador CNPG. El operador CNPG aplica los metadatos a todos los objetos relacionados con el clúster.
annotations Incluye la etiqueta DNS necesaria al exponer los puntos de conexión del clúster y habilita alpha.cnpg.io/failoverQuorum la conmutación por error basada en cuórum.
labels: azure.workload.identity/use: "true" Indica que AKS debe insertar dependencias de identidad de carga de trabajo en los pods que hospedan las instancias del clúster de PostgreSQL.
topologySpreadConstraints Requerir zonas diferentes y nodos diferentes con la etiqueta "workload=postgres".
resources Configura una clase de calidad de servicio (QoS) de Garantizado. En un entorno de producción, estos valores son clave para maximizar el uso de la máquina virtual del nodo subyacente y variar en función de la SKU de máquina virtual de Azure usada.
probes Reemplaza la configuración heredada startDelay . Los sondeos de inicio y preparación de streaming ayudan a garantizar que las réplicas estén en buen estado antes de atender el tráfico.
smartShutdownTimeout Permite que las transacciones de larga duración finalicen correctamente durante las actualizaciones en lugar de usar retrasos de detención agresivos.
bootstrap Específico del operador CNPG. Inicializa con una base de datos de aplicación vacía.
storage Define los ajustes de PersistentVolume para la base de datos. Con los discos administrados de Azure, la sintaxis simplificada mantiene los datos y WAL en el mismo volumen de 64 GiB, lo que ofrece mejores niveles de rendimiento en discos administrados. Ajuste si necesita volúmenes WAL independientes.
postgresql.synchronous minSyncReplicas / maxSyncReplicas Reemplaza y permite especificar el comportamiento de replicación sincrónica mediante el esquema más reciente.
postgresql.parameters Específico del operador CNPG. Asigna la configuración de postgresql.conf, pg_hba.conf y pg_ident.conf. En el ejemplo se resaltan los valores predeterminados de observabilidad y retención de WAL que se adaptan al escenario de identidad de carga de trabajo de AKS, pero que se deben ajustar por carga de trabajo.
serviceAccountTemplate Contiene la plantilla necesaria para generar las cuentas de servicio y asignar la credencial de identidad federada de AKS a la UAMI para habilitar la autenticación de identidad de carga de trabajo de AKS desde los pods que hospedan las instancias de PostgreSQL a recursos externos de Azure.
barmanObjectStore Específico del operador CNPG. Configura el conjunto de herramientas barman-cloud mediante la identidad de carga de trabajo de AKS para la autenticación en el almacén de objetos de Azure Blob Storage.

Para aislar aún más las cargas de trabajo de PostgreSQL, puede agregar un taint (por ejemplo, node-role.kubernetes.io/postgres=:NoSchedule) a los nodos del plano de datos y reemplazar el ejemplo nodeSelector/tolerations por los valores recomendados por CloudNativePG. Si adopta este enfoque, etiquete los nodos en consecuencia y confirme que las directivas de escalador automático de AKS se alinean con la topología.

Parámetros de rendimiento de PostgreSQL

El rendimiento de PostgreSQL depende en gran medida de los recursos y la carga de trabajo subyacentes del clúster. En la tabla siguiente se proporcionan instrucciones de línea base para un clúster de tres nodos que se ejecutan en nodos estándar D4s v3 (memoria de 16 GiB). Considere estos valores como punto de partida y ajústelos cuando comprenda su perfil de carga de trabajo.

Property Valor recomendado Definition
wal_compression lz4 Comprime las escrituras de página completa escritas en el archivo WAL con el método especificado
max_wal_size 6 GB Establece el tamaño de WAL que desencadena un punto de control
checkpoint_timeout 15 minutos Establece el tiempo máximo entre los puntos de control WAL automáticos.
checkpoint_completion_target 0.9 Equilibra el trabajo del punto de control en la ventana de punto de control
checkpoint_flush_after 2 MB Número de páginas después de las cuales las escrituras realizadas anteriormente se vacían en el disco
wal_writer_flush_after 2 MB Cantidad de WAL escrita por el escritor de WAL que desencadena un vaciado
min_wal_size 2 GB Establece el tamaño mínimo al que reducir WAL
max_slot_wal_keep_size 10 GB Límite superior para ranuras de replicación de WAL para servicio
shared_buffers 4 GB Establece el número de búferes de memoria compartidos usados por el servidor (25% de memoria de nodo en este ejemplo)
effective_cache_size 12 GB Establece la suposición del planificador sobre el tamaño total de las cachés de datos.
work_mem 1/256 de memoria de nodo Establece la memoria máxima que se va a usar para las áreas de trabajo de consulta.
maintenance_work_mem 6,25 % de la memoria del nodo Establece la memoria máxima que se va a usar para las operaciones de mantenimiento.
autovacuum_vacuum_cost_limit 2400 Cantidad de coste de vacío disponible antes de suspensión, para el vaciado automático
random_page_cost 1.1 Establece la estimación del planificador del costo de una página de disco recuperada de forma no secuencial.
effective_io_concurrency 64 Establece cuántas solicitudes simultáneas puede controlar el subsistema de disco de forma eficaz
maintenance_io_concurrency 64 Variante de "effective_io_concurrency" que se usa para el trabajo de mantenimiento

Implementación de PostgreSQL

  1. Implemente el clúster de PostgreSQL con el CRD de clúster mediante el comando 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
    

Nota:

El manifiesto de ejemplo usa la imagen ghcr.io/cloudnative-pg/postgresql:18-system-trixie porque está integrado con el núcleo de Barman Cloud, tal y como se muestra más adelante. Cuando esté listo para cambiar al complemento Barman Cloud, actualice spec.imageName a ghcr.io/cloudnative-pg/postgresql:18-standard-trixie y siga las instrucciones de configuración del complemento antes de volver a implementar el clúster.

Important

La entrada de ejemplo pg_hba permite el acceso no TLS. Si mantiene esta configuración, documente las implicaciones de seguridad del equipo y prefiera conexiones cifradas siempre que sea posible.

  1. Compruebe que el clúster de PostgreSQL principal se creó correctamente mediante el comando kubectl get. La CRD del clúster CNPG especificó tres instancias, que se pueden validar mediante la visualización de pods en ejecución una vez que cada instancia se abre y se une para la replicación. Tenga paciencia, ya que puede tardar algún tiempo en conectarse a las tres instancias y unirse al clúster.

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

    Salida de ejemplo

    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

Si usa NVMe local con Almacenamiento de contenedores de Azure y el pod permanece en estado de inicialización con un error de conexión múltiple, el pod sigue buscando el volumen en un nodo perdido. Una vez que el pod comienza a ejecutarse, entra en un CrashLoopBackOff estado porque CNPG crea una nueva réplica en un nuevo nodo sin datos y no encuentra el pgdata directorio. Para resolver este problema, destruya la instancia afectada y abra una nueva. Ejecute el siguiente comando:

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

Validar que Prometheus PodMonitor se está ejecutando

El PodMonitor creado manualmente vincula la configuración de extracción kube-prometheus-stack a los pods CNPG que implementó anteriormente.

Valide que PodMonitor se está ejecutando con el comando kubectl get.

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

Salida de ejemplo

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

Si usa Azure Monitor para Managed Prometheus, debe agregar otro monitor de pod mediante el nombre del grupo personalizado. Prometheus administrado no recoge las definiciones de recursos personalizados (CRD) de la comunidad de Prometheus. Aparte del nombre del grupo, los CRD son los mismos. Ese diseño permite que los monitores de pod para Prometheus administrado se ejecuten junto con monitores de pod que usan la CRD de la comunidad. Si no usa Prometheus administrado, puede omitir esta sección. Cree un nuevo monitor de 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

Compruebe que se crea el monitor de pods (tenga en cuenta la diferencia en el nombre del grupo).

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

Opción A: área de trabajo de Azure Monitor

Después de implementar el clúster de Postgres y el monitor de pods, puede ver las métricas mediante Azure Portal en un área de trabajo de Azure Monitor.

Captura de pantalla que muestra las métricas del clúster de Postgres en un área de trabajo de Azure Monitor en Azure Portal.

Opción B: Grafana administrada

Como alternativa, después de implementar los monitores de pod y clúster de Postgres, puede crear un panel de métricas en la instancia de Grafana administrada creada por el script de implementación para visualizar las métricas exportadas al área de trabajo de Azure Monitor. Puede acceder a Grafana administrada a través de Azure Portal. Vaya a la instancia de Grafana administrada creada por el script de implementación y seleccione el enlace endpoint como se indica aquí:

Captura de pantalla de las métricas del clúster de Postgres en una instancia de Grafana administrada de Azure en Azure Portal.

Al seleccionar el vínculo de endpoint, se abre una nueva ventana del navegador donde puede crear paneles en la instancia administrada de Grafana. Siguiendo las instrucciones para configurar un origen de datos de Azure Monitor, puede agregar visualizaciones para crear un panel de métricas desde el clúster de Postgres. Después de configurar la conexión de origen de datos, en el menú principal, seleccione la opción Orígenes de datos. Debería ver un conjunto de opciones de origen de datos para la conexión del origen de datos, como se muestra aquí:

Captura de pantalla que muestra las opciones del origen de datos de Azure Monitor en Azure Portal.

En la opción Managed Prometheus (Prometheus administrado), seleccione la opción para crear un panel para abrir el editor del panel. Una vez que se abra la ventana del editor, seleccione la opción Agregar visualización y, después, seleccione la opción Managed Prometheus para examinar las métricas desde el clúster de Postgres. Después de seleccionar la métrica que desea visualizar, seleccione el botón Ejecutar consultas para capturar los datos de la visualización, como se muestra aquí:

Captura de pantalla que muestra un panel de Prometheus administrado con métricas de clúster de Postgres.

Seleccione el icono Guardar para agregar el panel al tablero. Puede agregar otros paneles seleccionando el botón Agregar en el editor del panel y repitiendo este proceso para visualizar otras métricas. Al agregar las visualizaciones de métricas, debe tener algo similar al siguiente:

Captura de pantalla que muestra un panel de Prometheus administrado guardado en Azure Portal.

Seleccione el icono Guardar para guardar el panel.


Pasos siguientes

Contributors

Microsoft se encarga del mantenimiento de este artículo. Los siguientes colaboradores lo escribieron originalmente:

  • Ken Kilty | TPM de entidad de seguridad
  • Russell de Pina | TPM de entidad de seguridad
  • Adrian Joian | Ingeniero de clientes sénior
  • Jenny Hayes | Desarrollador de contenido sénior
  • Carol Smith | Desarrollador de contenido sénior
  • Erin Schaffer | Desarrollador de contenido 2
  • Adam Fabric | Ingeniero de clientes 2

Reconocimiento

Esta documentación se desarrolló conjuntamente con EnterpriseDB, los mantenedores del operador CloudNativePG. Agradecemos a Gabriele Bartolini por revisar los borradores anteriores de este documento y ofrecer mejoras técnicas.