How to deploy a PostgreSQL database on the Oracle Cloud using OKE and Portworx Data Services (PDS)

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:

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.

Oracle Container Engine for Kubernetes (OKE)

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.

Add Deployment Target

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.

Deployment Targets

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 SizeStorage Options and No, of Nodes, then click Deploy.

Deploy PostgreSQL

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.

Deployment / PostgreSQL

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.

One thought on “How to deploy a PostgreSQL database on the Oracle Cloud using OKE and Portworx Data Services (PDS)

Add yours

Leave a Reply

Create a website or blog at WordPress.com

Up ↑

%d bloggers like this: