Direct naar content

How to Postgres on Kubernetes, deel 1

Inmiddels alweer de nodige jaren geleden schreef collega Craig een driedelig blog over PostgreSQL in combinatie met Docker. De techniek heeft niet stil gestaan en een update is dan ook wel op zijn plaats, vond Nathan Koopmans, cloudplatform-engineer bij OptimaData. Daarom: How to Postgres on Kubernetes.

Deze blog is onderdeel van een tweeluik versie. Lees hieronder deel 2
Deel 2

Verschillen tussen Docker en Kubernetes

In deze blog ga ik er vanuit dat je al een werkende Kubernetes-setup hebt. Of dit nu met MiniKube, K3s, een lokale complete Kubernetes-setup is of bij een cloudprovider als AWS, GCP of Azure, dat maakt niet uit. Zelf gebruik ik onze lokale Kubernetes-omgeving. Kubernetes heeft een paar voordelen ten opzichte van Docker, waaronder het stukje self-healing. Om de verschillen tussen Docker en Kubernetes overzichtelijk te maken, heb ik een mooie afbeelding van internet geleend.

Verschillen tussen Docker en Kubernetes

De basis

Laten we beginnen bij het begin. Daarom laat ik in deel één een setup zien op basis van een standaard PostgreSQL-image, in blog deel twee (over 2 weken) zal ik een Kubernetes-database-operator (CloudnativePG / EDB Operator) gebruiken. Maar nu eerst: Plain PostgreSQL.

Eerst maak je een YAML file aan om hierin een aantal zaken te definiëren voor de PostgreSQL-pod / -container. Welke zaken zijn nodig en waarvoor dienen ze?

Secret

Een secret is een nette manier om data zoals wachtwoorden op te slaan. In het geval van PostgreSQL geef je een user en password op om te gebruiken voor verbinding met de database. Secrets zijn voor meerdere pods te gebruiken en bevatten slechts een kleine hoeveelheid aan data. Voor alle ins- en outs over secrets kan je terecht op de Kubernetes-pagina over secrets.

apiVersion: v1

kind: Secret

metadata:

  name: postgres-env

type: Opaque

stringData:

  POSTGRES_USER: example

  POSTGRES_PASSWORD: verysecret

---

PersistentVolumeClaim

Een PersistentVolumeClaim is een claim op een stukje ruimte om te gebruiken. Deze wordt gekoppeld aan een pod, zodat hier data opgeslagen kan worden. Dit heeft als voordeel dat bij het crashen van een pod, de data niet verloren gaat, maar meegenomen worden in een nieuwe pod. Je vindt meer info over PVCs en alle opties die er zijn op de Kubernetes-website.

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

  name: postgres-pv-claim

spec:

  accessModes:

  - ReadWriteOnce

  resources:

    requests:

      storage: 1Gi

---

Deployment:

De deployment zorgt voor het aanmaken en beheren van de pods binnen de deployment. Wanneer je de deployment schaalt van een naar twee pods, zorgt de deployment ervoor dat de kube-scheduler de tweede pod aan gaat maken. Pas je iets aan in de deployment, dan zullen de pods een voor een worden vervangen met de gewenste aanpassingen.

In de deployment geef je ook aan welke volumes (claims) gebruikt moeten worden. Indien gewenst kan je ook andere resources definieren, zoals bijvoorbeeld CPU en RAM gebruik. Meer info vind je op de Kubernetes-website.

Kubernetes website

apiVersion: apps/v1

kind: Deployment

metadata:

  labels:

    app: postgres

  name: postgresql

spec:

  replicas: 1

  strategy:

    type: Recreate

  selector:

    matchLabels:

      app: postgres

  template:

    metadata:

      labels:

        app: postgres

    spec:

      containers:

      - envFrom:

        - secretRef:

            name: postgres-env

        image: docker.io/postgres:14

        name: postgresql

        ports:

        - containerPort: 5432

          name: postgresql

        volumeMounts:

        - mountPath: /var/lib/postgresql

          name: postgres-data

      volumes:

      - name: postgres-data

        persistentVolumeClaim:

          claimName: postgres-pv-claim

Bij mij ziet het er dan uiteindelijk zo uit:

Postgres on Kubernetes deployment example

Postgres on Kubernetes deployment example part 2

Let op de “—” zoals ik deze hierboven in het screenshot heb gebruikt. Vergeet deze niet toe te voegen!

Best practise

Om alles schoon en overzichtelijk te houden, maak je een aparte namespace aan waar je deze container deployt. Omdat ik voor deze blog nog geen aparte namespace heb, maak ik deze nu eerst aan:

kubectl create ns postgresdeploy

Postgres on Kubernetes best practise namespace

De namespace is succesvol aangemaakt. Nu is het tijd om de YAML-file toe te passen zodat de Secret, PersistentVolumeClaim en de Deployment aangemaakt worden:

kubectl apply -f postgresdeploy.yaml -n postgresdeploy

Postgres on Kubernetes deployment example YAML file

Krijg je geen foutmelding? Dan heb je het goed gedaan. Krijg je wel een foutmelding, dan heeft dit meestal met een tikfout of indentatie te maken. YAML is erg gevoelig voor de uitlijning van de verschillende onderdelen in de file.

Controle

Geef het proces een paar minuten om alles aan te maken en te starten. Daarna kan je controleren of alles aangemaakt is en de container ready is en als status Running heeft.

kubectl get all -n postgresdeploy

Postgres on Kubernetes deployment check

Wat opvalt is dat de PVC hier mist. Dat is correct omdat een PVC clusterbreed is. Wil je controleren of de PVC is aangemaakt? Voer dan het volgende commando uit:

kubectl get pvc -n postgresdeploy

Postgres on Kubernetes deployment PVC

Verbinding maken

Nu ga je verbinding maken met de container:

kubectl exec -it postgresql-d684bfd65-5cjzm -n postgresdeploy -- /bin/bash

Je krijgt dan de bashprompt. Voer nu in:

su - postgres

Dit zorgt ervoor dat je de postgres-user wordt die standaard binnen de postgres-image actief is. Tik vervolgens het volgende in:

psql -U example

En voila, je zit in postgres. Via deze weg hoef je geen wachtwoord in te voeren. Bij extern verbinden wordt wel om het wachtwoord gevraagd.

Met l+ controleer ik vervolgens of ik data terug krijg en alles naar behoren reageert.