Mai 26, 2023 | Kubernetes, Tutorial

ReadWriteMany (RWX) mit dem NFS Ganesha Provisioner

von

Einführung

Du hast die Anforderung, dass Deine Anwendung für eine Lastverteilung über mehrere Nodes skalieren muss, aber Zugriff auf ein gemeines PVC benötigt? Zu diesem Zweck benötigst Du ein PVC welches RWX-fähig ist. Im Rahmen unserer Managed Kubernetes Cluster ist es möglich, einen CSI Cinder Blockstorage zu erstellen. Dieser ist jedoch wegen technischer Limitierungen nur ReadWriteOnce (RWO) fähig. Wie wir mittels eines Workarounds dennoch ein RWX-fähiges PVC auf die Beine stellen, zeigen wir Dir hier an einen Beispiel aus der Praxis! Was PVCs sind, wird im Tutorial Persistente Volumes in Kubernetes erstellen erklärt, auf welchem das vorliegende Tutorial aufbaut. Nehmen wir beispielsweise einen Webserver, welcher auf seinen PVC HTML-Seiten, Bilder, JS etc. gespeichert hat. Diese Dateien sollen einmalig hochgeladen und allen Instanzen des Webservers gleichzeitig zur Verfügung gestellt werden. Um die Last besser zu verteilen, wird das Deployment entsprechend skaliert. Somit laufen mehrere Pods des gleichen Types auf unterschiedlichen Servern. Damit alle Pods – über Hostgrenzen hinweg – Zugriff auf die Dateien haben, erstellen wir eine RWX Storageclass mit den nfs-ganesha-server-and-external-provisioner. Als Grundlage hierfür dient ein NWS Managed Kubernetes Cluster. Nach Abschluss des Workarounds haben wir die Möglichkeit, PVCs zu erstellen, welche durch mehrere Pods gleichzeitig gelesen und beschrieben werden können. Ein Hinweis vorweg: das beschriebene Setup ist nicht HA fähig!  

Voraussetzungen

Das Tutorial setzt Folgendes voraus:

  • NWS Managed Kubernetes Cluster
  • kubectl
  • helm

Weitere Informationen zu diesen Themen findest Du bei uns in den NWS Docs  

Einrichtung

Mit folgendem Befehl fügen wir das Helm Repository hinzu, welches uns den nfs-ganesha-server-and-external-provisioner bereitstellt, nachfolgend NFS Provisioner genannt. 

$ helm repo add nfs-ganesha-server-and-external-provisioner \
https://kubernetes-sigs.github.io/nfs-ganesha-server-and-external-provisioner/

Danach können wir sofort mit der Installation loslegen. Zu beachten sind die Einstellungen, die dem –set Parameter folgen. Diese bewirken:

  •  persistence.enabled=true 
    Dieser Parameter stellt sicher, dass unsere Daten auf einem persistenten Volume gespeichert werden und auch nach Neustart des Pods noch vorhanden sind.

  • persistence.storageClass=standard
    Hier wird angegeben, dass für die persistenten Daten die Storageclass „standard“ genutzt werden soll.

  • persistence.size=200Gi
    Dieser Parameter gibt an, wie groß das PVC sein soll, welches der NFS Provisioner für die Dateien holt.

Zu beachten ist, dass die PVC Größe, welche mit persistence.size angegeben wird, für alle NFS PVCs geteilt wird, welche über den NFS Provisioner bezogen werden. Es gibt noch viele weitere Konfigurationsoptionen mit denen der NFS Provisioner an die eigenen Bedürfnisse angepasst werden kann. Diese findest du hier 

$ helm install nfs-server \
nfs-ganesha-server-and-external-provisioner/nfs-server-provisioner \
--set persistence.enabled=true \
--set persistence.storageClass=standard,persistence \
--set size=200Gi

Wenn der NFS Provisioner erfolgreich installiert werden konnte, erscheint eine Ausgabe wie folgt: 

NAME: nfs-server
LAST DEPLOYED: Mon May 22 14:41:58 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The NFS Provisioner service has now been installed.
 
A storage class named 'nfs' has now been created and is available to provision dynamic volumes.
 
You can use this storageclass by creating a `PersistentVolumeClaim` with the correct storageClassName attribute. For example:
 
    ---
    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: test-dynamic-volume-claim
    spec:
      storageClassName: "nfs"
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 100Mi

Nun sehen wir uns den eben erstellten NFS Provisioner Pod an und prüfen ob dieser läuft: 

kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE
nfs-server-nfs-server-provisioner-0   1/1     Running   0          36m

Und natürlich auch die dazugehörige Storageclass für die automatische Bereitstellung von NFS RWX PVCs. Diesen können wir nun verwenden, um dynamisch PVCs vom Typ RWX zu erstellen und zu nutzen. 

$ kubectl get storageclass
NAME                  PROVISIONER                                       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
encrypted             cinder.csi.openstack.org                          Delete          Immediate           true                   3h22m
encrypted-high-iops   cinder.csi.openstack.org                          Delete          Immediate           true                   3h22m
high-iops             cinder.csi.openstack.org                          Delete          Immediate           true                   3h22m
nfs                   cluster.local/nfs-server-nfs-server-provisioner   Delete          Immediate           true                   39m
nws-storage           cinder.csi.openstack.org                          Delete          Immediate           true                   3h22m
standard (default)    cinder.csi.openstack.org                          Delete          Immediate           true                   3h22m

Webserver Beispiel

Wir haben jetzt ein PVC mit der Eigenschaft RWX welches wir dynamisch provisionieren können. Nun sehen wir uns konkret an, wie dieser in ein Deployment eingebunden wird. Wir legen zwei Dateien an; eine für unser Deployment des Webservers und eine für das RWX PVC: 

# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: webserver
  name: webserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webserver
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: webserver
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        volumeMounts:
        - mountPath: /files
          name: files
      volumes:
      - name: files
        persistentVolumeClaim:
          claimName: nfs-pvc 
# nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
  storageClassName: nfs

Unser Deployment gibt an, dass wir vom NGiNX Container genau eine Replika laufen lassen wollen. Dieses bindet das dynamisch erstellte NFS PVC unter /files ein. Jetzt müssen wir die Definitionen noch mittels kubectl an Kubernetes verfüttern: 

$ kubectl apply -f nfs-pvc.yaml nginx-deployment.yaml
persistentvolumeclaim/nfs-pvc created
deployment.apps/webserver created

Wie wir sehen, läuft ein Webserver Pod: 

$ kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE
nfs-server-nfs-server-provisioner-0   1/1     Running   0          54m
webserver-5486dd9cf5-hfhnd            1/1     Running   0          114s

Nachdem dieser aber bei weitem nicht für unsere Last ausreicht, erweitern wir das Deployment auf 4 Replikationen: 

$ kubectl scale deployment webserver --replicas=4
deployment.apps/webserver scaled

Es empfiehlt sich ein kleiner Check und siehe da, alle 4 Pods laufen fröhlich vor sich hin: 

$ kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE
nfs-server-nfs-server-provisioner-0   1/1     Running   0          55m
webserver-5486dd9cf5-hfhnd            1/1     Running   0          3m9s
webserver-5486dd9cf5-nh9fl            1/1     Running   0          18s
webserver-5486dd9cf5-ss27f            1/1     Running   0          18s
webserver-5486dd9cf5-xl2lj            1/1     Running   0          18s

Jetzt prüfen wir noch, ob das NFS auch zwischen den Pods richtig funktioniert. Ein erster Befehl zeigt uns, dass /files leer ist. Mithilfe eines zweiten Befehls erstellen wir die Datei nfs-is-rwx. An der dritten Ausgabe können wir erkennen, dass wir erfolgreich waren. Wir haben in einem Pod erstellt und die Datei war sofort in einem anderen Pod vorhanden. 

$ kubectl exec webserver-5486dd9cf5-hfhnd -- ls /files
$ kubectl exec webserver-5486dd9cf5-nh9fl -- touch /files/nfs-is-rwx
$ kubectl exec webserver-5486dd9cf5-xl2lj -- ls /files
nfs-is-rwx

Zusammenfassung

Du hast nun einen NFS Server eingerichtet, welcher im Hintergrund ein CSI Cinder Blockstorage nutzt. Der NFS Server nutzt das Block Storage im Hintergrund um via NFS ein RWX PVC für Deine Pods bereitzustellen. Dadurch haben wir die technische Limitierung eines CSI Cinder Blockdevices umgangen und Du kannst Deinen NWS Managed Kubernetes Cluster fortan für mehr Anwendungsfälle nutzen.

Erhalte den nächsten Artikel

Mehr Artikel in Kubernetes | Tutorial
Ingress-NGINX mit Cert-Manager absichern

Ingress-NGINX mit Cert-Manager absichern

In einem der ersten Tutorials auf unserer Seite haben wir dir gezeigt, wie du Ingress-NGINX in deinem Cluster installieren und einrichten kannst. Heute gehen wir einen Schritt weiter und schauen uns an, wie du Ingress-NGINX und deine Services mit Hilfe von...

Migration von Servern auf VMware zu OpenStack

Migration von Servern auf VMware zu OpenStack

In diesem Tutorial befassen wir uns mit der Migration von Servern auf VMware zu OpenStack. Nach der kürzlichen Übernahme VMwares durch Broadcom haben in den vergangenen Wochen viele kleinere Cloud Service Provider (CSPs) Mitteilung zur Kündigung ihrer Mitgliedschaft...

Meistere Kubernetes mit Cilium: Traffic Filterung auf L7 Basis

Meistere Kubernetes mit Cilium: Traffic Filterung auf L7 Basis

Mit der neuen Version des Cilium CNI auf unserem Kubernetes-Service erhältst Du die Möglichkeit, den Datenverkehr anhand von L7-Eigenschaften zu filtern. Das ist normalerweise Service-Meshes vorbehalten und kann bei der Sicherheit deiner Dienste sehr hilfreich sein....

Terraform und OpenStack

Terraform und OpenStack

Viele von Euch sind vermutlich bereits mit der Verwendung von Terraform in Kombination mit Azure oder AWS vertraut. Und obwohl dies die am häufigsten verwendeten Plattformen sind, gibt es - oftmals im Bezug auf Datenschutz (DSGVO) - Unwägbarkeiten und somit weiterhin...

Dynamic Inventory – Eine Ansible und OpenStack Lovestory

Dynamic Inventory – Eine Ansible und OpenStack Lovestory

Für diejenigen unter euch, die mit Ansible möglicherweise nicht allzu vertraut sind: Es ist ein großartiges Tool, um in die Welt der Automatisierung einzusteigen und erleichtert euer Leben im Konfigurationsmanagement erheblich.   Die Kennenlernphase In diesem Tutorial...

Persistente Volumes in Kubernetes vergrößern

Persistente Volumes in Kubernetes vergrößern

Du willst ein PersistentVolume (PV) in Kubernetes vergrößern? In diesem Blogeintrag erfährst du wie das funktioniert. Was PVs sind und wie man diese anlegt wird im Tutorial Persistente Volumes in Kubernetes erstellen erklärt, auf welchem das vorliegende Tutorial...

Wie Du Deine NETWAYS Managed Database startest

Wie Du Deine NETWAYS Managed Database startest

Im ersten Tutorial hat Sebastian bereits erklärt, was es mit Vitess auf sich hat und welche Möglichkeiten es Dir beim Betrieb Deiner Anwendung, im Vergleich zu einer gewöhnlichen Datenbank, bietet. Im folgenden Text möchte ich nun darauf eingehen, wie Du Dir in...

Was ist Vitess?

Was ist Vitess?

Im Jahr 2010 wurde eine Lösung entwickelt, um die massiven Skalierbarkeitsprobleme von MySQL bei YouTube zu lösen - und somit war Vitess geboren. Später - im Jahr 2018 - wurde das Projekt Teil der Cloud Native Computing Foundation und ist seit 2019 als eines der...

S3-Object-Storage anlegen und nutzen

S3-Object-Storage anlegen und nutzen

In Zeiten der Hochverfügbarkeit und mehreren Webservern muss irgendwie die Grätsche zwischen der zentralen Datenhaltung, Datensicherheit und schnellen Zugriffszeiten geschafft werden. Genau dafür nutzen immer mehr Anwender nun Technologien, die mit Schlagwörtern wie...