Introduction
PostgreSQL is one of the most popular open-source relational databases, and deploying it on Kubernetes (K8s) ensures scalability, high availability, and fault tolerance. This guide walks you through deploying PostgreSQL on Kubernetes using a NodePort service, allowing external access to the database.
We will also cover common issues faced during deployment and how to resolve them.
Step 1: Setting Up PostgreSQL on Kubernetes
1.1 Create a Persistent Volume (PV)
A Persistent Volume (PV) ensures PostgreSQL data persists even if the pod restarts.
Save the following YAML as psql-pv.yaml:
apiVersion: v1
kind: PersistentVolume
metadata:
  name: postgres-volume
  labels:
    type: local
    app: postgres
spec:
  storageClassName: manual
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteMany
  hostPath:
    path: /data/postgresql💡 Explanation:
- 20Gi storage is allocated for PostgreSQL.
 - ReadWriteMany (
RWX) allows multiple pods to read and write. hostPathensures data persistence on the node.
Apply the PV:
kubectl apply -f psql-pv.yaml1.2 Create a Persistent Volume Claim (PVC)
A Persistent Volume Claim (PVC) allows the PostgreSQL pod to request storage.
Save the following as psql-claim.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-volume-claim
  labels:
    app: postgres
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 20GiApply the PVC:
kubectl apply -f psql-claim.yaml💡 PVC will bind to the Persistent Volume (postgres-volume) automatically.
1.3 Create a ConfigMap for PostgreSQL Environment Variables
The ConfigMap stores database configuration parameters.
Save the following as postgres-configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-secret
  labels:
    app: postgres
data:
  POSTGRES_DB: core_mdm_dev
  POSTGRES_USER: app_user
  POSTGRES_PASSWORD: =MFIck)d]#F;vE98ffmRApply the ConfigMap:
kubectl apply -f postgres-configmap.yaml1.4 Deploy PostgreSQL
Now, create the PostgreSQL Deployment file and save it as ps-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres
  namespace: postgres
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: 'postgres:16'
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 5432
          envFrom:
            - configMapRef:
                name: postgres-secret
          volumeMounts:
            - mountPath: /var/lib/postgresql/data
              name: postgresdata
      volumes:
        - name: postgresdata
          persistentVolumeClaim:
            claimName: postgres-volume-claimApply the deployment:
kubectl apply -f ps-deployment.yaml1.5 Expose PostgreSQL Using NodePort
A NodePort service allows external access to the PostgreSQL database.
Save the following as ps-service.yaml:
apiVersion: v1
kind: Service
metadata:
  name: postgres
  labels:
    app: postgres
spec:
  type: NodePort
  selector:
    app: postgres
  ports:
    - name: postgres
      port: 5432           # The port PostgreSQL uses
      targetPort: 5432      # The port on the container (should be the same as 'port')
      nodePort: 31543       # NodePort that Kubernetes should expose
      protocol: TCPApply the service:
kubectl apply -f ps-service.yamlStep 2: Verify PostgreSQL Deployment
Check if the PostgreSQL pod is running:
kubectl get pods -n postgresIf running successfully, you should see:
NAME                        READY   STATUS    RESTARTS   AGE
postgres-xxxxxxxxxx-xxxxx   1/1     Running   0          10sNow, connect to PostgreSQL inside the pod:
kubectl exec -it $(kubectl get pods -n postgres -l app=postgres -o jsonpath='{.items[0].metadata.name}') -n postgres -- psql -U app_user -d postgresList available databases:
\lCommon Issues and How to Fix Them
1.1  PostgreSQL Pod in CrashLoopBackOff or Error State
Cause: Corrupt WAL (Write-Ahead Log)
PANIC: could not locate a valid checkpoint recordSolution: Reset WAL Logs
- Start a recovery pod:
 
kubectl apply -f postgres-recovery.yaml- Connect and reset WAL logs:
 
kubectl exec -it postgres-recovery -n postgres -- bash
su - postgres
/usr/lib/postgresql/16/bin/pg_resetwal -f /var/lib/postgresql/data- Delete the recovery pod and restart PostgreSQL:
 
kubectl delete pod postgres-recovery -n postgres
kubectl rollout restart deployment postgres -n postgres1.2 Cannot Delete a Database (Ghost Database)
Cause: Active connections or system corruption
ERROR:  database "lgn_section_dev" does not existSolution:
- Terminate active connections:
 
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'lgn_section_dev';- Manually delete the corrupted database entry:
 
DELETE FROM pg_database WHERE datname = 'lgn_section_dev';- Remove database files from storage (inside pod):
 
rm -rf /var/lib/postgresql/data/base/<OID>- Restart PostgreSQL:
 
kubectl rollout restart deployment postgres -n postgres1.3 External Connection Failing
Cause: PostgreSQL is not accepting external connections
Check if PostgreSQL is listening on all IPs:
SHOW listen_addresses;If not, update postgresql.conf:
ALTER SYSTEM SET listen_addresses TO '*';Restart PostgreSQL:
kubectl rollout restart deployment postgres -n postgresConclusion
Deploying PostgreSQL on Kubernetes with NodePort is a powerful way to manage database workloads in a containerized environment. By setting up Persistent Volumes, ConfigMaps, and a NodePort Service, we ensure data persistence and external access.




