Esercizio: Persistenza Postgres
Persistenza di applicativo postgres
La datadir di postgres è mappata ad un Persistent Volume.
Passi di Esecuzione
Per preparare un servizio postgres occorre:
- acquisire l’immagine nel registry locale
- PV e PVC per postgres
- secrets per postgres
- deployment e servizio per postgres
I secrets necessari si scoprono consultando sul web il sito per ‘postgres docker’
- nel nostro caso
POSTGRES_PASSWORD
Immagine in Registry Locale
Dalla macchina host:
docker pull postgres:12.2
docker tag postgres:12.2 localhost:5000/postgres:12.2
docker push localhost:5000/postgres:12.2
PV e PVC per postgres
Nel container kub, prepariamo la directory per gli scripts:
mkdir -p ~/scripts/pg
Il manifest è ~/scripts/pg/pg-volume.yml
vim ~/scripts/pg/pg-volume.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgres-pv-volume
spec:
storageClassName: standard
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data/pg/
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: postgres-pv-claim
spec:
volumeName: postgres-pv-volume
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
Applicare la configurazione:
kubectl apply -f ~/scripts/pg/pg-volume.yml
Secrets per postgres
La password di postgres sarà ‘secret’. Quindi:
echo -n secret | base64
c2VjcmV0
Il manifest è ~/scripts/pg/pg-secret.yml
:
vim ~/scripts/pg/pg-secret.yml
apiVersion: v1
kind: Secret
metadata:
name: pg-secret
type: Opaque
data:
root-password: c2VjcmV0
Applicare il file di configurazione:
kubectl apply -f ~/scripts/pg/pg-secret.yml
Deployment e Servizio
Anch'essi si possono combinare in un’unica configurazione. E’ raro che vi sia un deployment senza servizio.
Il manifest è ~/scripts/pg/pg-deployment.yml
:
vim ~/scripts/pg/pg-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pg-deployment
labels:
app: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
volumes:
- name: postgresdb
persistentVolumeClaim:
claimName: postgres-pv-claim
containers:
- name: postgres
image: localhost:5000/postgres:12.2
volumeMounts:
- name: postgresdb
mountPath: /var/lib/postgresql/data
ports:
- containerPort: 5432
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: pg-secret
key: root-password
---
apiVersion: v1
kind: Service
metadata:
name: pg-service
spec:
selector:
app: postgres
type: LoadBalancer
ports:
- protocol: TCP
port: 5432
targetPort: 5432
Applicare la configurazione:
kubectl apply -f ~/scripts/pg/pg-deployment.yml
Attendere la generazione dei pods con:
kubectl get pods
Test dell'Esercizio
Creare un oggetto in postgres
Connettersi al pod che ha postgres:
kubectl get pods
NAME READY STATUS RESTARTS AGE
pg-deployment-794d8fcb76-c2hnn 1/1 Running 0 72s
Collegarsi con una shell al pod:
kubectl exec -ti pg-deployment-794d8fcb76-c2hnn -- bash
Naturalmente il nome del pod sarà diverso.
Verificare di essere sul pod:
hostname
pg-deployment-794d8fcb76-c2hnn
Connettersi al database:
psql -U postgres
psql (12.2 (Debian 12.2-2.pgdg100+1))
Type "help" for help.
postgres=#
La connessione può fallire. Postgres la prima volta che viene lanciato crea la struttura della sua datadir, e questo può impiegare qualche minuto.
Semplicemente attendere e riprovare.
Postgres ha nella sua datadir il file di configurazione di accessi pg_hba.conf
. Contiene di default un settaggio che permette l'accesso come utente amministrativo postgres
dalla macchina locale, senza che venga chiaesta la password.
Listare i database correnti: \l
Creare un database: create database test;
Listare di nuovo i database correnti: \l
Uscire dalla connessione a database: \q
Rimuovere tutto e ricreare tutto da capo, poi verificare se il database test esiste ancora.
Prossimi passi:
- uscire dal pod:
exit
- rimuovere il cluster:
~/teardown.sh
Sulla macchina host verificare la persistenza dei dati:
sudo ls /data/pg
Ripartenza e Test di Connettività
cd
./setup.sh
Procedure Shell per l'Applicativo
Per automatizzare il setup e teardown dell’applicativo postgres creiamo due procedure shell, nella directory di postgres.
~/scripts/pg/pg-setup.sh
vim ~/scripts/pg/pg-setup.sh
#! /bin/sh
echo "Starting application: postgres"
kubectl apply -f ~/scripts/pg/pg-volume.yml
kubectl apply -f ~/scripts/pg/pg-secret.yml
kubectl apply -f ~/scripts/pg/pg-deployment.yml
echo
echo "Wait up to 120s for Postgres deployment to be ready ..."
kubectl wait deployment -n default pg-deployment --for condition=Available=True --timeout=120s
echo
echo " POSTGRES NOW READY"
echo " ===> Pods running:"
kubectl get pods
La rendiamo eseguibile:
chmod +x ~/scripts/pg/pg-setup.sh
~/scripts/pg/pg-teardown.sh
vim ~/scripts/pg/pg-teardown.sh
#! /bin/sh
echo "About to delete application 'postgres'"
echo "Press Control-C within 10 seconds to interrupt"
sleep 10
kubectl delete -f ~/scripts/pg/pg-deployment.yml
kubectl delete -f ~/scripts/pg/pg-secret.yml
kubectl delete -f ~/scripts/pg/pg-volume.yml
echo
echo "Application deleted: postgres"
La rendiamo eseguibile:
chmod +x ~/scripts/pg/pg-teardown.sh
Continua il Test dell'Applicativo
Setup dell’applicativo:
~/scripts/pg/pg-setup.sh
....
===> Pods running:
NAME READY STATUS RESTARTS AGE
pg-deployment-794d8fcb76-sqwtf 1/1 Running 0 17s
Verifica del servizio:
kubectl get svc
Collegamento al pod:
kubectl exec -ti pg-deployment-794d8fcb76-sqwtf -- bash
Collegamento a postgres:
psql -U postgres
Verifica dei database esistenti:
\l
Uscita da postgres:
\q
Uscita dal pod:
exit
Test di Connettività
Creare un container alpine sulla rete kind:
docker run -ti --rm --name alp --privileged --net kind alpine sh
Siamo nel container alpine. Installare il client postgres:
apk add postgresql-client
Connettersi:
psql -U postgres -h 172.18.255.200
Da il seguente errore:
psql: error: connection to server at "172.18.255.200", port 5432 failed: FATAL: no pg_hba.conf entry for host "10.244.2.1", user "postgres", database "postgres", SSL off
Uscire con exit
.
Il file di configurazione di accessi di Postgres, pg_hba.conf
, di default può non contenere linee di configurazione per l'accesso da host remoti.
Queste linee hanno uno dei seguenti formati:
host all all 0.0.0.0/0 md5
host all all all md5
Tenendo conto che la datadir di Postgres è mappata sulla macchina ospite alla directory /data/pg
, possiamo modificare il file di configurazione col comando:
sudo vim /data/pg/pg_hba.conf
aggiungendo la linea di configurazione:
host all all 0.0.0.0/0 md5
Occorre ora far ripartire il server postgres con:
kubectl delete -f ~/scripts/pg/pg-deployment.yml
kubectl apply -f ~/scripts/pg/pg-deployment.yml
Non potevamo modificare prima il file /data/pg/pg_hba.conf
perchè la directory /data/pg
ancora non esisteva, o non era ancora stata popolata come datadir.
Rilanciamo quindi il contenitore docker, installiamo il client postgres e riproviamo la connessione:
docker run -ti --rm --name alp --privileged --net kind alpine sh
apk add postgresql-client
psql -U postgres -h 172.18.255.200
Password for user postgres: secret
psql (14.5, server 12.2 (Debian 12.2-2.pgdg100+1))
Type "help" for help.
postgres=#
Test OK.
Uscire da postgres e dal container alpine.
Teardown dell’applicativo:
~/scripts/pg/pg-teardown.sh
Riscrittura di pg-setup.sh
Il problema è che non vogliamo editare un file a mano, ma vogliamo che tutte le attività vengano compiute in modo batch.
Riscriviamo quindi la procedura shell ~/scripts/pg/pg-setup.sh
.
vim ~/scripts/pg/pg-setup.sh
#! /bin/sh
echo "Starting application: postgres"
kubectl apply -f ~/scripts/pg/pg-volume.yml
kubectl apply -f ~/scripts/pg/pg-secret.yml
kubectl apply -f ~/scripts/pg/pg-deployment.yml
echo
echo "Wait up to 120s for Postgres deployment to be ready ..."
kubectl wait deployment -n default pg-deployment --for condition=Available=True --timeout=120s
echo
echo " POSTGRES NOW READY"
echo " ===> Pods running:"
kubectl get pods
# pod running the deployment
pod=$(kubectl get pod | grep pg-deployment | cut -d\ -f1)
echo "Waiting for datadir to be ready"
cycles=30
while true
do
cycles=`expr $cycles - 1`
if kubectl logs $pod | grep "ready to accept connections"
then
echo "Datadir ready"
break
else
if [ $cycles -le 0 ]
then
echo "Losing patience. Patch pg_hba.conf yourself"
exit 1
fi
echo "Not ready yet, waiting 10 seconds"
sleep 10
fi
done
if sudo grep "host" /data/pg/pg_hba.conf | grep 0.0.0.0 \
|| sudo grep "host all all all md5" /data/pg/pg_hba.conf
then
echo pg_hba.conf is already patched
else
sudo sed -i -e '$ahost all all 0.0.0.0/0 md5' /data/pg/pg_hba.conf
echo pg_hba.conf has been patched
echo Stopping the postgres service:
kubectl delete -f ~/scripts/pg/pg-deployment.yml
echo Restarting the postgres service:
kubectl apply -f ~/scripts/pg/pg-deployment.yml
echo "Wait up to 120s for Postgres deployment to be ready ..."
kubectl wait deployment -n default pg-deployment --for condition=Available=True --timeout=120s
echo
echo " POSTGRES NOW REALLY READY"
fi
Connessione Esterna
Da un semplice container sulla stessa rete del cluster:
docker run -ti --rm --net kind --name client \
postgres:12.2 psql -h 172.18.255.200 -U postgres
Da un container che implementa un'utility grafica:
docker run -d --rm --name omnidb --net kind -v "$HOME/pg/omnidb":/data -p 127.0.0.1:8000:8000 -p 127.0.0.1:25482:25482 t4skforce/omnidb
- collegarsi con un browser a
localhost:8000
- credenziali di login:
admin/admin
- creare una nuova scheda di connessione
- usare la connessione
- uscire da omnidb
Altra utility grafica:
docker run -d --net kind --name pgadmin -p 8080:80 -e 'PGADMIN_DEFAULT_EMAIL=mich@stormforce.ac' -e 'PGADMIN_DEFAULT_PASSWORD=supersecret' dpage/pgadmin4