28 Apr 2019

Running PostgreSQL in a Cloud on Oracle Containers Engine for Kubernetes

In this post I am going to show a few steps to deploy and run PostgreSQL database in a K8S cluster on OKE.

The deployment is going to be based on postgres:11.1 Docker image which requires a few environment variables to be configured: POSTGRES_DB (database name), POSTGRES_USER and POSTGRES_PASSWORD. I am going to store values of these variables in K8S ConfigMap and Secret:
apiVersion: v1
kind: ConfigMap
metadata:
  name: postgre-db-config
data:
  db-name: flexdeploy

apiVersion: v1
kind: Secret
metadata:
  name: postgre-db-secret
stringData:
  username: creator
  password: c67

These configuration K8S resources are referenced by the StatefulSet which actually takes care of the lifespan of a pod with postgres-db container:
apiVersion: apps/v1beta2
kind: StatefulSet
metadata:
  name: postgre-db
  labels:
    run: postgre-db
spec:
  selector:
      matchLabels:
        run: postgre-db
  serviceName: "postgre-db-svc"
  replicas: 1
  template:
    metadata:
      labels:
        run: postgre-db
    spec:
      containers:
      - image: postgres:11.1
        volumeMounts:
           - mountPath: /var/lib/postgresql/data
             name: db     
        env:
          - name: POSTGRES_DB
            valueFrom:
              configMapKeyRef:
                   name: postgre-db-config
                   key: db-name                  
          - name: POSTGRES_USER
            valueFrom:
              secretKeyRef:
                   name: postgre-db-secret
                   key: username                  
          - name: POSTGRES_PASSWORD
            valueFrom:
              secretKeyRef:
                   name: postgre-db-secret
                   key: password                  
          - name: PGDATA
            value: /var/lib/postgresql/data/pgdata           
        name: postgre-db
        ports:
        - containerPort: 5432
  volumeClaimTemplates:
   - metadata:
       name: db
     spec:
       accessModes: [ "ReadWriteOnce" ]
       resources:
         requests:
           storage: 3Gi  


StatefulSet K8S resource has been specially designed for stateful applications like database that save their data to a persistent storage. In order to define a persistent storage for our database we use another K8s resource Persistent Volume and here in the manifest file we are defining a claim to create a 3Gi Persistent Volume with name db. The volume is called persistent because its lifespan is not maintained by a container and not even by a pod, it’s maintained by a K8s cluster. So it can outlive any containers and pods and save the data. Meaning that if we kill or recreate a container or a pod or even the entire StatefulSet, the data will be still there. We are referring to this persistence volume in the container definition mounting a volume on path /var/lib/postgresql/data. This is where PostgreSQL container stores its data.

In order to access the database we are going to create a service:
apiVersion: v1
kind: Service
metadata:
  name: postgre-db-svc 
spec:
  selector:
    run: postgre-db
  ports:
    - port: 5432
      targetPort: 5432 
  type: LoadBalancer   

This is a LoadBalancer service which is accessible from outside of the K8S cluster:
$ kubectl get svc postgre-db-svc
NAME             TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)          AGE
postgre-db-svc   LoadBalancer   10.96.177.34   129.146.211.77   5432:32498/TCP   39m

Assuming that we have created a K8s cluster on OKE and our kubectl is configured to communicate with it we can apply the manifest files to the cluster:
kubectl apply -f postgre-db-config.yaml
kubectl apply -f postgre-db-secret.yaml
kubectl apply -f postgre-db-pv.yaml
kubectl apply -f postgre-db-service.yaml

Having done that, we can connect to the database from our favorite IDE on our laptop

The manifest files for this post are available on GitHub.

That's it!