The PostgreSQL Operator lets you manage PostgreSQL clusters on Kubernetes, but it doesn’t actually run PostgreSQL itself; it orchestrates the deployment and lifecycle of PostgreSQL instances using Kubernetes primitives.
Let’s see it in action. Imagine we have a basic Kubernetes cluster set up and the PostgreSQL Operator installed. We want to deploy a simple, single-node PostgreSQL instance.
First, we define our desired PostgreSQL cluster using a Custom Resource Definition (CRD) that the operator understands. This CRD is typically named PostgresCluster.
apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
name: hippo
namespace: default
spec:
image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-15.3-1
instances:
- name: instance1
replicas: 1
dataVolumeClaimSpec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
When we apply this manifest:
kubectl apply -f cluster.yaml
The PostgreSQL Operator, which is running as a Deployment in our cluster, watches for PostgresCluster resources. Upon seeing hippo, it kicks off a series of Kubernetes actions.
It will first create a StatefulSet named hippo-postgres. StatefulSets are crucial here because they provide stable network identifiers and persistent storage for each PostgreSQL instance.
kubectl get statefulset hippo-postgres
You’ll see a StatefulSet with one replica. The operator configures this StatefulSet to pull the specified crunchy-postgres image. For each replica defined (in this case, just one instance1), the operator will:
- Create a Pod: This Pod will contain the PostgreSQL container.
- Provision Persistent Storage: It requests a PersistentVolumeClaim (PVC) based on the
dataVolumeClaimSpecin ourPostgresClusterdefinition. This PVC will eventually be bound to a physical PersistentVolume (PV) by Kubernetes. - Configure PostgreSQL: The operator injects configuration into the PostgreSQL container. This includes setting up
pg_hba.conffor authentication andpostgresql.conffor tuning. It also initializes the PostgreSQL data directory on the provisioned storage. - Create a Service: A Kubernetes Service named
hippo-postgresis created. This Service provides a stable IP address and DNS name for accessing the PostgreSQL primary instance, abstracting away the specific Pod that happens to be running it at any given moment.
kubectl get service hippo-postgres
kubectl get pvc
The operator also manages secrets for database credentials. It will create a secret named hippo-postgres-pguser-pgroot containing the postgres user’s password.
kubectl get secret hippo-postgres-pguser-pgroot -o jsonpath='{.data.password}' | base64 --decode
To connect to your PostgreSQL instance, you would typically use the Service name hippo-postgres and the postgres username with the password from the secret.
# Inside a pod in the same namespace
psql postgresql://postgres:<password>@hippo-postgres.default.svc.cluster.local:5432/postgres
The operator’s power comes from its ability to automate complex tasks. For example, if you wanted to create a replica, you’d simply update the PostgresCluster spec to replicas: 2 and kubectl apply again. The operator would then add a new replica Pod to the existing StatefulSet and configure PostgreSQL replication.
When you need to perform a PostgreSQL upgrade, you update the spec.image field in the PostgresCluster manifest to the new version and kubectl apply. The operator orchestrates a rolling upgrade, ensuring minimal downtime. It handles promoting replicas, switching the primary, and updating configurations.
The operator also manages things like backups, monitoring, and TLS configuration through additional fields in the PostgresCluster CRD. It translates your declarative desired state into imperative Kubernetes actions.
What most people miss is how the operator uses Kubernetes primitives like StatefulSets and Services to provide high availability and stable access. It’s not just about spinning up a PostgreSQL container; it’s about leveraging Kubernetes’ inherent capabilities to manage stateful applications reliably. The operator acts as a domain-specific controller, understanding PostgreSQL’s needs and translating them into Kubernetes API calls.
The next concept you’ll likely encounter is managing High Availability configurations with replicas and automatic failover.