PostgreSQL Hoge beschikbaarheid met Zalando Postgres Operator: Multi-Cloud Kubernetes implementatiehandleiding
Implementeer PostgreSQL HA van productiekwaliteit met Zalando Operator op elk Kubernetes-platform
Introductie: waarom PostgreSQL hoge beschikbaarheid op Kubernetes belangrijk is voor
Het draaien van PostgreSQL in productie vereist een hoge beschikbaarheid (HA). Downtime, gemeten in minuten, kan bedrijven miljoenen dollars aan omzetverlies kosten, het vertrouwen van klanten ondermijnen en overeenkomsten inzake serviceniveau schenden. Kubernetes is het de facto platform geworden voor het orkestreren van gecontaineriseerde workloads, maar het uitvoeren van stateful services zoals PostgreSQL op Kubernetes brengt unieke uitdagingen met zich mee: persistent opslagbeheer, verkiezing van leiders, automatische failover, back-uporkestratie en pooling van verbindingen.
DeZalando Postgres Operatoris een open-source, beproefde oplossing die Zalando, Europa's grootste online moderetailer, heeft gebouwd om honderden PostgreSQL-clusters in productie te beheren. Het maakt gebruik vanPatronivoor op consensus gebaseerde verkiezing van leiders,Spiloals de PostgreSQL-containerimage,WAL-Gvoor continue archivering en herstel op een bepaald tijdstip, enPgBouncervoor het poolen van verbindingen. Samen leveren deze componenten een volledig geautomatiseerde, zelfherstellende PostgreSQL-implementatie die werkt in elke Kubernetes-distributie: van beheerde cloudservices zoals AWS EKS, Azure AKS en Google GKE tot bare-metal clusters met k3s met Rancher.
In deze uitgebreide gids verkennen we de architectuur van de Zalando Postgres Operator, lopen we door de installatie en configuratie op meerdere Kubernetes-platforms, duiken we diep in replicatie, back-ups, noodherstel, monitoring en productie-afstemming. Aan het einde beschikt u over de kennis om PostgreSQL HA-clusters van productiekwaliteit te implementeren en te bedienen op elke Kubernetes-infrastructuur.
Zalando Postgres Operatorarchitectuur
Het begrijpen van de architectuur is essentieel voordat u het implementeert. De Zalando Postgres Operator volgt het Kubernetes-operatorpatroon: hij let op Custom Resource Definitions (CRDs) van het typepostgresqlen stemt de gewenste status af op daadwerkelijke Kubernetes-bronnen. Hier ziet u hoe de componenten in elkaar passen:
Spilo: de PostgreSQL-containerafbeelding
Spilois Zalando's Docker-image die PostgreSQL bundelt met Patroni, WAL-G en essentiële extensies. Elke pod in de StatefulSet voert een Spilo-container uit. Spilohandvatten:
- PostgreSQL-server— de database-engine zelf, die versies 13 tot en met 16 ondersteunt
- Patroni— de HA-agent die de verkiezing, replicatie en failover van leiders beheert
- WAL-G— continue WAL-archiverings- en basisback-uptool
- pg_cron, pg_stat_statements, PostGIS— veelgebruikte extensies vooraf geïnstalleerd
Patroni: Leiderverkiezing en automatische failover
Patroni is het hart van het HA-mechanisme. Het maakt gebruik van een Distributed Configuration Store (DCS) om de clusterstatus te behouden en leidersverkiezingen uit te voeren. In de Zalando-operatorcontext gebruikt Patroni deKubernetes APIzelf als DCS (via Endpoints of ConfigMaps), waardoor er geen externe etcd- of ZooKeeper-cluster nodig is.
Hier ziet u hoe Patroni's failover-proces werkt:
- Gezondheidscontroles— Elke Patroni-agent bewaakt voortdurend zijn lokale PostgreSQL-instantie en rapporteert de status aan de DCS.
- Leader lock— De primaire bevat een leader lock in de DCS (een Kubernetes Endpoint-object). Het slot heeft een TTL (standaard 30 seconden).
- Foutdetectie— Als de primaire er niet in slaagt zijn vergrendeling binnen de TTL te vernieuwen, detecteren replica's de afwezigheid.
- Verkiezing— In aanmerking komende replica's strijden om het leidersslot. De replica met de minste replicatievertraging wint.
- Promotie— De winnende replica promoveert zichzelf naar primair, werkt de DCS bij en het Kubernetes
masterService-eindpunt wordt automatisch bijgewerkt. - Schermen— De oude primaire is omheind (gestopt of gedegradeerd tot replica) om gespleten hersenen te voorkomen.
Dit volledige failover-proces wordt doorgaans voltooid in15-30 seconden, waardoor minimale downtime voor uw applicaties wordt gegarandeerd.
WAL-G: Continue archivering en back-up
WAL-G is een archieftool van de volgende generatie voor PostgreSQL die back-up naar S3, Google Cloud Storage (GCS) en Azure Blob Storage ondersteunt. Het biedt:
- Basisback-ups— Volledige fysieke back-ups met behulp van
pg_basebackup - WAL-archivering— Continu vooruitschrijven van logboekverzending voor herstel op een bepaald tijdstip
- Delta-back-ups— Incrementele back-ups die alleen gewijzigde pagina's opslaan
- -codering— AES-256-codering van back-ups in rust
- Compressie— LZ4- of ZSTD-compressie voor lagere opslagkosten
Kubernetes-bronhiërarchie
Wanneer u een aangepastepostgresql-resource maakt, maakt de operator een uitgebreide set Kubernetes-resources om het cluster te beheren. Het begrijpen van deze hiërarchie is belangrijk voor het oplossen van problemen en het monitoren:
-bronnen gemaakt door de operator
- StatefulSet— Beheert de PostgreSQL-pods met stabiele netwerkidentiteiten en geordende implementatie
- Services— Twee ClusterIP-services:
<cluster-name>voor de primaire en<cluster-name>-replvoor leesreplica's - Eindpunten— Patroni werkt eindpunten bij zodat deze naar de huidige leider verwijzen voor een naadloze failover
- PodDisruptionBudgets (PDB)— Zorgt ervoor dat ten minste één exemplaar beschikbaar blijft tijdens vrijwillige verstoringen
- Secrets— PostgreSQL superuser-, replicatie- en applicatiereferenties opgeslagen als Kubernetes Secrets
- PersistentVolumeClaims (PVCs)— Eén PVC per pod voor PostgreSQL gegevensopslag
- PgBouncer-implementatie— Optionele verbindingspooler geïmplementeerd als een afzonderlijke implementatie met een eigen service
Installatie op meerdere Kubernetes-platforms
Vereisten
Zorg ervoor dat u beschikt over:
voordat u de Zalando Postgres Operator installeert- Een actief Kubernetes-cluster (v1.25+)
kubectlgeconfigureerd met clusterbeheerderstoeganghelmv3 heeft geïnstalleerd- Een standaard StorageClass geconfigureerde
Operatorinstallatie via Helm
De aanbevolen installatiemethode maakt gebruik van Helm. Dit werkt consistent op alle Kubernetes-platforms:
# 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-operatorControleer of de operator actief is:
kubectl get pods -n postgres-operator
# Expected output:
# NAME READY STATUS RESTARTS AGE
# postgres-operator-7f8b9c6d4-x2k9j 1/1 Running 0 2mAWS EKS-implementatiespecificaties
Amazon EKS vereist specifieke configuratie voor optimale PostgreSQL-prestaties:
# 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: trueVoor WAL-G-back-ups op EKS configureert u IAM-rollen voor serviceaccounts (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 AKS-implementatie
Azure AKS gebruikt Azure-schijf voor permanente opslag en beheerde identiteit voor back-upverificatie:
# 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"Google GKE-implementatie
Google Kubernetes Engine gebruikt Persistent Disk en Workload Identity voor GCS-back-uptoegang:
# 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"Blank metaal k3s/Rancher met Longhorn-opslag
Voor implementaties op locatie biedt k3s een lichtgewicht Kubernetes-distributie en Longhorn biedt gedistribueerde blokopslag. Deze combinatie is ideaal wanneer u volledige controle over uw infrastructuur nodig heeft zonder dat u gebonden bent aan een cloudleverancier.
# 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.210PostgreSQL Cluster CRD Specificatie
De kern van het inzetten van een PostgreSQL-cluster met de Zalando-operator is depostgresqlCustom Resource. Dit YAML-manifest geeft de gewenste status van uw cluster aan, en de operator stemt dit af met de realiteit. Hieronder vindt u een uitgebreide, productieklare CRD-specificatie:
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-sleutel CRD-velden uitgelegd
- numberOfInstances— Totaal aantal peulen. De operator wijst er automatisch één aan als primair en de rest als streaming-replica's.
- enableConnectionPooler— Implementeert PgBouncer zijspan voor de primaire service, waardoor de verbindingsoverhead wordt verminderd.
- enableReplicaConnectionPooler— Implementeert een afzonderlijke PgBouncer voor de replicaservice, essentieel voor leesintensieve werklasten.
- postgresql.parameters— Directe PostgreSQL-configuratieparameters doorgegeven aan
postgresql.conf. - patroni— Configureert Patroni-gedrag inclusief TTL, luswachttijd, time-out voor opnieuw proberen en synchrone replicatiemodus.
- volume.storageClass— Wordt toegewezen aan de platformspecifieke StorageClass (EBS gp3 op AWS, Premium SSD op Azure, SSD PD op GCP, Longhorn op k3s).
- enableShmVolume— Mounts een
tmpfsop/dev/shmvoor PostgreSQL gedeeld geheugen, cruciaal voor prestaties.
Verbindingspooling met PgBouncer
Het proces-per-verbindingsmodel van de PostgreSQL maakt het duur om grote aantallen clientverbindingen te verwerken. Elke verbinding verbruikt ongeveer 10 MB RAM. PgBouncer lost dit op door duizenden clientverbindingen te multiplexen over een kleine pool van daadwerkelijke PostgreSQL-verbindingen.
De Zalando-operator ondersteunt standaard de implementatie van PgBouncer. Wanneer uenableConnectionPooler: truein de CRD instelt, maakt de operator:
- Een PgBouncer-implementatie met configureerbaar aantal replica's
- Een speciale service (
<cluster-name>-pooler) voor gepoolde verbindingen - Automatische identificatiesynchronisatie met PostgreSQL
PgBouncer-configuratiemodi
# 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: 256MiVoor toepassingen die voorbereide instructies of functies op sessieniveau nodig hebben, kunt u rechtstreeks verbinding maken met de PostgreSQL-services en PgBouncer omzeilen, of desession-poolingmodus gebruiken met als wisselwerking een lagere verbindingsefficiëntie.
PostgreSQL-replicatie voor meerdere regio's
Voor mondiale toepassingen die leesbewerkingen met lage latentie vanaf meerdere geografische locaties of noodherstel tussen regio's vereisen, is replicatie in meerdere regio's essentieel. De Zalando-operator ondersteunt dit via standby-clusters die repliceren vanuit een primair cluster via streaming-replicatie of WAL-G-archieven.
Streamingreplicatieconfiguratie
PostgreSQL-streamingreplicatie vormt de basis van HA in de Zalando-operator. Het werkt door Write-Ahead Log (WAL)-records in bijna realtime van de primaire naar replica's te verzenden. De operator configureert dit automatisch, maar het begrijpen van de details helpt bij het afstemmen en oplossen van problemen.
- Synchrone replicatie— De primaire wacht op ten minste één replica om de WAL-ontvangst te bevestigen voordat een transactie wordt vastgelegd. Dit garandeert geen gegevensverlies (RPO=0), maar voegt latentie toe. Inschakelen met
patroni.synchronous_mode: true. - Asynchrone replicatie— De primaire commit wordt onmiddellijk doorgevoerd en WAL asynchroon verzonden. Iets lagere latentie maar potentieel gegevensverlies tijdens failover. Dit is de standaardinstelling.
- Trapsgewijze replicatie— Replica's kunnen repliceren vanaf andere replica's in plaats van de primaire, waardoor de belasting van de primaire in grote clusters wordt verminderd.
# 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 replicasBack-up en herstel met WAL-G
WAL-G Back-upconfiguratie
Een juiste back-upconfiguratie is van cruciaal belang voor noodherstel. De Zalando-operator integreert WAL-G voor continue back-up naar objectopslag. Hier is een volledige configuratie voor S3-compatibele opslag:
# 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"Point-in-Time-herstel (PITR)
MetPITR kunt u uw database op elk specifiek moment herstellen, wat van cruciaal belang is voor herstel na het per ongeluk verwijderen of beschadigen van gegevens. De Zalando-operator ondersteunt PITR via het kloonmechanisme:
# 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 insteadWanneer deze CRD wordt toegepast, voert de operator de volgende stappen uit:
- Vindt de nieuwste basisback-up vóór de doeltijdstempel
- Herstelt de basisback-up naar de primaire pod van de nieuwe StatefulSet
- Speelt WAL-segmenten opnieuw af tot de opgegeven tijdstempel
- Opent de database voor lees-schrijfbewerkingen
- Stelt streaming-replicatie in op de replica-pods
Stand-bycluster voor noodherstel
Een stand-bycluster repliceert voortdurend vanuit een primair cluster, waardoor een warme stand-by wordt geboden die tijdens een ramp kan worden bevorderd. Dit verschilt van replica's binnen een cluster: een standby-cluster is een volledig onafhankelijke Kubernetes-bron die in een andere naamruimte, cluster of zelfs regio kan worden uitgevoerd.
# 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: trueOm een standby-cluster te promoveren naar een onafhankelijke primaire cluster (tijdens noodherstel), verwijdert u eenvoudigweg destandby-sectie van de CRD en past u het volgende toe:
# 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-bewaking met Prometheus en Grafana
Uitgebreide monitoring is niet onderhandelbaar voor productie-PostgreSQL-implementaties. De Zalando-operator ondersteunt de export van Prometheus-statistieken via depostgres_exporter-zijspan. Hier ziet u hoe u een complete monitoringstack instelt:
ServiceMonitor voor 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: /metricsBelangrijke statistieken om
te monitorenDit zijn de meest kritische PostgreSQL-statistieken om bij te houden in uw Grafana-dashboards:
- pg_stat_replication_lag— Replicatievertraging in bytes en seconden. Waarschuw als de vertraging uw RPO-drempel overschrijdt.
- pg_stat_activity_count— Actieve verbindingen per staat. Waarschuwing bij uitputting van de verbindingspool.
- pg_stat_database_tup_fetched/returned/inserted/updated/deleted— Querydoorvoerstatistieken.
- pg_stat_bgwriter_buffers_checkpoint/clean/backend— Efficiëntie van bufferbeheer.
- pg_database_size_bytes— Groei van databasegrootte in de loop van de tijd voor capaciteitsplanning.
- pg_locks_count— Vergrendeling van conflicten. Waarschuw bij overmatige wachtsloten.
- pg_stat_statements_calls/mean_time— Prestatiestatistieken opvragen voor optimalisatie.
- patroni_postgres_running— Patroni-gezondheidsstatus (1 = actief, 0 = uitgeschakeld).
- patroni_master— Welke pod is de huidige primaire (1 = master, 0 = replica).
- pg_up— Basis PostgreSQL beschikbaarheidssonde.
Waarschuwingsregels
# 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 }}"Productieafstemmingsgids
Een goede afstemming is essentieel om maximale prestaties uit de PostgreSQL op de Kubernetes te halen. De volgende parameters moeten worden aangepast op basis van de resourcelimieten en werkbelastingkenmerken van uw pod.
Geheugenconfiguratie
# 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"WAL en Checkpoint-configuratie
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 checkpointsQueryplanner en I/O
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"Verbinding en loggen
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 timeoutRolling Updates en versie-upgrades
Kleine versie-upgrades
Kleine versie-upgrades (bijvoorbeeld 16.2 naar 16.3) worden automatisch afgehandeld door de operator wanneer u de Spilo-afbeeldingstag bijwerkt. De operator voert een rollende herstart uit:
# 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)Grote versie-upgrades
Grote versie-upgrades (bijv. PostgreSQL 15 naar 16) vereisen een zorgvuldigere planning. De Zalando-operator ondersteunt grote upgrades ter plaatse met behulp vanpg_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'"Belangrijke overwegingen voor grote upgrades:
- Maak altijd een nieuwe back-up voordat u een upgrade uitvoert van
- Test de upgrade eerst op een gekloond cluster
- Grote upgrades vereisen downtime (doorgaans 5-30 minuten, afhankelijk van de databasegrootte)
- Bekijk de releaseopmerkingen van de PostgreSQL voor de belangrijkste wijzigingen in
- Houd de replicatievertraging nauwlettend in de gaten na het opnieuw opbouwen van de
- Voer
ANALYZEuit op alle databases om de statistieken van de queryplanner opnieuw te genereren
Geavanceerde operationele patronen
Logische back-ups
Naast fysieke WAL-G-back-ups ondersteunt de operator logische back-ups met behulp vanpg_dump. Logische back-ups zijn handig voor migraties tussen versies en selectief tabelherstel:
# 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 S3Aangepaste pod-omgevingsvariabelen
U kunt omgevingsvariabelen in Spilo-pods injecteren met behulp van een ConfigMap. Dit is handig voor het configureren van WAL-G, aangepaste scripts of het afstemmen van parameters op besturingssysteemniveau:
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"Netwerkbeleid voor beveiliging
Beperk in productie de netwerktoegang tot PostgreSQL-pods met behulp van Kubernetes Netwerkbeleid:
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 backupsProblemen oplossen Veelvoorkomende problemen
Zelfs bij automatisering ontstaan er problemen. Hier zijn de meest voorkomende problemen en hun oplossingen bij het uitvoeren van PostgreSQL met de Zalando-operator:
1. Pod zit vast in de status 'In behandeling'
# 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 databases2. Replicatievertraging bij het groeien van
# 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. Failover activeert
niet# 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. Back-upfouten
# 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/"Beste beveiligingspraktijken
Het beveiligen van PostgreSQL op Kubernetes vereist een diepgaande verdedigingsaanpak:
- TLS-codering— Schakel SSL in voor alle clientverbindingen. De operator kan certificaten automatisch inrichten met behulp van cert-manager.
- Geheimenbeheer— Gebruik Kubernetes Secrets (of externe geheimmanagers zoals Vault) voor databasereferenties. Bewaar nooit wachtwoorden in ConfigMaps.
- RBAC— Beperk de ServiceAccount-machtigingen van de operator. Gebruik toegang met de minste bevoegdheden voor gebruikers van de applicatiedatabase.
- Netwerkbeleid— Beperk pod-tot-pod-communicatie zoals weergegeven in de vorige sectie.
- pg_hba.conf— Configureer hostgebaseerde authenticatie om te beperken welke IP's en gebruikers verbinding kunnen maken.
- Auditregistratie— Schakel de
pgaudit-extensie in voor SQL-auditregistratie in gereguleerde omgevingen. - Gecodeerde opslag— Gebruik gecodeerde StorageClasses (EBS-codering, Azure-schijfcodering, enz.).
- Pod-beveiligingsnormen— Voer Spilo-pods uit als niet-root met beperkte beveiligingscontexten.
# 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: 0640Capaciteitsplanning en dimensionering
De juiste maatvoering zorgt voor stabiele prestaties en kostenefficiëntie. Gebruik deze richtlijnen als uitgangspunt en pas deze aan op basis van uw werklastmonitoringsgegevens:
| Werklast | CPU | Geheugen | Opslag | -instanties |
|---|---|---|---|---|
| Ontwikkeling | 500m | 1Gi | 10Gi | 1 |
| Kleine productie | 2 kernen | 8Gi | 50Gi SSD | 3 |
| Middelgrote productie | 4 kernen | 16Gi | 200Gi SSD | 3 |
| Grote productie | 8 kernen | 32Gi | 500Gi SSD | 5 |
| Enterprise/Analytics | 16+ kernen | 64Gi+ | 1Ti+ SSD | 5+ |
Compleet end-to-end implementatievoorbeeld
Laten we alles samenvoegen met een volledige implementatie vanaf het begin op een nieuw Kubernetes-cluster:
# 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();"Conclusie
De Zalando Postgres Operator transformeert PostgreSQL op Kubernetes van een complexe operationele uitdaging naar een beheersbare, geautomatiseerde implementatie. Door gebruik te maken van Patroni voor op consensus gebaseerde failover, Spilo voor een containerimage met batterijen, WAL-G voor continue back-up en herstel, en PgBouncer voor efficiënte pooling van verbindingen, krijgt u een databaseplatform van productiekwaliteit dat consistent werkt in AWS EKS, Azure AKS, Google GKE en bare-metal k3s-clusters.
De belangrijkste punten uit deze handleiding zijn:
- Automatiseer alles— Laat de operator het StatefulSet-beheer, failover en back-upplanning afhandelen. Handmatige interventie zou de uitzondering moeten zijn.
- Agressief monitoren— Implementeer Prometheus en Grafana vanaf de eerste dag. Replicatievertraging, aantal verbindingen en vergrendelingsconflicten zijn uw vroege waarschuwingssignalen.
- Plan voor rampen— Configureer WAL-G-back-ups, test PITR regelmatig en onderhoud een standby-cluster voor kritieke werklasten.
- Stem af op uw werklast— Standaard PostgreSQL-parameters zijn conservatief. Pas de instellingen voor shared_buffers, work_mem en checkpoint aan op basis van uw resourcetoewijzing en querypatronen.
- Standaard beveiligd— Schakel TLS in, gebruik SCRAM-SHA-256-authenticatie, beperk netwerktoegang en versleutel opslag in rust.
- Testupgrades— Kloon altijd uw cluster en test belangrijke versie-upgrades voordat u ze in productie gebruikt.
Met deze uitgebreide basis bent u goed uitgerust om PostgreSQL-clusters met hoge beschikbaarheid op elk Kubernetes-platform te implementeren en te gebruiken, voor toepassingen die betrouwbaarheid, prestaties en gegevensintegriteit op schaal vereisen.