With the recent growth in popularity of PostgreSQL, you may have noticed that many of the major Cloud vendors have developed and now offer managed PostgreSQL Database-as-Service (DBaaS) solutions, for example:
- Azure Database for PostgreSQL
- Amazon RDS for PostgreSQL
- Amazon Aurora
- Google Cloud SQL PostgreSQL
- Google AlloyDB for PostgreSQL
- IBM Cloud Database for PostgreSQL
Additional, there are a few database vendor DBaaS offerings available for consideration, these include:
What about Oracle Cloud Infrastructure (OCI) ?
The Oracle Cloud, unlike many of its peers does no currently offer a managed PostgreSQL managed database service.
Note, it is possible to run PostgreSQL in OCI and the Oracle solutions team has produced an excellent guide on how to Deploy a PostgreSQL Database on OCI and also a Terraform Stack to assist in the automation of the Infrastructure-as-a-Service (IaaS) components.
Another approach is to use the Oracle Container Engine for Kubernetes (OKE) and deploy PostgreSQL using one of the many PostgreSQL database Operators available from OperatorHub.io
However, neither of these approaches offer a managed PostgreSQL database-as-a-service, enter Portworx Data Services (PDS)
What is Portworx Data Services (PDS)
Portworx Data Services (PDS) is a Database-as-a-Service (DBaaS) platform for Kubernetes.
PDS enables DevOps engineers and data professionals to deploy SQL and NoSQL databases, search and streaming solutions from a broad catalog of data services using curated templates with a single click of a button, including PostgreSQL.
Oracle Kubernetes Engine (OKE) Environment
I have a number of posts on my blog providing details on how to create a Kubernetes cluster on OKE, including a post on using Terraform to automate the deployment of OKE.
For this post I have used the OKE Quick Create wizard to deploy a 3 node Kubernetes cluster, running Kubernetes v1.24.1, in the UK-London-1 OCI region across the 3 Availability Domains.

We can confirm the Kubernetes version and topology using kubectl get nodes with the labels topology.kubernetes.io/region and topology.kubernetes.io/zone, as below.
% kubectl get nodes -L topology.kubernetes.io/region,topology.kubernetes.io/zone NAME STATUS ROLES AGE VERSION REGION ZONE 10.0.10.160 Ready node 95m v1.24.1 uk-london-1 UK-LONDON-1-AD-3 10.0.10.162 Ready node 95m v1.24.1 uk-london-1 UK-LONDON-1-AD-1 10.0.10.66 Ready node 95m v1.24.1 uk-london-1 UK-LONDON-1-AD-2
Portworx Enterprise
Following my Portworx Enterprise installation on OKE post I have installed the Portworx Operator 2.11, for example
% kubectl apply -f 'https://install.portworx.com/2.11?comp=pxoperator' serviceaccount/portworx-operator created Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy/px-operator created clusterrole.rbac.authorization.k8s.io/portworx-operator created clusterrolebinding.rbac.authorization.k8s.io/portworx-operator created deployment.apps/portworx-operator created
And applied the specification created from PX-Central using kubectl apply.
% kubectl apply -f 'https://install.portworx.com/2.11?operator=true&mc=false&b=true&c=px-cluster-demo&stork=true&csi=true&mon=true&tel=false&st=k8s&promop=true' storagecluster.core.libopenstorage.org/px-cluster-demo created
To confirm the Portworx version with pxctl -v
% export PX_POD=$(kubectl get pods -l name=portworx -n kube-system -o jsonpath='{.items[0].metadata.name}') % kubectl exec -it $PX_POD -n kube-system -- /opt/pwx/bin/pxctl -v Defaulted container "portworx" out of: portworx, csi-node-driver-registrar pxctl version 2.11.4-96ccc8b
Portworx Data Services (PDS)
Before we can deploy a PostgreSQL database to OKE we need to register our Oracle Kubernetes Engine cluster with Portworx Data Services (PDS).
Logon to PDS, and click on the Settings (Gear icon) on the left hand panel, then click + Add Deployment Target and click the Copy icon to capture the helm command.

Return to the Kubernetes cluster and paste the helm install command provided, for example
% helm install --create-namespace --namespace=pds-system pds pds-target --repo=https://portworx.github.io/pds-charts --version=1.10.4 --set tenantId= ... NAME: pds LAST DEPLOYED: Wed Jan 4 14:09:08 2023 NAMESPACE: pds-system STATUS: deployed REVISION: 1 TEST SUITE: None
PDS will create a new Storage Class (sc) called pds-db and a 8GB Persistent Volume Claim (pvc) called pds-prometheus-server as well as pods, services and deployments, for example.
% kubectl get po,svc,deploy,pvc -n pds-system NAME READY STATUS RESTARTS AGE pod/pds-agent-7dc4cf9b86-55j6w 1/1 Running 0 87s pod/pds-backup-controller-manager-b6bd89fb-slt5q 2/2 Running 0 87s pod/pds-deployment-controller-manager-569f647c9-9dxtd 2/2 Running 0 87s pod/pds-external-dns-667ffb86db-r8sq2 1/1 Running 0 79s pod/pds-kube-state-metrics-574f6688bf-nhb2f 1/1 Running 0 86s pod/pds-operator-target-controller-manager-fdb6f4cbb-llc2v 1/1 Running 0 86s pod/pds-prometheus-node-exporter-llzz9 1/1 Running 0 87s pod/pds-prometheus-node-exporter-prqb8 1/1 Running 0 87s pod/pds-prometheus-node-exporter-sxqt8 1/1 Running 0 87s pod/pds-prometheus-server-8bf8475ff-c9cgd 2/2 Running 0 87s pod/pds-teleport-5cfdfdcb85-mwrjk 1/1 Running 0 54s pod/pds-teleport-5d968ff884-827pq 1/1 Running 0 19s pod/pds-teleport-5d968ff884-jl2tk 0/1 Running 0 9s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/pds-backup-controller-manager-metrics-service ClusterIP 10.96.103.144 <none> 8443/TCP 89s service/pds-deployment-controller-manager-metrics-service ClusterIP 10.96.122.87 <none> 8443/TCP 89s service/pds-external-dns ClusterIP 10.96.50.149 <none> 7979/TCP 89s service/pds-kube-state-metrics ClusterIP 10.96.248.255 <none> 8080/TCP 89s service/pds-operator-target-controller-manager-metrics-service ClusterIP 10.96.78.96 <none> 8443/TCP 89s service/pds-prometheus-node-exporter ClusterIP 10.96.112.19 <none> 9111/TCP 89s service/pds-prometheus-server ClusterIP 10.96.41.111 <none> 80/TCP 89s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/pds-agent 1/1 1 1 89s deployment.apps/pds-backup-controller-manager 1/1 1 1 89s deployment.apps/pds-deployment-controller-manager 1/1 1 1 88s deployment.apps/pds-external-dns 1/1 1 1 89s deployment.apps/pds-kube-state-metrics 1/1 1 1 88s deployment.apps/pds-operator-target-controller-manager 1/1 1 1 88s deployment.apps/pds-prometheus-server 1/1 1 1 88s deployment.apps/pds-teleport 2/2 2 2 88s NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/pds-prometheus-server Bound pvc-598e9069-1423-407e-96ea-623aeb2c0259 8Gi RWO pds-db 91s
Now create a dedicated PostgreSQL Kubernetes namespace for the PDS to use and label it with pds.portworx.com/available=true
% kubectl create namespace pds-postgresql namespace/pds-postgresql created % kubectl label namespace pds-postgresql pds.portworx.com/available=true namespace/pds-postgresql labeled % kubectl get namespace pds-postgresql --show-labels NAME STATUS AGE LABELS pds-postgresql Active 41s kubernetes.io/metadata.name=pds-postgresql,pds.portworx.com/available=true
Once the helm chart has been installed and namespace labeled the Kubernetes cluster should automatically appear in the PDS console.

An optional, but advisable task is to rename the deployment with a more meaning full name, this is easily achieved by clicking on the edit (pencil icon) and entering a name, for example.

PostgreSQL Deployment
From the PDS dashboard, click the Deployment (Disk icon), you can find this in the left hand panel, this will display existing deployments.
Now click on PostgreSQL and Deploy, to be presented with the Deploy PostgreSQL form.
Confirm Version, and provide a Name, select the Target and Namespace previously created.
The database name will default to pds, if required thus can be changed by selecting Custom from Application Configuration, and providing a PG_DATABASE.
Select required template for Size, Storage Options and No, of Nodes, then click Deploy.

Returning to the Kubernetes cluster, after a few minutes we can see PDS has created PostgreSQL Pods (po), Statefulset (sts), Services (svc) and Persistent Volume Claims (pvc).
% kubectl get po,sts,svc,pvc -n pds-postgresql NAME READY STATUS RESTARTS AGE pod/pg-pg-ron-lk3wqj-0 2/2 Running 0 6m17s pod/pg-pg-ron-lk3wqj-1 2/2 Running 0 5m45s pod/pg-pg-ron-lk3wqj-2 2/2 Running 0 5m19s pod/pg-pg-ron-lk3wqj-cluster-init-z6845 0/1 Completed 0 4m51s pod/pg-pg-ron-lk3wqj-node-init-25srw 0/1 Completed 0 4m51s NAME READY AGE statefulset.apps/pg-pg-ron-lk3wqj 3/3 6m17s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/pg-pg-ron-lk3wqj-pds-postgresql LoadBalancer 10.96.101.99 <pending> 5432:30849/TCP,8009:31207/TCP,2022:32387/TCP 6m18s service/pg-pg-ron-lk3wqj-pds-postgresql-0 ClusterIP None <none> 5432/TCP,8009/TCP,2022/TCP 6m21s service/pg-pg-ron-lk3wqj-pds-postgresql-0-vip LoadBalancer 10.96.17.208 10.0.20.169 5432:32155/TCP,8009:30848/TCP,2022:31640/TCP 6m21s service/pg-pg-ron-lk3wqj-pds-postgresql-1 ClusterIP None <none> 5432/TCP,8009/TCP,2022/TCP 6m20s service/pg-pg-ron-lk3wqj-pds-postgresql-1-vip LoadBalancer 10.96.68.51 10.0.20.22 5432:30843/TCP,8009:32459/TCP,2022:31316/TCP 6m20s service/pg-pg-ron-lk3wqj-pds-postgresql-2 ClusterIP None <none> 5432/TCP,8009/TCP,2022/TCP 6m19s service/pg-pg-ron-lk3wqj-pds-postgresql-2-vip LoadBalancer 10.96.2.236 10.0.20.188 5432:31971/TCP,8009:31638/TCP,2022:30934/TCP 6m19s service/pg-pg-ron-lk3wqj-pds-postgresql-config ClusterIP None <none> 5432/TCP,8009/TCP,2022/TCP 6m18s service/px-558893992775619098-server ClusterIP 10.96.214.48 <none> 2049/TCP 6m1s service/px-716575463879534822-server ClusterIP 10.96.137.195 <none> 2049/TCP 75m NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/datadir-pg-pg-ron-lk3wqj-0 Bound pvc-7e2986e1-6f8b-4a9c-b878-e1e4ba8aa167 10Gi RWO pg-pg-ron-lk3wqj-pds-postgresql 6m18s persistentvolumeclaim/datadir-pg-pg-ron-lk3wqj-1 Bound pvc-ccb477e4-4be5-4a20-b7b1-c80f536799de 10Gi RWO pg-pg-ron-lk3wqj-pds-postgresql 5m46s persistentvolumeclaim/datadir-pg-pg-ron-lk3wqj-2 Bound pvc-5da79ec7-49ff-495a-9f8c-003914041b30 10Gi RWO pg-pg-ron-lk3wqj-pds-postgresql 5m21s persistentvolumeclaim/sharedbackupsdir-pg-pg-ron-lk3wqj Bound pvc-c626913c-b4b2-4d5e-adba-d9f1314bc174 28Gi RWX pg-pg-ron-lk3wqj-sharedbackups-pds-postgresql 6m19s
Once the pods are all up, return to Portworx Data Services (PDS) console.
The deployment should show a green icon for each node, and updated CPU, Memory and Storage metrics.

Clicking on the PDS Metrics icon, we can see graphs covering storage and application usage, for example.


Summary
In this post I have shared how we can use Portworx Database Services (PDS) to deploy and deliver a PostgreSQL DBaaS solution on the Oracle Cloud Infrastructure (OCI) Oracle Container Engine for Kubernetes (OKE) service.
In my next post I will show how we can obtain the PostgreSQL database password from PDS and / or the Kubernetes cluster and how connect to our PostgreSQL database.