Run PostgreSQL
This assumes you can already reach your cluster with kubectl (see the
kubectl quickstart).
You’ll deploy a single PostgreSQL instance in its own namespace, backed by persistent storage so its data survives pod restarts. The cluster’s default StorageClass provisions the volume for you.
Deploy
Section titled “Deploy”Create a dedicated namespace:
kubectl create namespace postgresDeploy the database, its storage, and a Service into the namespace:
cat <<'EOF' | kubectl apply -f -apiVersion: v1kind: Secretmetadata: name: postgres namespace: postgresstringData: POSTGRES_PASSWORD: change-me---apiVersion: v1kind: PersistentVolumeClaimmetadata: name: postgres namespace: postgresspec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi---apiVersion: apps/v1kind: Deploymentmetadata: name: postgres namespace: postgresspec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: postgres template: metadata: labels: app: postgres spec: containers: - name: postgres image: postgres:16 env: - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: postgres key: POSTGRES_PASSWORD # Subdir keeps initdb off the volume's lost+found. - name: PGDATA value: /var/lib/postgresql/data/pgdata ports: - containerPort: 5432 volumeMounts: - name: data mountPath: /var/lib/postgresql/data volumes: - name: data persistentVolumeClaim: claimName: postgres---apiVersion: v1kind: Servicemetadata: name: postgres namespace: postgresspec: selector: app: postgres ports: - port: 5432 targetPort: 5432EOFSecurity
Section titled “Security”This Service is ClusterIP, so the database is only reachable from inside the
cluster. On a single-tenant skube cluster that’s the safe default: keep your app
and database in the cluster and connect over the Service with no TLS.
If you need to reach it from outside the cluster:
- For occasional access, prefer
kubectl port-forward -n postgres service/postgres 5432:5432over a public endpoint. It tunnels through the API server and exposes nothing. - To expose it for real, enable PostgreSQL’s own TLS (
ssl = onwith a cert and key). The Ingress and Gateway guides are HTTP-only and don’t apply to the Postgres wire protocol. - Use a strong password, not
change-me, and rotate the secret if it leaks.
Connect
Section titled “Connect”Check it’s accepting queries:
kubectl exec -n postgres deploy/postgres -- psql -U postgres -c "SELECT version();"Open an interactive psql shell inside the pod:
kubectl exec -n postgres -it deploy/postgres -- psql -U postgresFrom there, \l lists databases and \dt lists tables in the current one.
Other workloads in the cluster connect with this URI (<password> is the value
from the secret above):
postgresql://postgres:<password>@postgres.postgres.svc.cluster.local:5432/postgresClean up
Section titled “Clean up”Delete the namespace to remove everything at once:
kubectl delete namespace postgresThis destroys the database’s data along with it.