
PostgreSQL is an open-source relational database system with strong support for extensibility, concurrency, and SQL standards compliance. PGO, the Postgres Operator from Crunchy Data, extends Kubernetes with custom resources that automate provisioning, high availability, backups, and upgrades for PostgreSQL clusters.
This guide explains how to install PostgreSQL in a Vultr Kubernetes Engine (VKE) cluster using PGO. It covers installing the operator with Helm, provisioning a cluster backed by Block Storage, configuring pgBackRest to archive write-ahead logs and backups to Object Storage, connecting to the database, and applying common customizations such as replicas, connection pooling, and scheduled backups.
Before you begin, you need to:
kubectl returns.PGO is distributed as a Helm chart in an OCI registry. Installing the chart registers the PostgresCluster, PGUpgrade, and PGAdmin Custom Resource Definitions (CRDs) and starts the controller that reconciles them.
Install the operator into a dedicated namespace.
Verify that the operator pod reports a Running status.
The output displays a single pgo pod with a Running status and 1/1 containers ready.
Confirm that the operator installed its Custom Resource Definitions.
The output lists postgresclusters, pgupgrades, and pgadmins. The postgresclusters resource serves both the stable v1 API and the older v1beta1 API.
pgBackRest reads its S3 credentials from a Kubernetes Secret rather than from the cluster manifest, which keeps the access keys out of the resource definition. The Secret must contain a key named s3.conf holding a pgBackRest configuration section.
Retrieve your Object Storage access key and secret key from the Object Storage page in the Vultr Console.
Create the pgBackRest configuration file.
Add the following configuration. Replace S3-ACCESS-KEY and S3-SECRET-KEY with your Object Storage credentials.
Save and close the file.
Create the Secret from the file.
The --from-file flag names the Secret key after the file, which produces the s3.conf key that pgBackRest expects.
Verify that the Secret contains the s3.conf key.
The output lists a single key, s3.conf.
Delete the local file so that the credentials do not remain on disk.
A PostgresCluster resource describes the PostgreSQL version, storage, and backup targets. PGO supplies the container images for Postgres, pgBackRest, and pgBouncer automatically, so the manifest does not need to pin image tags.
Create the cluster manifest.
Add the following configuration. Replace BUCKET-NAME with your bucket and OBJECT-STORAGE-HOSTNAME with your Object Storage hostname, such as ewr1.vultrobjects.com.
Save and close the file.
apiVersion: Uses the stable v1 API served by current operator releases.postgresVersion: Selects the major PostgreSQL version that PGO deploys. The operator ships images for versions 15 through 18, so set a different major version here to deploy one of the others.dataVolumeClaimSpec: Requests a PersistentVolume from the vultr-block-storage StorageClass. Block Storage enforces a 10 GB minimum, so smaller requests fail to bind.repo1-s3-uri-style: path: Required for Object Storage, which addresses buckets by path rather than by virtual host.repo1-retention-full: Keeps the 14 most recent full backups and expires older ones.region: Object Storage ignores the value but pgBackRest requires the field, so any valid region string works.Apply the manifest.
Wait for the cluster pod to become ready.
Verify the running pods.
The output displays the operator pod alongside a hippo-instance1 pod with a Running status and 4/4 containers ready, covering Postgres, pgBackRest, and the replication controller.
Verify that the PersistentVolumeClaim bound to Block Storage.
Verify that the STATUS column shows Bound and the STORAGECLASS column shows vultr-block-storage.
PGO creates a pgBackRest stanza and runs an initial full backup as soon as the cluster starts. The backup and the archived write-ahead logs land in the bucket under the repo1-path prefix.
Wait for the initial backup job to finish.
Check the repository status reported by the operator.
Verify that the output reports "stanzaCreated":true and "replicaCreateBackupComplete":true.
Identify the primary pod.
Query pgBackRest from inside the primary pod. Replace PRIMARY-POD-NAME with the pod name from the previous step.
The output confirms the stanza status and lists the completed full backup:
PGO generates a Secret named CLUSTER-NAME-pguser-USER-NAME that holds the generated credentials and connection strings. For the cluster in this guide, the Secret is hippo-pguser-hippo.
List the fields the Secret provides.
The Secret contains user, password, dbname, host, port, uri, jdbc-uri, and verifier.
Decode the individual connection values.
Identify the primary pod.
Run a query directly against the primary to confirm the server version. Replace PRIMARY-POD-NAME with the pod name from the previous step.
Forward the primary pod to your workstation to connect with an external client. Replace PRIMARY-POD-NAME with the pod name returned by the previous command.
Connect to localhost:5432 using the decoded user, database, and password.
Forward the pod rather than the hippo-primary or hippo-ha Services. Patroni manages those Services without a selector, and kubectl port-forward rejects them with Service is defined without a selector.
The operator reconciles the cluster whenever the PostgresCluster resource changes. Each of the following customizations edits postgres.yaml and applies it again.
Additional replicas run streaming replication against the primary, and PGO promotes one automatically if the primary fails.
Open the cluster manifest.
Set replicas under the instance set to the total number of Postgres pods.
Save and close the file.
Apply the manifest.
Verify that the additional pods reach a Running status.
Synchronous replication suits workloads that cannot tolerate losing committed transactions. Commits take longer, and writes to the primary block when no synchronous replica is available.
Apply Add Replicas before this section. Enabling synchronous replication on a single-instance cluster leaves no synchronous replica available, which blocks writes to the primary.
Open the cluster manifest.
Add the patroni block under spec.
Save and close the file.
The archive_timeout parameter forces a write-ahead log segment switch every 60 seconds so that Object Storage receives archives on a predictable interval.
Apply the manifest.
pgBouncer multiplexes client connections onto a smaller pool of backend connections, which helps applications that open many short-lived connections.
Open the cluster manifest.
Add the proxy block under spec.
Save and close the file.
Apply the manifest.
Verify that the pooler pod is running.
Confirm that the pooler connection details were added to the user Secret.
The Secret gains pgbouncer-host, pgbouncer-port, pgbouncer-uri, and pgbouncer-jdbc-uri.
Forward the pooler Service to connect through it.
A schedules block runs full and incremental backups on a cron expression instead of only on demand.
Open the cluster manifest.
Add a schedules block to the repository. Replace BUCKET-NAME and OBJECT-STORAGE-HOSTNAME with the same values used in the cluster manifest.
Save and close the file.
This schedule runs a full backup daily at 1 a.m. and an incremental backup every four hours.
Apply the manifest.
Verify that the operator created the backup CronJobs.
A manual backup target defines the options PGO uses when you trigger a one-off backup with an annotation.
Open the cluster manifest.
Add a manual block under pgbackrest.
Save and close the file.
Apply the manifest.
Annotate the cluster to trigger the backup.
Verify that the backup job completed.
A second repository backed by a PersistentVolume keeps a local copy of backups alongside the Object Storage copy.
Open the cluster manifest.
Add a second entry to repos. Replace BUCKET-NAME and OBJECT-STORAGE-HOSTNAME with the same values used in the cluster manifest.
Save and close the file.
Block Storage enforces a 10 GB minimum, so a smaller storage request leaves the claim unbound.
Apply the manifest.
Verify that the second repository's PersistentVolumeClaim bound.
The operator records reconciliation problems as Kubernetes events and cluster conditions, and pgBackRest writes its own logs inside the instance pod.
Inspect the cluster resource and its events.
List namespace events in chronological order.
Review the operator log when a cluster never becomes ready.
Validate the pgBackRest configuration from inside the primary pod. Replace PRIMARY-POD-NAME with your primary pod name.
The command produces no output and exits with status 0 when the repository and archive settings are valid. A misconfigured repository prints the failing check instead.
Read the pgBackRest logs. Replace PRIMARY-POD-NAME with your primary pod name.
You have successfully installed PostgreSQL in a Vultr Kubernetes Engine cluster using PGO, with data stored on Block Storage and write-ahead logs and backups archived to Object Storage. Extend the deployment by adding replicas for high availability, enabling connection pooling, or scheduling recurring backups. For more information, visit the official PGO documentation.
0 Comments
Be the first to comment and share your perspective with the community.