Accessing Postgresql data of Kubernetes cluster - postgresql

I have kubernetes cluster with two replicas of a PostgreSQL database in it, and I wanted to see the values stored in the database.
When I exec myself into one of the two postgres pod (kubectl exec --stdin --tty [postgres_pod] -- /bin/bash) and check the database from within, I have only a partial part of the DB. The rest of the DB data is on the other Postgres pod, and I don't see any directory created by the persistent volumes with all the database stored.
So in short I create 4 tables; in one postgres pod I have 4 tables but 2 are empty, in the other postgres pod there are 3 tables and the tables that were empty in the first pod, here are filled with data.
Why the pods don't have the same data in it?
How can I access and download the entire database?
PS. I deploy the cluster using HELM in minikube.
Here are the YAML files:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
labels:
app: postgres
data:
POSTGRES_DB: database-pg
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
PGDATA: /data/pgdata
---
kind: PersistentVolume
apiVersion: v1
metadata:
name: postgres-pv-volume
labels:
type: local
app: postgres
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
hostPath:
path: "/mnt/data"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: postgres-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: postgres
labels:
app: postgres
spec:
ports:
- name: postgres
port: 5432
nodePort: 30432
type: NodePort
selector:
app: postgres
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres-service
selector:
matchLabels:
app: postgres
replicas: 2
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:13.2
volumeMounts:
- name: postgres-disk
mountPath: /data
# Config from ConfigMap
envFrom:
- configMapRef:
name: postgres-config
volumeClaimTemplates:
- metadata:
name: postgres-disk
spec:
accessModes: ["ReadWriteOnce"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
labels:
app: postgres
spec:
selector:
matchLabels:
app: postgres
replicas: 2
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:13.2
imagePullPolicy: IfNotPresent
envFrom:
- configMapRef:
name: postgres-config
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgredb
volumes:
- name: postgredb
persistentVolumeClaim:
claimName: postgres-pv-claim
---

I found a solution to my problem of downloading the volume directory, however when I run multiple replicasets of postgres, the tables of the DB are still scattered between the pods.
Here's what I did to download the postgres volume:
First of all, minikube supports some specific directories for volume appear:
minikube is configured to persist files stored under the following directories, which are made in the Minikube VM (or on your localhost if running on bare metal). You may lose data from other directories on reboots.
/data
/var/lib/minikube
/var/lib/docker
/tmp/hostpath_pv
/tmp/hostpath-provisioner
So I've changed the mount path to be under the /data directory. This made the database volume visible.
After this I ssh'ed into minikube and copied the database volume to a new directory (I used /home/docker as the user of minikube is docker).
sudo cp -R /data/pgdata /home/docker
The volume pgdata was still owned by root (access denied error) so I changed it to be owned by docker. For this I also set a new password which I knew:
sudo passwd docker # change password for docker user
sudo chown -R docker: /home/docker/pgdata # change owner from root to docker
Then you can exit and copy the directory into you local machine:
exit
scp -r $(minikube ssh-key) docker#$(minikube ip):/home/docker/pgdata [your_local_path].
NOTE
Mario's advice, which is to use pgdump is probably a better solution to copy a database. I still wanted to download the volume directory to see if it has the full database, when the pods have only a part of all the tables. In the end it turned out it doesn't.

Related

unable to understand mounting postgres data path onto minikube kubernetes deployment with permission errors

I’m getting started with kubernetes, and I want to create a simple app with a single webserver & postgres database. The problem I’m running into is the deployment of the postgres is giving me permission errors. The following are discussions around this:
https://github.com/docker-library/postgres/issues/116
https://github.com/docker-library/postgres/issues/103
https://github.com/docker-library/postgres/issues/696
Can't get either Postgres permissions or PVC working in AKS
Kubernetes - Pod which encapsulates DB is crashing
Mount local directory into pod in minikube
https://serverfault.com/questions/981459/minikube-using-a-storageclass-to-provision-data-outside-of-tmp
EDIT
spec:
OSX - 10.15.4
minikube - v1.9.2
kubernetes - v1.18.2
minikube setup
minikube start --driver=virtualbox --cpus=2 --memory=5120 --kubernetes-version=v1.18.2 --container-runtime=docker --mount=true --mount-string=/Users/holmes/kubernetes/pgdata:/data/pgdata
The permission error: chmod: changing permissions of '/var/lib/postgresql/data': Operation not permitted
I am trying to mount a local OS directory into minikube to be used with the postgres deployment/pod/container volume mount.
After I run the above setup I ssh into minikube (minikube ssh) and check the permissions
# minikube: /
drwxr-xr-x 3 root root 4096 May 13 19:31 data
# minikube: /data
drwx------ 1 docker docker 96 May 13 19:27 pgdata
By running the script below the chmod permission error surfaces. If I change the --mount-string=/Users/holmes/kubernetes/pgdata:/data (leave out /pgdata) and then minikube ssh to create the pgdata directory:
mkdir -p /data/pgdata
chmod 777 /data/pgdata
I get a different set of permissions before deployment
# minikube: /
drwx------ 1 docker docker 96 May 13 20:10 data
# minikube: /data
drwxrwxrwx 1 docker docker 64 May 13 20:25 pgdata
and after deployment
# minikube: /
drwx------ 1 docker docker 128 May 13 20:25 data
# minikube: /data
drwx------ 1 docker docker 64 May 13 20:25 pgdata
Not sure why this changes, and the chmod permission error persists. It seems like the above reference links are bouncing around different methods on different machines on different vms which I don’t understand nor can I get this to work. Can someone walk me getting this to work? Super confused going through all the above discussions.
postgres.yaml
apiVersion: v1
kind: Namespace
metadata:
name: data-block
---
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
namespace: data-block
labels:
type: starter
data:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: docker
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgres-pv
namespace: data-block
labels:
app: postgres
spec:
capacity:
storage: 2Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data/pgdata
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pv-claim
namespace: data-block
labels:
app: postgres
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: ""
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
namespace: data-block
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:12.2
ports:
- containerPort: 5432
envFrom:
- configMapRef:
name: postgres-config
volumeMounts:
- name: postgres-vol
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-vol
persistentVolumeClaim:
claimName: postgres-pv-claim
UPDATE
I went ahead and updated the deployment script to a simple pod. The goal is map the postgres /var/lib/postgresql/data to my local file directory /Users/<my-path>/database/data to persist the data.
---
apiVersion: v1
kind: Pod
metadata:
name: postgres-pod
namespace: data-block
labels:
name: postgres-pod
spec:
containers:
- name: postgres
image: postgres:12.3
imagePullPolicy: IfNotPresent
ports:
- name: postgres-port
containerPort: 5432
envFrom:
- configMapRef:
name: postgres-env-config
- secretRef:
name: postgres-secret
volumeMounts:
- name: postgres-vol
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-vol
hostPath:
path: /Users/<my-path>/database/data
restartPolicy: Never
The error: initdb: error: could not access directory "/var/lib/postgresql/data": Permission denied
How to go about mounting the local file directory?
You are declaring the PGDATA field that maybe the cause of the issue. I faced the same error, this comes because there's as LOST+FOUND folder already in that directory however, the container wants it to be a empty dir. Giving the subPath field solves this issue. Please try this it should solve the issue and you need not need any PGDATA field. Try omitting it from your configmap and add subPath to some folder. Please go through following manifests.
https://github.com/mendix/kubernetes-howto/blob/master/postgres-deployment.yaml
https://www.bmc.com/blogs/kubernetes-postgresql/
it's a statefulset that usually you should go with and not a deployment when it comes to Database deployment.
- name: postgredb
mountPath: /var/lib/postgresql/data
#setting subPath will fix your issue it can be pgdata or
postgres or any other folder name according to your
choice.
subPath: postgres

How to have data persist in GKE kubernetes StatefulSet with postgres?

So I'm just trying to get a web app running on GKE experimentally to familiarize myself with Kubernetes and GKE.
I have a statefulSet (Postgres) with a persistent volume/ persistent volume claim which is mounted to the Postgres pod as expected. The problem I'm having is having the Postgres data endure. If I mount the PV at var/lib/postgres the data gets overridden with each pod update. If I mount at var/lib/postgres/data I get the warning:
initdb: directory "/var/lib/postgresql/data" exists but is not empty
It contains a lost+found directory, perhaps due to it being a mount point.
Using a mount point directly as the data directory is not recommended.
Create a subdirectory under the mount point.
Using Docker alone having the volume mount point at var/lib/postgresql/data works as expected and data endures, but I don't know what to do now in GKE. How does one set this up properly?
Setup file:
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: sm-pd-volume-claim
spec:
storageClassName: "standard"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1G
---
apiVersion: "apps/v1"
kind: "StatefulSet"
metadata:
name: "postgis-db"
namespace: "default"
labels:
app: "postgis-db"
spec:
serviceName: "postgis-db"
replicas: 1
selector:
matchLabels:
app: "postgis-db"
template:
metadata:
labels:
app: "postgis-db"
spec:
terminationGracePeriodSeconds: 25
containers:
- name: "postgis"
image: "mdillon/postgis"
ports:
- containerPort: 5432
name: postgis-port
volumeMounts:
- name: sm-pd-volume
mountPath: /var/lib/postgresql/data
volumes:
- name: sm-pd-volume
persistentVolumeClaim:
claimName: sm-pd-volume-claim
You are getting this error because the postgres pod has tried to mount the data directory on / folder. It is not recommended to do so.
You have to create subdirectory to resolve this issues on the statefulset manifest yaml files.
volumeMounts:
- name: sm-pd-volume
mountPath: /var/lib/postgresql/data
subPath: data

Kubernetes StatefulSet - does not resatore data on pod restart

Kubernetes version - 1.8
Created statefulset for postgres database with pvc
Added some tables to database
Restarted pod by scaling statefulset to 0 and then again 1
Created tables in step # 2 are no longer available
Tried another scnario with steps on docker-for-desktop cluster k8s version 1.10
Created statefulset for postgres database with pvc
Added some tables to database
Restarted docker for desktop
Created tables in step # 2 are no longer available
k8s manifest
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
labels:
app: postgres
data:
POSTGRES_DB: kong
POSTGRES_USER: kong
POSTGRES_PASSWORD: kong
PGDATA: /var/lib/postgresql/data/pgdata
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgres-pv
labels:
app: postgres
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/postgresql/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
labels:
app: postgres
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: postgres
app: postgres
spec:
ports:
- name: pgql
port: 5432
targetPort: 5432
protocol: TCP
selector:
app: postgres
---
apiVersion: apps/v1beta2 # for k8s versions before 1.9.0 use apps/v1beta2 and before 1.8.0 use extensions/v1beta1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: "postgres"
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:9.6
imagePullPolicy: "IfNotPresent"
ports:
- containerPort: 5432
envFrom:
- configMapRef:
name: postgres-config
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgredb
volumes:
- name: postgredb
persistentVolumeClaim:
claimName: postgres-pvc
---
If you have multiple nodes - the issue you see is totally expected. So if you want to use hostPath as a Persistent Volume in a multi-node cluster - you must use some shared filesystem like Glusterfs or Ceph and place your /mnt/postgresql/data folder onto that shared filesystem.

How to mount PostgreSQL data directory in Kubernetes?

I'm using minikube to run kubernetes locally. My local k8s have two pods which one of them is PostgreSQL and another one is my own app. I've mounted a PersistentVolume and PersistentVolumeClaim in order to make a stateful pod for PostgreSQL:
kind: PersistentVolume
apiVersion: v1
metadata:
name: postgres-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/data/psql"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Here is PostgreSQL deployment yaml file:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
template:
metadata:
labels:
name: postgres
spec:
containers:
- name: postgres
imagePullPolicy: Never
image: postgres:9.6
ports:
- name: postgres
containerPort: 5432
volumeMounts:
- mountPath: /var/lib/postgresql
name: postgres-persistent-storage
volumes:
- name: postgres-persistent-storage
persistentVolumeClaim:
claimName: postgres-pv-claim
The problem is that PostgreSQL service doesn't start and this error occurs when I run its pod:
Error: /var/lib/postgresql/9.6/main is not accessible; please fix the directory permissions (/var/lib/postgresql/9.6/ should be world readable)
No PostgreSQL clusters exist; see "man pg_createcluster" ... (warning).
I've checked inside of PostgreSQL pod and I found that /var/lib/postgresql is empty, just like /data/psql In minikube host.
Can anyone help?
Change:
volumeMounts:
- mountPath: /var/lib/postgresql
to
volumeMounts:
- mountPath: /var/lib/postgresql/data
With the wrong mountPoint postgres executables were overridden.
I attach an image with the data I see from inside the pod (on the left) and from inside minikube space (on the right, the little shell from virtualbox).

Kubernetes - Pod which encapsulates DB is crashing

I am experiencing issues when I try to deploy my Django application to Kubernetes cluster. More specifically, when I try to deploy PostgreSQL.
Here is what my .YML deployment file looks like:
apiVersion: v1
kind: Service
metadata:
name: postgres-service
spec:
selector:
app: postgres-container
tier: backend
ports:
- protocol: TCP
port: 5432
targetPort: 5432
type: ClusterIP
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgres-pv
labels:
type: local
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 2Gi
hostPath:
path: /tmp/data/persistent-volume-1 #U okviru cvora n
persistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pv-claim
labels:
type: local
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres-container
tier: backend
template:
metadata:
labels:
app: postgres-container
tier: backend
spec:
containers:
- name: postgres-container
image: postgres:9.6.6
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-credentials
key: user
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-credentials
key: password
- name: POSTGRES_DB
value: agent_technologies_db
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-volume-mount
mountPath: /var/lib/postgresql/data/db-files
volumes:
- name: postgres-volume-mount
persistentVolumeClaim:
claimName: postgres-pv-claim
- name: postgres-credentials
secret:
secretName: postgres-credentials
Here is what I get when I run kubectl get pods command :
NAME READY STATUS RESTARTS AGE
agent-technologies-deployment-7c7c6676ff-8p49r 1/1 Running 0 2m
agent-technologies-deployment-7c7c6676ff-dht5h 1/1 Running 0 2m
agent-technologies-deployment-7c7c6676ff-gn8lp 1/1 Running 0 2m
agent-technologies-deployment-7c7c6676ff-n9qql 1/1 Running 0 2m
postgres-8676b745bf-8f7jv 0/1 CrashLoopBackOff 4 3m
And here is what I get when I try to inspect what is going on with PostgreSQL deployment by using kubectl logs $pod_name:
initdb: directory "/var/lib/postgresql/data" exists but is not empty
If you want to create a new database system, either remove or empty
the directory "/var/lib/postgresql/data" or run initdb
with an argument other than "/var/lib/postgresql/data".
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.
The database cluster will be initialized with locale "en_US.utf8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".
Data page checksums are disabled.
Note: I am using Google Cloud as a provider.
You can't have your db in /var/lib/postgres/data/whatever.
Change that path by /var/lib/postgres/whatever and it will work.
17.2.1. Use of Secondary File Systems
Many installations create their database clusters on file systems (volumes) other than the machine's "root" volume. If you choose to do this, it is not advisable to try to use the secondary volume's topmost directory (mount point) as the data directory. Best practice is to create a directory within the mount-point directory that is owned by the PostgreSQL user, and then create the data directory within that. This avoids permissions problems, particularly for operations such as pg_upgrade, and it also ensures clean failures if the secondary volume is taken offline.
And, by the way, I had to create a secret, as it is not in the post:
apiVersion: v1
kind: Secret
metadata:
name: postgres-credentials
type: Opaque
data:
user: cG9zdGdyZXM= #postgres
password: cGFzc3dvcmQ= #password
Note that the username needs to be "postgres". I don't know if you are covering this...
Adding to what #suren answered.
I had this issue while running postgresql-setup --initdb in RHEL 8.4. I was getting this error :
Initializing database in '/var/lib/pgsql/data'
ERROR: Initializing database failed, possibly see /var/lib/pgsql/initdb_postgresql.log
So, following suren's suggestion, I deleted the 'data' folder and ran the command again. Worked like a charm!