This is part 2 of a 4-part series on deploying an application to Azure Kubernetes. Here’s a full list of this series:
- k8spractice Overview
- k8spractice PostgreSQL Service Deployment (this post)
- k8spractice Services
- k8spractice Ingress Rules
Motivation
First, I want to point out that Azure provides a PostgreSQL service (see here for info) that you should prefer in a production environment. I haven’t personally used it so I can’t speak to its quality other than it’s probably better than doing what this post describes. My main motivation for deploying my own PostgreSQL instance is to have something to practice deploying a Kubernetes Persistent Volume. Before going any further the yaml file for the PostgreSQL deployment is available here.
Create the Azure Disk resource
The PostgreSQL service needs a persistent location to save the database data. For that, I’m using an Azure Managed Disk. I chose this because PostgreSQL creates symlinks for its data which this resource is able to do.
Start by following the instructions to “Create an Azure Disk”. After the disk resource was created, I went in and updated the network access to “Private endpoint (through disk access)” set Network access to “Private Endpoint” and added a Disk Access resource. See here for more information.
Configure persistent volume store
Below is the PersistentVolume resource definition:
apiVersion: v1
kind: PersistentVolume
metadata:
name: psqlvol
spec:
storageClassName: psqldata
azureDisk:
kind: Managed
diskURI: <AZ DISK INSTANCE ID>
diskName: <AZ disk name>
accessModes:
- ReadWriteOnce
capacity:
storage: 2Gi
persistentVolumeReclaimPolicy: Retain
To get the value for <AZ DISK INSTANCE ID> use the following “az” comand
az disk show -g <Resource group name> -n <AZ DISK NAME> --query 'id'
Note that the value of <AZ disk name> must match the Disk resource’s name. AKS’ PersistentVolume implementation allows for an Azure Disk to be dynamically created. See here for more info on dynamically creating disks. Since this disk will be used by only a single Pod instance access mode is set to “ReadWriteOnce”. Reclaim policy is set to “Retain” so that data is not deleted if all claims are released.
Configure Persistent Volume Claim
Now that we have a Persistent Volume its time to claim space on it for use by the DB server. Below is the PVC configuration:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: psqlpvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: psqldata
This is rather straightforward. Request 1 GB of space for a Persistent Volume in the “psqldata” storage class. At this point we have a disk mount that PostgreSQL can store its data to; so, time to create a PostgreSQL deployment in our cluster.
Determining if the Persistent Volume and Persistent Volume Claim configuration are correct will have to wait until the PostgreSQL deployment is done.
Configure the PostgreSQL Deployment
The official PostgreSQL container requires that the POSTGRES_PASSWORD environment variable be set to the intended password for the DB superuser account. Create a secret for the POSTGRES_PASSWORD environment variable that will be used by the Deployment
kubectl create secret generic postgresqlsuperpass --from-literal='POSTGRES_PASSWORD=<PASSWORD HERE>'
Below is the Deployment configuration for the PostgreSQL service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: psqlserver
spec:
replicas: 1
selector:
matchLabels:
role: dbserver
template:
metadata:
labels:
role: dbserver
spec:
containers:
- name: psqlserver
image: postgres:12-alpine
imagePullPolicy: IfNotPresent
envFrom:
- secretRef:
name: postgresqlsuperpass
env:
- name: PGDATA
value: "/mnt/permstore/pgdata"
ports:
- containerPort: 5432
protocol: TCP
name: psqlport
volumeMounts:
- name: psqldata
mountPath: /mnt/permstore
volumes:
- name: psqldata
persistentVolumeClaim:
claimName: psqlpvc
readOnly: false
In the container definition the secretRef will make the stored POSTGRES_PASSWORD available to the container. The PGDATA environment variable sets the directory path to store the server’s data. The “volumeMounts” and “volumes” configures the container to use the “psqlpvc” Persistent Volume Claim defined above.
If the PV, PVC are usable by the PostgreSQL container deployed by the Deployment you’ll have one running postgresqlserver pod. Finally, create a Kubernetes Service to make the database server available to the cluster. Here’s the Service configuration:
apiVersion: v1
kind: Service
metadata:
name: dbserver
spec:
selector:
role: dbserver
ports:
- port: 5432
protocol: TCP
Create the database and roles that Backend service will use
At this point we have a running service on the cluster. The easiest way to connect to it would be to use “kubectl exec” and run psql on the running pod. First run “kubectl get pod” to get the name of the postgresql pod. Start “psql” on the pod by running the following:
kubectl exec <pod name> -t -i -- psql -U postgres -h localhost
This is the easiest way to connect to the PostgreSQL server instance, and since psql will use the Unix-domain socket the superuser password is not required. When the command above is ran you’ll have an interactive connection to psql console program. Run the SQL scripts in /app/backend/db to create the necessary role, ACL and data definition. After that create a login user for the Backend service that has a k8spractice_backend
role.
In the next post, we will deploy the k8spractice app to the cluster.