The operator pattern
PGO registers three controllers with the controller-runtime manager when it starts:
Each controller uses a reconciler loop. When you create or update a custom resource, Kubernetes adds an event to the controller’s work queue. The reconciler reads the current state of the cluster, computes the desired state from the spec, and applies the necessary Kubernetes API calls to converge them.
The operator runs with leader election (configurable via the
PGO_CONTROLLER_LEASE_NAME environment variable) so that exactly one replica is active at any time. It uses coordination.k8s.io/leases for the lease and exposes a health probe on port 8081 and authenticated Prometheus metrics on port 8443.
PostgresCluster controller
Thepostgrescluster controller owns every Kubernetes object that belongs to a PostgresCluster. The ManagedReconciler function registers ownership of:
ConfigMap,Secret,Service,ServiceAccount,EndpointsPersistentVolumeClaimDeployment,StatefulSetJob,CronJobRole,RoleBindingPodDisruptionBudget
PostgresCluster, deleting the PostgresCluster cascades to all its child objects through Kubernetes garbage collection.
Reconciliation order
The reconciler follows a strict ordering to ensure each subsystem is available before the next depends on it. Condensed fromReconcile() in controller.go:
1
Validation and defaults
Set defaults, detect OpenShift, verify required container images, warn if the selected PostgreSQL version is end-of-life, and validate standby configuration.
2
Root CA and TLS
Reconcile the cluster’s root certificate authority (
reconcileRootCertificate). All subsequent TLS material derives from this CA.3
Data source and volume preparation
Run directory-move Jobs if volumes need to be relocated (
reconcileDirMoveJobs), observe existing PersistentVolumeClaims, and reconcile the data source for new clusters or in-place restores (reconcileDataSource). The reconciler returns early while these long-running Jobs are in progress.4
Networking and RBAC
Reconcile the cluster pod Service, the primary Service, the replica Service, the Patroni leader lease Service, and the instance ServiceAccount with its Role and RoleBinding.
5
Patroni configuration
Generate
pg_hba.conf rules and PostgreSQL parameters, then reconcile Patroni’s distributed configuration (stored in an Endpoints object) and dynamic configuration (applied live via the Patroni API).6
Instance sets
Reconcile the StatefulSets that run PostgreSQL pods, including rolling updates and pod restart handling (
reconcileInstanceSets, handlePatroniRestarts).7
Databases and users
Create or update databases (
reconcilePostgresDatabases), provision users and their credential Secrets (reconcilePostgresUsers), and apply any databaseInitSQL ConfigMap.8
pgBackRest
Reconcile backup repositories, the pgBackRest repository host, scheduled backup CronJobs, and any in-progress restore or clone operations (
reconcilePGBackRest).9
Snapshots, pgBouncer, and monitoring
Reconcile VolumeSnapshots, the pgBouncer Deployment, and the pgMonitor exporter sidecar with its metrics configuration (
reconcilePGBouncer, reconcilePGMonitorExporter).10
pgAdmin
Optionally reconcile a pgAdmin Deployment and its configuration (
reconcilePGAdmin).status.observedGeneration to match the current metadata.generation. Status conditions (Progressing, ProxyAvailable, PersistentVolumeResizing) provide structured observability into what the operator is doing.
You can pause reconciliation at any time by setting
spec.paused: true in the PostgresCluster. The controller sets a Progressing=False/Paused condition and stops applying changes until you remove the field.High availability with Patroni
PGO uses Patroni for high availability. Patroni provides distributed consensus-based leader election: each PostgreSQL instance runs a Patroni agent that participates in a consensus protocol (backed by a Kubernetes Endpoints object acting as a DCS) to elect and maintain a single primary. Key behaviors:- Automatic failover: if the primary becomes unavailable, Patroni promotes the most up-to-date replica within seconds.
- Self-healing primaries: after a failed primary recovers, Patroni automatically brings it back as a replica and reintegrates it into the cluster.
- Synchronous replication: set
spec.patronito configure synchronous standby names, ensuring no transactions are lost during failover. - Switchover: PGO exposes
reconcilePatroniSwitchoverso you can trigger a controlled switchover by annotating thePostgresCluster. - Standby clusters: set
spec.standby.enabled: truewith either arepoName(WAL archive) or ahost(streaming replication) to create a read-only standby cluster that can be promoted independently.
patroniLeaderService) always routes to the current primary. Applications should connect through this Service to avoid write-split scenarios.
Backups and restore with pgBackRest
pgBackRest handles all backup and restore operations. PGO reconciles a dedicated pgBackRest repository host pod and up to four backup repositories inspec.backups.pgbackrest.repos.
Supported repository backends:
- Local volume
- Amazon S3
- Google Cloud Storage
- Azure Blob Storage
PostgresCluster by referencing a dataSource.postgresCluster or a cloud-based dataSource.pgbackrest source.
Connection pooling with pgBouncer
Enable pgBouncer by addingspec.proxy.pgBouncer: {} to your PostgresCluster. PGO reconciles a pgBouncer Deployment (reconcilePGBouncer) that sits in front of the PostgreSQL primary. pgBouncer maintains a pool of server-side connections and serves multiple application clients from that pool, dramatically reducing connection overhead for applications that open many short-lived connections.
PGO automatically rotates pgBouncer’s TLS certificate and keeps its configuration synchronized with the current primary’s address as Patroni performs failovers. The pgBouncer connection URI is stored in the pgbouncer-uri key of the user credential Secret.
You can set resource requests and limits, replica count, custom configuration, and sidecar containers (via the PGBouncerSidecars feature gate) in spec.proxy.pgBouncer.
Monitoring with pgMonitor
PGO integrates pgMonitor for PostgreSQL metrics. When monitoring is enabled, PGO runs apostgres_exporter sidecar on each PostgreSQL instance pod. The exporter exposes standard PostgreSQL metrics in Prometheus format and is configured with query files managed through a ConfigMap (reconcileExporterQueriesConfig).
The monitoring credentials are stored in a dedicated Secret (reconcileMonitoringSecret) separate from the application user Secrets.
To enable monitoring, add spec.monitoring.pgmonitor to your PostgresCluster:
AppendCustomQueries feature gate to append your own SQL queries to the default pgMonitor query set.
Custom resource definitions
PGO ships three CRDs under thepostgres-operator.crunchydata.com API group:
PostgresCluster
The primary CRD. Defines the full desired state of a PostgreSQL cluster. Keyspec fields from postgrescluster_types.go:
PGUpgrade
Controls in-place major version upgrades. ThePGUpgrade resource instructs PGO to run pg_upgrade across instance pods and then bring the cluster back up on the new PostgreSQL version. See the PGUpgrade reference for details.
PGAdmin
The standalonePGAdmin CRD (managed by standalone_pgadmin.ManagedReconciler) deploys a pgAdmin 4 instance that can connect to multiple PostgresCluster resources. This is distinct from the embedded spec.userInterface.pgAdmin field, which scopes pgAdmin to a single cluster. See the PGAdmin reference for details.
Feature gates
PGO uses a Kubernetes-style feature gate system to control the availability of features that are in Alpha or Beta maturity. Feature gates are set at operator startup via thePGO_FEATURE_GATES environment variable using the format Feature1=true,Feature2=false.
The full gate list from internal/feature/features.go:
Alpha features are disabled by default. Beta features are enabled by default. You can override any gate at operator startup. See the feature gates reference for full documentation.
Namespace modes
By default PGO watches all namespaces in the cluster. You can restrict it to a single namespace using thePGO_TARGET_NAMESPACE environment variable, or to a set of namespaces using PGO_TARGET_NAMESPACES (comma-separated). This is configured in the Kustomize install overlays.
Further reading
Install with Kustomize
Step-by-step installation using the official Kustomize overlays.
High availability guide
Configure replicas, synchronous replication, and standby clusters.
Backups guide
Set up pgBackRest repositories and scheduled backup policies.
Feature gates reference
Full reference for all available PGO feature gates and how to configure them.