Postgres Kubernetes Deployment
December 11, 2024
This is an overview of setting up a Postgres server in my Kubernetes homelab. I wanted a database server (I like postgres) running in my cluster that multiple apps could use.
Setting up a Postgres server in my Kubernetes homelab was very informative and I learned a lot about k8s in the process. Using a deployment for a database in Kubernetes is only for development and testing.
Design Decision
In order to have persistent data storage and backup and restore capabilities for a database in Kubernetes you should use a StatefulSet. For learning and experimenting with a single node cluster, I am currently using k3s, I decided to use a deployment for postgres.
The requirements I had for postgres:
- Custom config file for starting the postgres server
- Persistent data directory
- init files for the postgres container, to create tables and seed data
- A postgres server available to other pods and services
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
namespace: postgres
labels:
app: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
name: postgres
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
imagePullPolicy: IfNotPresent
args: ["-c", "config_file=/config/postgresql.conf"]
ports:
- containerPort: 5432
envFrom:
- secretRef:
name: db-credentials
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
- name: config
mountPath: /config
- name: init
mountPath: /docker-entrypoint-initdb.d
volumes:
- name: data
persistentVolumeClaim:
claimName: pg-data-pvc
- name: config
persistentVolumeClaim:
claimName: pg-config-pvc
- name: init
persistentVolumeClaim:
claimName: pg-init-pvc
restartPolicy: Always
Problem-solving Approaches
Since I am currently using a single node cluster for development, I created PVs on the node with local-path
for data,
config, and the init directories. This would allow for the files to exist so I could mount the init files for the postgres container.
k3s provides a local-path StorageClass.
For the database credentials I am using a k8s secret that sets environment variables for the container. For development this is adequate. There are better options for production.
Other apps in the cluster need to access the postgres server, so I exposed the database with a service in a separate k8s namespace using ClusterIP.
Future Improvements
Next steps for Postgres in my homelab is to create a StatefulSet in k8s and persistent data storage and implement backups.
Lessons Learned
I learned about how pods and PVs behave using deployments, especially with multinode clusters. Deployments are not used for applications that have state. I have a better understanding of DNS in pods and services.
The yaml files are available in my homelab github repo