Workstation Logo
Productos
Labs de IAAgentes OpenAIAgentes ClaudeGrok BotWorkstation CRM (WSL CRM)MarketingTodos los Productos
Soluciones IA
Estaciones de Trabajo IAAI SME PackagesIA PrivadaClústeres GPUIA en el BordeLaboratorio IA EmpresarialIA por Industria
Servicios
Modernización de plataformaIngeniería digitalFundamentos de datos e IAOperaciones autónomasConsultoría de IAAutomatización DevOpsCiberseguridadDesarrollo de softwareCreación de agentesConfiguración MLOps
Sobre Nosotros
SociosHistorias de Clientes
Artículos
Documentación
WSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7
Blog
ContáctenosLogin
Workstation

Estaciones de trabajo de IA, software multiagente de IA, infraestructura de GPU y soluciones de agentes inteligentes para empresas modernas.

Contáctenos

Soluciones de IA

Estaciones de Trabajo IAAI SME PackagesIA PrivadaClústeres GPUIA en el BordeLaboratorio IA EmpresarialIA por Industria

Productos

Todos los ProductosWSL CRM y ERPMarketingAgentes OpenAIWSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7

Empresa

Sobre NosotrosPor qué WorkstationSociosHistorias de ClientesPreciosContacto

Recursos

ArtículosDocumentaciónBlogBuscarMapa del Sitio
Oficina Reino Unido
77-79 Marlowes, Hemel Hempstead HP1 1LFCómo llegar: tome la salida 20 de la M25, Outer LondonN.º de empresa: 11641870Lun - Vie: 9:00 - 18:00 GMT
+44 7515 356 146
Oficina Bélgica
Workstation SRL, Rue Vanderkindere 34, 1180 Uccle, BrusselsBE 0751.518.683Lun - Vie: 9:00 - 18:00 CET
+32 492 45 67 46
Oficina India
#159 Sector 9, Pocket 1, DDA Flats, 110077 Dwarka, New Delhi
+91 98881 98841

© 2026 Workstation AI. Todos los derechos reservados.

PrivacidadCookiesTérminos de ServicioMapa del sitio web

Loading blog...

Home / Blog
DatabaseKubernetesDevOpsBackend

Alta disponibilidad de PostgreSQL con el operador Zalando Postgres: Guía de implementación de Kubernetes en múltiples nubes

Implemente PostgreSQL HA de nivel de producción con Zalando Operador en cualquier plataforma Kubernetes

Balinder Walia12 de abril de 202629 min read
Introducción a

: Por qué es importante la alta disponibilidad de PostgreSQL en Kubernetes

La ejecución de PostgreSQL en producción exige alta disponibilidad (HA). El tiempo de inactividad medido en minutos puede costar a las empresas millones de dólares en pérdida de ingresos, erosión de la confianza del cliente e incumplimiento de acuerdos de nivel de servicio. Kubernetes se ha convertido en la plataforma de facto para orquestar cargas de trabajo en contenedores, pero ejecutar servicios con estado como PostgreSQL en Kubernetes presenta desafíos únicos: administración de almacenamiento persistente, elección de líder, conmutación por error automática, orquestación de respaldo y agrupación de conexiones.

El operadorZalando Postgreses una solución de código abierto probada en batalla que Zalando, el minorista de moda en línea más grande de Europa, creó para gestionar cientos de clústeres PostgreSQL en producción. AprovechaPatronipara la elección de líderes basada en consenso,Spilocomo imagen de contenedor PostgreSQL,WAL-Gpara archivado continuo y recuperación en un momento dado, yPgBouncerpara agrupación de conexiones. Juntos, estos componentes ofrecen una implementación PostgreSQL totalmente automatizada y autorreparable que funciona en cualquier distribución Kubernetes, desde servicios de nube administrados como AWS EKS, Azure AKS y Google GKE hasta clústeres básicos que ejecutan k3s con Rancher.

En esta guía completa, exploraremos la arquitectura del operador Zalando Postgres, recorreremos la instalación y configuración en múltiples plataformas Kubernetes, profundizaremos en la replicación, las copias de seguridad, la recuperación ante desastres, el monitoreo y el ajuste de la producción. Al final, tendrá el conocimiento para implementar y operar clústeres PostgreSQL HA de nivel de producción en cualquier infraestructura Kubernetes.

Arquitectura del operador Zalando Postgres

Comprender la arquitectura es esencial antes de realizar la implementación. El operador Zalando Postgres sigue el patrón del operador Kubernetes: busca definiciones de recursos personalizados (CRD) de tipopostgresqly concilia el estado deseado con los recursos Kubernetes reales. Así es como encajan los componentes:

Arquitectura del operador Zalando PostgresPostgreSQL CRDTipo: postgresqlPostgres OperadorRelojes y amplificadoresConciliaConjunto de estadogestiona el ciclo de vida del podMódulo primarioEspilo (PostgreSQL)Agente PatroniRéplica de cápsula 1Espilo (PostgreSQL)Agente PatroniRéplica de cápsula 2Espilo (PostgreSQL)Agente PatroniPatrones DCS (Kubernetes API)Elección y control del líderEstado del clústerPgBouncerAgrupación de conexionesWAL-GCopias de seguridad en S3/GCS/AzurePrimarioRéplicaConsenso/DCSCopia de seguridadGrupo de conexiones

Spilo: La imagen del contenedor PostgreSQL

Spiloes la imagen Docker de Zalando que incluye PostgreSQL con Patroni, WAL-G y extensiones esenciales. Cada pod en StatefulSet ejecuta un contenedor Spilo. Mangos Spilo:

  • Servidor PostgreSQL: el motor de base de datos en sí, compatible con las versiones 13 a 16
  • Patroni: el agente HA que gestiona la elección, replicación y conmutación por error del líder
  • WAL-G: herramienta de copia de seguridad básica y archivado WAL continuo
  • pg_cron, pg_stat_statements, PostGIS: extensiones comúnmente necesarias preinstaladas

Patroni: Elección de líder y conmutación por error automática

Patroni es el corazón del mecanismo HA. Utiliza un almacén de configuración distribuida (DCS) para mantener el estado del clúster y realizar la elección del líder. En el contexto del operador de Zalando, Patroni utiliza el propioKubernetes APIcomo DCS (a través de Endpoints o ConfigMaps), eliminando la necesidad de un etcd externo o un clúster ZooKeeper.

Así es como funciona el proceso de conmutación por error de Patroni:

  1. Verificaciones de estado: cada agente Patroni monitorea continuamente su instancia PostgreSQL local e informa el estado al DCS.
  2. Bloqueo de líder: el principal tiene un bloqueo de líder en el DCS (un objeto de extremo Kubernetes). La cerradura tiene un TTL (por defecto 30 segundos).
  3. Detección de fallas: si el principal no puede renovar su bloqueo dentro del TTL, las réplicas detectan la ausencia.
  4. Elección: las réplicas elegibles compiten por el bloqueo de líder. Gana la réplica con el menor retraso de replicación.
  5. Promoción: la réplica ganadora se promociona a sí misma a primaria, actualiza el DCS y el punto final del servicio Kubernetesmasterse actualiza automáticamente.
  6. Cercado: la antigua primaria está cercada (detenida o degradada a réplica) para evitar la división del cerebro.

Todo este proceso de conmutación por error normalmente se completa en15 a 30 segundos, lo que garantiza un tiempo de inactividad mínimo para sus aplicaciones.

WAL-G: Archivado y Backup Continuo

WAL-G es una herramienta de archivo de próxima generación para PostgreSQL que admite copias de seguridad en S3, Google Cloud Storage (GCS) y Azure Blob Storage. Proporciona:

  • Copias de seguridad básicas: copias de seguridad físicas completas usandopg_basebackup
  • Archivado WAL: envío de registros de escritura anticipada continua para recuperación en un momento dado
  • Copias de seguridad delta: copias de seguridad incrementales que solo almacenan páginas modificadas
  • Cifrado: cifrado AES-256 de copias de seguridad en reposo
  • Compresión: compresión LZ4 o ZSTD para reducir los costos de almacenamiento

Kubernetes Jerarquía de recursos

Cuando crea un recurso personalizadopostgresql, el operador crea un conjunto completo de recursos Kubernetes para administrar el clúster. Comprender esta jerarquía es importante para la resolución de problemas y el monitoreo:

Jerarquía de recursos Kubernetes — Operador de Zalandopostgresql CRDPostgres OperadorConjunto de estadoServicio(maestro)Servicio(réplica)Puntos finalesPDBCápsulasPVCsSecretosImplementación de PgBouncerServicio(agrupador)PrimarioRéplicaRéplicaLíneas continuas = creación directa | Líneas discontinuas = creación condicionalRecursos

creados por el operador

  • StatefulSet: gestiona los pods PostgreSQL con identidades de red estables e implementación ordenada
  • Servicios: dos servicios ClusterIP:<cluster-name>para el principal y<cluster-name>-replpara réplicas de lectura
  • Puntos finales: Patroni actualiza los puntos finales para que apunten al líder actual para una conmutación por error perfecta
  • PodDisruptionBudgets (PDB): garantiza que al menos una instancia permanezca disponible durante interrupciones voluntarias
  • Secrets: credenciales de superusuario, replicación y aplicación de PostgreSQL almacenadas como Kubernetes Secrets
  • PersistentVolumeClaims (PVCs): un PVC por pod para PostgreSQL almacenamiento de datos
  • Implementación de PgBouncer: agrupador de conexiones opcional implementado como una implementación separada con su propio servicio
Instalación de

en múltiples plataformas Kubernetes

Requisitos previos

Antes de instalar el operador Zalando Postgres, asegúrese de tener:

  • Un clúster Kubernetes en ejecución (v1.25+)
  • kubectlconfigurado con acceso de administrador del clúster
  • helmv3 instalado
  • Un StorageClass predeterminado configurado
Instalación del operador

a través de Helm

El método de instalación recomendado utiliza Helm. Esto funciona de manera consistente en todas las plataformas Kubernetes:

# Add the Zalando Postgres Operator Helm repository
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator
helm repo add postgres-operator-ui-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator-ui
helm repo update

# Create a dedicated namespace
kubectl create namespace postgres-operator

# Install the operator with custom values
helm install postgres-operator postgres-operator-charts/postgres-operator \
  --namespace postgres-operator \
  --set configKubernetes.enable_pod_antiaffinity=true \
  --set configKubernetes.pod_environment_configmap=postgres-pod-config \
  --set configAwsOrGcp.aws_region=us-east-1 \
  --set configLoadBalancer.db_hosted_zone=db.example.com \
  --set configConnectionPooler.connection_pooler_default_cpu_request=500m \
  --set configConnectionPooler.connection_pooler_default_memory_request=100Mi

# Optionally install the operator UI for visual management
helm install postgres-operator-ui postgres-operator-ui-charts/postgres-operator-ui \
  --namespace postgres-operator

Verifique que el operador esté ejecutando:

kubectl get pods -n postgres-operator
# Expected output:
# NAME                                 READY   STATUS    RESTARTS   AGE
# postgres-operator-7f8b9c6d4-x2k9j   1/1     Running   0          2m

AWS Especificaciones de implementación de EKS

Amazon EKS requiere una configuración específica para un rendimiento óptimo de PostgreSQL:

# EKS-specific Helm values (eks-values.yaml)
configAwsOrGcp:
  aws_region: us-east-1
  enable_ebs_gp3_migration: true
  additional_secret_mount: "aws-iam-token"

configKubernetes:
  enable_pod_antiaffinity: true
  pod_environment_configmap: "postgres-pod-config"
  spilo_privileged: false
  storage_resize_mode: pvc

# Use EBS gp3 StorageClass for better performance
# Create the StorageClass first:
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-gp3-postgres
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iops: "6000"
  throughput: "400"
  encrypted: "true"
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

Para copias de seguridad WAL-G en EKS, configure roles de IAM para cuentas de servicio (IRSA):

# Create IAM policy for WAL-G S3 access
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:DeleteObject",
        "s3:GetBucketLocation"
      ],
      "Resource": [
        "arn:aws:s3:::my-pg-backups",
        "arn:aws:s3:::my-pg-backups/*"
      ]
    }
  ]
}

Azure Implementación de AKS

Azure AKS utiliza el disco Azure para almacenamiento persistente y la identidad administrada para autenticación de respaldo:

# AKS-specific StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-premium-postgres
provisioner: disk.csi.azure.com
parameters:
  skuName: Premium_LRS
  cachingMode: ReadOnly
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
---
# WAL-G backup to Azure Blob Storage environment variables
apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-pod-config
  namespace: default
data:
  AZURE_STORAGE_ACCOUNT: "pgbackupsstorage"
  AZURE_STORAGE_ACCESS_KEY: "" # Use Managed Identity instead
  WALG_AZ_PREFIX: "azure://pg-wal-backups/$(SCOPE)"
  USE_WALG_BACKUP: "true"
  USE_WALG_RESTORE: "true"
  BACKUP_SCHEDULE: "0 2 * * *"
  BACKUP_NUM_TO_RETAIN: "7"

Implementación de Google GKE

El motor Google Kubernetes utiliza un disco persistente y una identidad de carga de trabajo para el acceso a la copia de seguridad de GCS:

# GKE StorageClass for SSD Persistent Disks
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ssd-postgres
provisioner: pd.csi.storage.gke.io
parameters:
  type: pd-ssd
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
---
# GCS backup configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-pod-config
  namespace: default
data:
  WALG_GS_PREFIX: "gs://my-pg-backups/$(SCOPE)"
  USE_WALG_BACKUP: "true"
  USE_WALG_RESTORE: "true"
  GOOGLE_APPLICATION_CREDENTIALS: "/var/secrets/google/key.json"
  BACKUP_SCHEDULE: "0 2 * * *"
  BACKUP_NUM_TO_RETAIN: "7"

Bare Metal k3s/Rancher con almacenamiento Longhorn

Para implementaciones locales, k3s proporciona una distribución Kubernetes liviana y Longhorn ofrece almacenamiento en bloques distribuido. Esta combinación es ideal cuando necesita control total sobre su infraestructura sin depender de un proveedor de nube.

# Install k3s on all nodes
# Master node:
curl -sfL https://get.k3s.io | sh -s - server \
  --cluster-init \
  --disable traefik \
  --write-kubeconfig-mode 644

# Worker nodes:
curl -sfL https://get.k3s.io | sh -s - agent \
  --server https://master-ip:6443 \
  --token $(cat /var/lib/rancher/k3s/server/node-token)

# Install Longhorn for persistent storage
helm repo add longhorn https://charts.longhorn.io
helm install longhorn longhorn/longhorn \
  --namespace longhorn-system \
  --create-namespace \
  --set defaultSettings.defaultReplicaCount=3 \
  --set defaultSettings.defaultDataPath=/mnt/longhorn

# Install MetalLB for LoadBalancer services
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml

# Configure MetalLB IP pool
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: postgres-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.200-192.168.1.210
k3s / Implementación de metal desnudo RancherServidor de gestión ganaderoNodo 1 (servidor k3s)PostgreSQL PrimarioSpilo + PatroniOperador ZalandoPiscina PgBouncerVolumen de bocina larga/mnt/longhorn (3 réplicas)Nodo 2 (servidor k3s)PostgreSQL RéplicaSpilo + PatroniPiscina PgBouncerPrometheus ExportadorVolumen de bocina larga/mnt/longhorn (3 réplicas)Nodo 3 (agente k3s)PostgreSQL RéplicaSpilo + PatroniPiscina PgBouncerGrafana TableroVolumen de bocina larga/mnt/longhorn (3 réplicas)HAProxy/MetalLB LoadBalancerCopias de seguridad WAL-GCompatible con NFS / MinIO S3PrimarioRéplicaPgBouncerBocina largaReplicación de transmisión

PostgreSQL Clúster CRD Especificación

El núcleo de la implementación de un El clúster PostgreSQL con el operador Zalando es el recurso personalizadopostgresql. Este manifiesto YAML declara el estado deseado de su clúster y el operador lo concilia con la realidad. A continuación se muestra una especificación CRD completa y lista para producción:

apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
  name: pg-production-cluster
  namespace: databases
  labels:
    team: platform
    environment: production
spec:
  teamId: "platform"
  volume:
    size: 100Gi
    storageClass: ebs-gp3-postgres
  numberOfInstances: 3
  enableConnectionPooler: true
  enableReplicaConnectionPooler: true
  connectionPooler:
    numberOfInstances: 2
    mode: transaction
    schema: pooler
    user: pooler
    resources:
      requests:
        cpu: 500m
        memory: 100Mi
      limits:
        cpu: "1"
        memory: 256Mi
  users:
    app_user:
    - superuser
    - createdb
    readonly_user: []
  databases:
    app_database: app_user
  postgresql:
    version: "16"
    parameters:
      shared_buffers: "2GB"
      max_connections: "200"
      work_mem: "64MB"
      maintenance_work_mem: "512MB"
      effective_cache_size: "6GB"
      random_page_cost: "1.1"
      effective_io_concurrency: "200"
      wal_buffers: "64MB"
      max_wal_size: "4GB"
      min_wal_size: "1GB"
      checkpoint_completion_target: "0.9"
      default_statistics_target: "100"
      log_statement: "ddl"
      log_min_duration_statement: "1000"
      idle_in_transaction_session_timeout: "600000"
      lock_timeout: "30000"
      statement_timeout: "60000"
  patroni:
    initdb:
      encoding: "UTF8"
      locale: "en_US.UTF-8"
      data-checksums: "true"
    pg_hba:
    - hostssl all all 0.0.0.0/0 md5
    - host    all all 0.0.0.0/0 md5
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    synchronous_mode: false
    synchronous_mode_strict: false
    maximum_lag_on_failover: 33554432
  resources:
    requests:
      cpu: "2"
      memory: 8Gi
    limits:
      cpu: "4"
      memory: 16Gi
  podAnnotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "9187"
  tolerations:
  - key: "database"
    operator: "Equal"
    value: "postgres"
    effect: "NoSchedule"
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: workload-type
          operator: In
          values:
          - database
  enableShmVolume: true
  spiloRunAsUser: 101
  spiloRunAsGroup: 103
  spiloFSGroup: 103

Clave CRD Campos explicados

  • numberOfInstances: número total de pods. El operador designa automáticamente uno como principal y el resto como réplicas de streaming.
  • enableConnectionPooler: implementa el sidecar PgBouncer para el servicio principal, lo que reduce la sobrecarga de conexión.
  • enableReplicaConnectionPooler: implementa un PgBouncer independiente para el servicio de réplica, esencial para cargas de trabajo de lectura intensa.
  • postgresql.parameters: parámetros de configuración directos de PostgreSQL pasados apostgresql.conf.
  • patrones: configura el comportamiento de Patroni, incluido TTL, espera de bucle, tiempo de espera de reintento y modo de replicación sincrónica.
  • volume.storageClass: se asigna a la StorageClass específica de la plataforma (EBS gp3 en AWS, Premium SSD en Azure, SSD PD en GCP, Longhorn en k3s).
  • enableShmVolume: monta untmpfsen/dev/shmpara la memoria compartida PostgreSQL, fundamental para el rendimiento.
Agrupación de conexiones

con PgBouncer

El modelo de proceso por conexión de

PostgreSQL hace que sea costoso manejar una gran cantidad de conexiones de clientes. Cada conexión consume aproximadamente 10 MB de RAM. PgBouncer resuelve esto multiplexando miles de conexiones de clientes en un pequeño grupo de conexiones PostgreSQL reales.

El operador Zalando admite de forma nativa la implementación de PgBouncer. Cuando configuraenableConnectionPooler: trueen el CRD, el operador crea:

  • Una implementación de PgBouncer con recuento de réplicas configurable
  • Un servicio dedicado (<cluster-name>-pooler) para conexiones agrupadas
  • Sincronización automática de credenciales con PostgreSQL

Modos de configuración de PgBouncer

# PgBouncer connection pooler modes:
#
# transaction (recommended for most workloads)
#   - Connection returned to pool after each transaction
#   - Best balance of efficiency and compatibility
#   - Cannot use session-level features (prepared statements, temp tables)
#
# session
#   - Connection held for entire client session
#   - Full PostgreSQL compatibility
#   - Lower pooling efficiency
#
# statement
#   - Connection returned after each statement
#   - Most efficient but most restrictive
#   - Only works with autocommit queries

# Custom PgBouncer configuration via operator
spec:
  connectionPooler:
    numberOfInstances: 3
    mode: transaction
    schema: pooler
    user: pooler
    defaultPoolSize: 25
    maxDBConnections: 100
    resources:
      requests:
        cpu: 250m
        memory: 128Mi
      limits:
        cpu: "1"
        memory: 256Mi

Para aplicaciones que necesitan declaraciones preparadas o funciones a nivel de sesión, conéctese directamente a los servicios PostgreSQL sin pasar por PgBouncer o utilice el modo de agrupaciónsessioncon la desventaja de una menor eficiencia de conexión.

Replicación PostgreSQL multirregional

Para aplicaciones globales que requieren lecturas de baja latencia desde múltiples ubicaciones geográficas o recuperación ante desastres entre regiones, la replicación multirregional es esencial. El operador de Zalando admite esto a través de clústeres en espera que se replican desde un clúster primario mediante replicación de transmisión o archivos WAL-G.

Replicación de transmisión PostgreSQL multirregionalEE.UU.-ESTE-1 (AWS EKS)CLÚSTER PRIMARIOpg-prod-us (3 cápsulas)PrimarioRéplicaReplicación de sincronización dentro de AZWAL-G → S3 (continuo)Agrupador PgBouncerUE-OESTE-1 (Azure AKS)Clúster de esperapg-standby-eu (2 módulos)En esperaRéplicaReplicación en cascadaWAL-G → Azure BlobPgBouncer (solo lectura)AP-SURESTE (GCP GKE)Clúster de esperapg-standby-ap (2 módulos)En esperaRéplicaReplicación en cascadaWAL-G → Cucharón GCSPgBouncer (solo lectura)ASINCRÍNICOASYNC (envío WAL)Topología de replicaciónPrimario (EE.UU.-ESTE) → Transmisión asíncrona a UE-OESTE y Europa. Clústeres de reserva AP-SURESTE | RPO: ~segundos | RTO: <5 min con promoción manualReplicación de sincronizaciónReplicación asíncronaPrimarioLíder en esperaLeer réplicaConfiguración de replicación de transmisión por secuencias

La replicación de streaming

PostgreSQL es la base de HA en el operador Zalando. Funciona enviando registros de registro de escritura anticipada (WAL) desde el principal a las réplicas casi en tiempo real. El operador configura esto automáticamente, pero comprender los detalles ayuda con el ajuste y la resolución de problemas.

  • Replicación síncrona: el principal espera a que al menos una réplica confirme la recepción de WAL antes de confirmar una transacción. Esto garantiza cero pérdida de datos (RPO=0) pero agrega latencia. Habilitar conpatroni.synchronous_mode: true.
  • Replicación asincrónica: el principal se confirma inmediatamente y envía WAL de forma asincrónica. Latencia ligeramente menor pero posible pérdida de datos durante la conmutación por error. Este es el valor predeterminado.
  • Replicación en cascada: las réplicas se pueden replicar desde otras réplicas en lugar de desde la principal, lo que reduce la carga en la principal en clústeres grandes.
# Enable synchronous replication for zero data loss
spec:
  patroni:
    synchronous_mode: true
    synchronous_mode_strict: false  # Allow async if no sync replica available
    synchronous_node_count: 1       # Number of sync replicas required
  postgresql:
    parameters:
      synchronous_commit: "on"      # Matches Patroni synchronous_mode
      max_wal_senders: "10"         # Maximum WAL sender processes
      wal_keep_size: "1GB"          # WAL retention for replica catch-up
      hot_standby: "on"             # Allow queries on replicas
      hot_standby_feedback: "on"    # Reduce query conflicts on replicas
Copia de seguridad y recuperación de

con WAL-G

Configuración de copia de seguridad WAL-G

La configuración adecuada de la copia de seguridad es fundamental para la recuperación ante desastres. El operador de Zalando integra WAL-G para realizar copias de seguridad continuas en el almacenamiento de objetos. Aquí hay una configuración completa para almacenamiento compatible con S3:

# ConfigMap for WAL-G backup configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-pod-config
  namespace: databases
data:
  # S3 backup configuration
  AWS_ENDPOINT: "https://s3.us-east-1.amazonaws.com"
  AWS_S3_FORCE_PATH_STYLE: "false"
  AWS_REGION: "us-east-1"
  WALG_S3_PREFIX: "s3://my-pg-backups/$(SCOPE)"
  WALG_DISABLE_S3_SSE: "false"
  WALG_S3_SSE: "aws:kms"
  WALG_S3_SSE_KMS_ID: "arn:aws:kms:us-east-1:123456789:key/mrk-abcdef"

  # Backup scheduling and retention
  USE_WALG_BACKUP: "true"
  USE_WALG_RESTORE: "true"
  BACKUP_SCHEDULE: "0 1 * * *"       # Daily at 1 AM UTC
  BACKUP_NUM_TO_RETAIN: "14"          # Keep 14 daily backups

  # WAL archiving
  WALG_COMPRESSION_METHOD: "zstd"     # Better compression than lz4
  WALG_DELTA_MAX_STEPS: "6"           # Delta backups between full backups
  WALG_UPLOAD_CONCURRENCY: "4"        # Parallel upload streams
  WALG_DOWNLOAD_CONCURRENCY: "4"      # Parallel download for restore
  WALG_UPLOAD_DISK_CONCURRENCY: "4"   # Disk read concurrency

  # Clone configuration
  CLONE_AWS_ENDPOINT: "https://s3.us-east-1.amazonaws.com"
  CLONE_AWS_REGION: "us-east-1"
  CLONE_WALG_S3_PREFIX: "s3://my-pg-backups/$(CLONE_SCOPE)"
  CLONE_METHOD: "CLONE_WITH_WALG"
  CLONE_USE_WALG_RESTORE: "true"

Recuperación de un punto en el tiempo (PITR)

PITR le permite restaurar su base de datos en cualquier momento específico, algo fundamental para recuperarse de una eliminación o corrupción accidental de datos. El operador de Zalando soporta PITR mediante el mecanismo de clonación:

# Clone a cluster with PITR
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
  name: pg-restored-cluster
  namespace: databases
spec:
  teamId: "platform"
  volume:
    size: 100Gi
    storageClass: ebs-gp3-postgres
  numberOfInstances: 3
  postgresql:
    version: "16"
  clone:
    cluster: "pg-production-cluster"
    timestamp: "2026-04-11T14:30:00+00:00"  # Restore to this exact moment
    s3_wal_path: "s3://my-pg-backups/wal/16/pg-production-cluster"
    s3_endpoint: "https://s3.us-east-1.amazonaws.com"
    s3_access_key_id: ""      # Use IAM role instead
    s3_secret_access_key: ""  # Use IAM role instead

Cuando se aplica este CRD, el operador realiza los siguientes pasos:

  1. Encuentra la última copia de seguridad base antes de la marca de tiempo de destino
  2. Restaura la copia de seguridad base en el pod principal del nuevo StatefulSet
  3. Reproduce segmentos WAL hasta la marca de tiempo especificada
  4. Abre la base de datos para operaciones de lectura y escritura
  5. Configura la replicación de transmisión en los pods de réplica

Clúster en espera para recuperación ante desastres

Un clúster en espera se replica continuamente desde un clúster primario, lo que proporciona un respaldo activo que se puede promover durante un desastre. Esto es diferente de las réplicas dentro de un clúster: un clúster en espera es un recurso Kubernetes completamente independiente que puede ejecutarse en un espacio de nombres, clúster o incluso región diferente.

# Standby cluster in a different region
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
  name: pg-standby-eu
  namespace: databases
spec:
  teamId: "platform"
  volume:
    size: 100Gi
    storageClass: managed-premium-postgres
  numberOfInstances: 2
  postgresql:
    version: "16"
  standby:
    standby_host: "pg-production-cluster.databases.svc.cluster.local"
    standby_port: "5432"
    # Alternative: replicate from S3 WAL archive
    # s3_wal_path: "s3://my-pg-backups/wal/16/pg-production-cluster"
  enableConnectionPooler: true
  enableReplicaConnectionPooler: true

Para promover un clúster en espera a primario independiente (durante la recuperación ante desastres), simplemente elimine la secciónstandbydel CRD y aplique:

# Edit the standby cluster CRD to remove standby section
kubectl patch postgresql pg-standby-eu -n databases --type json \
  -p '[{"op": "remove", "path": "/spec/standby"}]'

# The operator will promote the standby to primary
# Update your application DNS/service mesh to point to the new primary
Monitoreo

con Prometheus y Grafana

El monitoreo integral no es negociable para implementaciones de producción PostgreSQL. El operador de Zalando admite la exportación de métricas Prometheus a través del sidecarpostgres_exporter. A continuación se explica cómo configurar una pila de monitoreo completa:

Monitor de servicio

para Prometheus

# ServiceMonitor for PostgreSQL metrics
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: postgres-monitor
  namespace: databases
  labels:
    team: platform
    release: prometheus
spec:
  selector:
    matchLabels:
      team: platform
  namespaceSelector:
    matchNames:
    - databases
  endpoints:
  - port: exporter
    interval: 15s
    scrapeTimeout: 10s
    path: /metrics
    relabelings:
    - sourceLabels: [__meta_kubernetes_pod_label_spilo_role]
      targetLabel: role
    - sourceLabels: [__meta_kubernetes_pod_label_cluster_name]
      targetLabel: cluster
---
# PodMonitor alternative (scrapes pods directly)
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: postgres-pod-monitor
  namespace: databases
spec:
  selector:
    matchLabels:
      application: spilo
  podMetricsEndpoints:
  - port: exporter
    interval: 15s
    path: /metrics
Métricas clave de

para monitorear

Estas son las métricas de PostgreSQL más importantes para realizar un seguimiento en sus paneles de Grafana:

  • pg_stat_replication_lag: retraso de replicación en bytes y segundos. Alerta si el retraso excede su umbral de RPO.
  • pg_stat_activity_count: conexiones activas por estado. Alerta sobre agotamiento del grupo de conexiones.
  • pg_stat_database_tup_fetched/returned/inserted/updated/deleted: consultar métricas de rendimiento.
  • pg_stat_bgwriter_buffers_checkpoint/clean/backend: eficiencia de la gestión del búfer.
  • pg_database_size_bytes: crecimiento del tamaño de la base de datos a lo largo del tiempo para la planificación de capacidad.
  • pg_locks_count— Contención de bloqueo. Alerta sobre espera excesiva de cerraduras.
  • pg_stat_statements_calls/mean_time: consulta estadísticas de rendimiento para optimización.
  • patroni_postgres_running: estado de salud de Patroni (1 = en ejecución, 0 = inactivo).
  • patroni_master: qué pod es el principal actual (1 = maestro, 0 = réplica).
  • pg_up: sonda de disponibilidad básica PostgreSQL.

Reglas de alerta

# PrometheusRule for PostgreSQL alerts
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: postgres-alerts
  namespace: databases
spec:
  groups:
  - name: postgresql.rules
    rules:
    - alert: PostgreSQLDown
      expr: pg_up == 0
      for: 1m
      labels:
        severity: critical
      annotations:
        summary: "PostgreSQL instance {{ $labels.instance }} is down"
    - alert: PostgreSQLReplicationLag
      expr: pg_stat_replication_pg_wal_lsn_diff > 100000000
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "Replication lag is {{ $value }} bytes on {{ $labels.instance }}"
    - alert: PostgreSQLHighConnections
      expr: sum(pg_stat_activity_count) by (instance) > 180
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "{{ $value }} active connections on {{ $labels.instance }}"
    - alert: PostgreSQLDeadlocks
      expr: rate(pg_stat_database_deadlocks[5m]) > 0
      for: 1m
      labels:
        severity: warning
      annotations:
        summary: "Deadlocks detected on {{ $labels.datname }}"
    - alert: PatroniFailover
      expr: changes(patroni_master[5m]) > 0
      labels:
        severity: critical
      annotations:
        summary: "Patroni failover occurred in cluster {{ $labels.cluster }}"
Guía de ajuste de producción de

El ajuste adecuado es esencial para extraer el máximo rendimiento de PostgreSQL en Kubernetes. Los siguientes parámetros deben ajustarse según los límites de recursos de su pod y las características de la carga de trabajo.

Configuración de memoria

# For a pod with 16GB memory limit:
postgresql:
  parameters:
    # shared_buffers: 25% of total memory
    shared_buffers: "4GB"

    # effective_cache_size: 75% of total memory
    # (tells planner how much OS cache to expect)
    effective_cache_size: "12GB"

    # work_mem: shared_buffers / (max_connections * 2)
    # Conservative to prevent OOM
    work_mem: "10MB"

    # maintenance_work_mem: 5-10% of total memory
    # Used for VACUUM, CREATE INDEX, ALTER TABLE
    maintenance_work_mem: "1GB"

    # temp_buffers: memory for temp tables per session
    temp_buffers: "32MB"

    # huge_pages: try to use huge pages (requires OS config)
    huge_pages: "try"

Configuración de WAL y punto de control

postgresql:
  parameters:
    # WAL settings
    wal_buffers: "64MB"           # 1/32 of shared_buffers, max 64MB
    wal_compression: "zstd"        # Compress WAL (PG 15+)
    max_wal_size: "8GB"            # Before forced checkpoint
    min_wal_size: "2GB"            # WAL disk reservation
    wal_level: "replica"           # Required for replication

    # Checkpoint settings
    checkpoint_completion_target: "0.9"  # Spread I/O over 90% of interval
    checkpoint_timeout: "15min"          # Max time between checkpoints

Planificador de consultas y E/S

postgresql:
  parameters:
    # Cost parameters for SSD storage
    random_page_cost: "1.1"          # SSD: close to seq_page_cost
    seq_page_cost: "1.0"             # Sequential I/O baseline
    effective_io_concurrency: "200"   # Concurrent I/O for SSD

    # Planner behavior
    default_statistics_target: "200"  # More accurate statistics
    from_collapse_limit: 12           # JOIN planning threshold
    join_collapse_limit: 12           # JOIN planning threshold

    # Parallel queries
    max_parallel_workers_per_gather: "4"
    max_parallel_workers: "8"
    max_parallel_maintenance_workers: "4"
    parallel_tuple_cost: "0.01"
    parallel_setup_cost: "1000"
Conexión y registro

postgresql:
  parameters:
    # Connection limits
    max_connections: "200"                   # Keep low, use PgBouncer
    superuser_reserved_connections: "5"       # Reserve for admin access

    # Logging for troubleshooting
    log_statement: "ddl"                     # Log DDL statements
    log_min_duration_statement: "500"         # Log queries > 500ms
    log_checkpoints: "on"                    # Log checkpoint activity
    log_connections: "off"                   # Too noisy in production
    log_disconnections: "off"                # Too noisy in production
    log_lock_waits: "on"                     # Log lock waits
    log_temp_files: "0"                      # Log all temp file usage
    log_autovacuum_min_duration: "1000"       # Log slow autovacuum

    # Statement timeouts
    statement_timeout: "60000"               # 60 second query timeout
    lock_timeout: "30000"                    # 30 second lock timeout
    idle_in_transaction_session_timeout: "600000"  # 10 min idle txn timeout

Actualizaciones continuas y actualizaciones de versión

Actualizaciones de la versión menor de

El operador maneja automáticamente las actualizaciones de versiones menores (por ejemplo, 16.2 a 16.3) cuando actualiza la etiqueta de imagen de Spilo. El operador realiza un reinicio continuo:

# Update the operator configuration to use a new Spilo image
helm upgrade postgres-operator postgres-operator-charts/postgres-operator \
  --namespace postgres-operator \
  --set configGeneral.docker_image=ghcr.io/zalando/spilo-16:3.1-p1 \
  --reuse-values

# The operator will perform rolling updates:
# 1. Restart replicas one at a time
# 2. Failover the primary to a freshly updated replica
# 3. Restart the old primary (now a replica)
Actualizaciones de la versión principal de

Las actualizaciones de versiones principales (por ejemplo, PostgreSQL 15 a 16) requieren una planificación más cuidadosa. El operador de Zalando admite actualizaciones importantes in situ mediantepg_upgrade:

# Step 1: Update the CRD to the new major version
spec:
  postgresql:
    version: "16"  # Changed from "15"

# Step 2: The operator detects the version change and:
# a) Scales down the StatefulSet to 1 replica
# b) Runs pg_upgrade on the primary pod
# c) Scales back up to the desired numberOfInstances
# d) Replicas are rebuilt from the upgraded primary

# Step 3: Verify the upgrade
kubectl exec -it pg-production-cluster-0 -n databases -- \
  su postgres -c "psql -c 'SELECT version()'"

# Step 4: Run ANALYZE to update statistics after upgrade
kubectl exec -it pg-production-cluster-0 -n databases -- \
  su postgres -c "psql -c 'ANALYZE VERBOSE'"

Consideraciones importantes para actualizaciones importantes:

  • Realice siempre una copia de seguridad nueva antes de actualizar
  • Pruebe primero la actualización en un clúster clonado
  • Las actualizaciones importantes requieren tiempo de inactividad (normalmente entre 5 y 30 minutos, dependiendo del tamaño de la base de datos)
  • Revise las notas de la versión PostgreSQL para conocer los cambios importantes
  • Supervise el retraso de replicación de cerca después de la reconstrucción de la réplica
  • EjecuteANALYZEen todas las bases de datos para regenerar las estadísticas del planificador de consultas

Patrones operativos avanzados

Copias de seguridad lógicas

Además de las copias de seguridad físicas WAL-G, el operador admite copias de seguridad lógicas utilizandopg_dump. Las copias de seguridad lógicas son útiles para migraciones entre versiones y restauraciones selectivas de tablas:

# Enable logical backups in the operator configuration
helm upgrade postgres-operator postgres-operator-charts/postgres-operator \
  --namespace postgres-operator \
  --set configLogicalBackup.logical_backup_schedule="0 3 * * *" \
  --set configLogicalBackup.logical_backup_s3_bucket="my-pg-logical-backups" \
  --set configLogicalBackup.logical_backup_s3_region="us-east-1" \
  --set configLogicalBackup.logical_backup_s3_sse="AES256" \
  --reuse-values

# The operator creates a CronJob for each cluster that:
# 1. Connects to the primary PostgreSQL instance
# 2. Runs pg_dumpall (or pg_dump per database)
# 3. Compresses and uploads to S3

Variables de entorno de pod personalizadas

Puede inyectar variables de entorno en pods de Spilo utilizando un ConfigMap. Esto es útil para configurar WAL-G, scripts personalizados o ajustar parámetros a nivel del sistema operativo:

apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-pod-config
  namespace: databases
data:
  # Custom Spilo configurations
  SPILO_CONFIGURATION: |
    bootstrap:
      dcs:
        ttl: 30
        loop_wait: 10
        retry_timeout: 10
        maximum_lag_on_failover: 33554432
        postgresql:
          use_pg_rewind: true
          use_slots: true
          parameters:
            archive_mode: "on"
            archive_timeout: 1800s
  # Enable pg_stat_statements
  POSTGRESQL_SHARED_PRELOAD_LIBRARIES: "bg_mon,pg_stat_statements,pgextwlist,pg_auth_mon,set_user,timescaledb,pg_cron,pg_stat_kcache"
  # Cron jobs inside PostgreSQL
  ENABLE_PG_CRON: "true"

Políticas de red para seguridad

En producción, restrinja el acceso a la red a los pods PostgreSQL usando Kubernetes NetworkPolicies:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: postgres-network-policy
  namespace: databases
spec:
  podSelector:
    matchLabels:
      application: spilo
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: app-namespace
    - podSelector:
        matchLabels:
          app: backend
    ports:
    - protocol: TCP
      port: 5432
    - protocol: TCP
      port: 8008   # Patroni REST API
  - from:
    - namespaceSelector:
        matchLabels:
          name: monitoring
    ports:
    - protocol: TCP
      port: 9187   # Prometheus exporter
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
    ports:
    - protocol: TCP
      port: 443    # S3/GCS/Azure for backups

Solución de problemas problemas comunes

Incluso con la automatización, surgen problemas. A continuación se detallan los problemas más comunes y sus soluciones al ejecutar PostgreSQL con el operador Zalando:

1. Pod atascado en estado pendiente

# Check events for the pod
kubectl describe pod pg-production-cluster-0 -n databases

# Common causes:
# - No nodes with matching tolerations/affinity
# - Insufficient CPU or memory on nodes
# - PVC cannot be provisioned (check StorageClass)

# Fix: Check node resources and storage availability
kubectl get nodes -o custom-columns=NAME:.metadata.name,CPU:.status.allocatable.cpu,MEM:.status.allocatable.memory
kubectl get pvc -n databases

2. Retraso de replicación creciente

# Check replication status on the primary
kubectl exec -it pg-production-cluster-0 -n databases -- \
  su postgres -c "psql -c 'SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, write_lag, flush_lag, replay_lag FROM pg_stat_replication'"

# Common causes:
# - Replica CPU/IO saturation
# - Network bandwidth limits
# - Long-running queries on replica blocking WAL replay
# - Insufficient wal_keep_size

# Fix: Check replica resources and cancel blocking queries
kubectl exec -it pg-production-cluster-1 -n databases -- \
  su postgres -c "psql -c 'SELECT pg_cancel_backend(pid) FROM pg_stat_activity WHERE state = \"active\" AND query_start < now() - interval \"5 minutes\"'"

3. La conmutación por error no activa

# Check Patroni cluster status
kubectl exec -it pg-production-cluster-0 -n databases -- \
  su postgres -c "patronictl list"

# Check Patroni logs
kubectl logs pg-production-cluster-0 -n databases -c postgres | grep -i patroni

# Manual failover (if auto-failover is stuck)
kubectl exec -it pg-production-cluster-0 -n databases -- \
  su postgres -c "patronictl failover --candidate pg-production-cluster-1 --force"

4. Fallos de copia de seguridad

# Check WAL-G backup status
kubectl exec -it pg-production-cluster-0 -n databases -- \
  su postgres -c "envdir /run/etc/wal-e.d/env wal-g backup-list"

# Check backup CronJob logs
kubectl logs -l application=spilo,cluster-name=pg-production-cluster -n databases | grep -i wal-g

# Verify S3/GCS credentials
kubectl exec -it pg-production-cluster-0 -n databases -- \
  su postgres -c "envdir /run/etc/wal-e.d/env aws s3 ls s3://my-pg-backups/"

Mejores prácticas de seguridad

Proteger PostgreSQL en Kubernetes requiere un enfoque de defensa en profundidad:

  • Cifrado TLS: habilite SSL para todas las conexiones de clientes. El operador puede proporcionar certificados automáticamente utilizando cert-manager.
  • Gestión de secretos: utilice secretos Kubernetes (o administradores de secretos externos como Vault) para las credenciales de la base de datos. Nunca almacene contraseñas en ConfigMaps.
  • RBAC: limita los permisos de la cuenta de servicio del operador. Utilice acceso con privilegios mínimos para los usuarios de la base de datos de la aplicación.
  • NetworkPolicies: restrinja la comunicación entre pods como se muestra en la sección anterior.
  • pg_hba.conf: configure la autenticación basada en host para restringir qué IP y usuarios pueden conectarse.
  • Registro de auditoría: habilite la extensiónpgauditpara el registro de auditoría SQL en entornos regulados.
  • Almacenamiento cifrado: utilice StorageClasses cifrados (cifrado EBS, cifrado de disco Azure, etc.).
  • Estándares de seguridad del pod: ejecute los pods de Spilo como no root con contextos de seguridad restringidos.
# Security-hardened CRD settings
spec:
  spiloRunAsUser: 101
  spiloRunAsGroup: 103
  spiloFSGroup: 103
  enableShmVolume: true
  patroni:
    pg_hba:
    - hostssl all all 0.0.0.0/0 md5
    - host    replication standby all md5
    - hostssl replication standby all md5
  postgresql:
    parameters:
      ssl: "on"
      ssl_min_protocol_version: "TLSv1.3"
      password_encryption: "scram-sha-256"
  additionalVolumes:
  - name: postgres-tls
    mountPath: /tls
    secret:
      secretName: pg-tls-cert
      defaultMode: 0640

Planificación de capacidad y dimensionamiento

El tamaño adecuado garantiza un rendimiento estable y rentabilidad. Utilice estas pautas como punto de partida y ajústelas según los datos de monitoreo de su carga de trabajo:

Carga de trabajoMemoriaInstanciasDesarrolloSSD
CPUAlmacenamiento
500m1Gi10Gi1
Pequeña producción2 núcleos8Gi50Gi SSD3
Producción media4 núcleos16Gi200Gi3
Gran producción8 núcleos32Gi500Gi SSD5
Empresa/Análisis16+ núcleos64Gi+1Ti+ SSD5+

Ejemplo completo de implementación de un extremo a otro

Juntemos todo con una implementación completa desde cero en un clúster Kubernetes nuevo:

# Step 1: Create namespace and configure storage
kubectl create namespace databases
kubectl create namespace postgres-operator

# Step 2: Install the Zalando Postgres Operator
helm repo add postgres-operator-charts \
  https://opensource.zalando.com/postgres-operator/charts/postgres-operator
helm repo update

helm install postgres-operator postgres-operator-charts/postgres-operator \
  --namespace postgres-operator \
  --set configKubernetes.enable_pod_antiaffinity=true \
  --set configKubernetes.pod_environment_configmap=databases/postgres-pod-config

# Step 3: Create backup configuration
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-pod-config
  namespace: databases
data:
  USE_WALG_BACKUP: "true"
  USE_WALG_RESTORE: "true"
  WALG_S3_PREFIX: "s3://my-pg-backups/\$(SCOPE)"
  BACKUP_SCHEDULE: "0 1 * * *"
  BACKUP_NUM_TO_RETAIN: "14"
EOF

# Step 4: Deploy the PostgreSQL cluster
kubectl apply -f - <<EOF
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
  name: pg-app-cluster
  namespace: databases
  labels:
    team: platform
spec:
  teamId: "platform"
  volume:
    size: 50Gi
  numberOfInstances: 3
  enableConnectionPooler: true
  enableReplicaConnectionPooler: true
  users:
    app_user:
    - superuser
    - createdb
  databases:
    app_db: app_user
  postgresql:
    version: "16"
    parameters:
      shared_buffers: "2GB"
      work_mem: "64MB"
      effective_cache_size: "6GB"
  resources:
    requests:
      cpu: "2"
      memory: 8Gi
    limits:
      cpu: "4"
      memory: 16Gi
EOF

# Step 5: Wait for cluster readiness
kubectl wait --for=condition=Running postgresql/pg-app-cluster \
  -n databases --timeout=300s

# Step 6: Verify cluster status
kubectl get postgresql -n databases
kubectl get pods -n databases -l cluster-name=pg-app-cluster
kubectl get svc -n databases -l cluster-name=pg-app-cluster

# Step 7: Get connection credentials
export PGPASSWORD=$(kubectl get secret app-user.pg-app-cluster.credentials.postgresql.acid.zalan.do \
  -n databases -o jsonpath='{.data.password}' | base64 -d)

# Step 8: Connect and verify
kubectl run pg-client --rm -it --image=postgres:16 -n databases -- \
  psql -h pg-app-cluster-pooler -U app_user -d app_db -c "SELECT version();"

Conclusión

El operador Zalando Postgres transforma PostgreSQL en Kubernetes de un desafío operativo complejo a una implementación automatizada y manejable. Al aprovechar Patroni para una conmutación por error basada en consenso, Spilo para una imagen de contenedor con baterías incluidas, WAL-G para respaldo y recuperación continuos y PgBouncer para una agrupación de conexiones eficiente, obtiene una plataforma de base de datos de nivel de producción que funciona de manera consistente en los clústeres AWS EKS, Azure AKS, Google GKE y k3s bare-metal.

Las conclusiones clave de esta guía son:

  • Automatice todo: permita que el operador se encargue de la administración de StatefulSet, la conmutación por error y la programación de copias de seguridad. La intervención manual debería ser la excepción.
  • Monitoreo agresivo: implemente Prometheus y Grafana desde el primer día. El retraso en la replicación, el recuento de conexiones y la contención de bloqueos son sus primeras señales de advertencia.
  • Planifique ante desastres: configure copias de seguridad WAL-G, pruebe PITR periódicamente y mantenga un clúster en espera para cargas de trabajo críticas.
  • Ajuste para su carga de trabajo: los parámetros predeterminados de PostgreSQL son conservadores. Ajuste las configuraciones de Shared_buffers, work_mem y checkpoint según su asignación de recursos y patrones de consulta.
  • Seguro de forma predeterminada: habilite TLS, utilice la autenticación SCRAM-SHA-256, restrinja el acceso a la red y cifre el almacenamiento en reposo.
  • Pruebe las actualizaciones: clone siempre su clúster y pruebe las actualizaciones de versiones principales antes de aplicarlas a producción.

Con esta base integral, está bien equipado para implementar y operar clústeres PostgreSQL de alta disponibilidad en cualquier plataforma Kubernetes, sirviendo aplicaciones que exigen confiabilidad, rendimiento e integridad de datos a escala.