Zum Inhalt

Lab 02: Übung: Persistent Storage in AKS

Erzeuge dir für diese Übung einen Cluster wie in Aufgabe 1 und setze dir Umgebungsvariablen wie dort beschrieben.

Teil 1: Erkunden der vorhandenen StorageClasses

Liste alle verfügbaren StorageClasses in deinem AKS-Cluster auf:

kubectl get storageclasses

Untersuche die Details der Disk- und Files-StorageClasses:

kubectl describe storageclass managed-csi
kubectl describe storageclass azurefile-csi

Besonders relevant ist bei StorageClasses der VolumeBindingMode und die ReclaimPolicy. Ersteres bestimmt, ob für ein PersistentVolumeClaim ein PersistentVolume erzeugt wird, auch wenn niemand es verwendet. Letzteres kontrolliert, wann das PV wieder gelöscht wird.

Erstelle um dies zu verdeutlichen eine Datei pvc-disk.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-azure-disk
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: managed-csi
  resources:
    requests:
      storage: 5Gi

Wende das Manifest an und überprüfe den Status:

kubectl apply -f pvc-disk.yaml
kubectl get pvc pvc-azure-disk -w

Frage: Warum bleibt der PVC im Status "Pending"? (Tipp: VolumeBindingMode)


Teil 2: StatefulSet mit Azure Disk Volume

Wir werden in dieser Aufgabe ein StatefulSet erzeugen, welches einen NGINX via LoadBalancer erreichbar macht. Die Dateien des Webservers werden auf einer Azure Disk gespeichert.

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
  type: LoadBalancer
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: my-statefulset
spec:
  serviceName: my-service
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      securityContext:
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: my-container
          image: nginx:1.29.4
          ports:
            - containerPort: 80
          readinessProbe:
            tcpSocket:
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            tcpSocket:
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 20
          volumeMounts:
            - mountPath: "/usr/share/nginx/html"
              name: my-volume
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "200m"
              memory: "256Mi"
  volumeClaimTemplates:
    - metadata:
        name: my-volume
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 1Gi

index.html:

<!doctype html>
<html lang="de">
  <head>
    <meta charset="UTF-8" />
    <title>Meine persönliche Webseite</title>
  </head>
  <body>
    <h1>Hallo, das ist meine persönliche Webseite!</h1>
    <p>
      Willkommen auf meiner Webseite, die in einem Kubernetes-Pod mit einem
      Persistent Volume läuft.
    </p>
  </body>
</html>

Kopiere nun die index.html in diesem Verzeichnis in den Pod:

kubectl cp index.html my-statefulset-0:/usr/share/nginx/html/index.html -c my-container

Ermittle nun über kubectl die externe IP des LoadBalancers und rufe sie auf. Du solltest obige HTML-Seite sehen können.

Aber was passiert, wenn wir den Pod löschen?

kubectl delete pod my-statefulset-0

Für eine kurze Zeit wird unsere Anwendung nicht mehr erreichbar sein. Aber wie sieht es aus, wenn der Pod wieder erstellt wird? Ist die HTML-Seite die gleiche?

Spoiler: Sie ist nach wie vor die gleiche. Das liegt daran, dass das StatefulSet den Pod automatisch neu deployt und die Verbindung zum PersistentVolumeClaim erneut herstellt.`


Teil 3: PVC mit Azure Files (Shared Storage)

Erstelle eine Datei pvc-files.yaml mit ReadWriteMany als Access Mode:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-azure-files
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: azurefile-csi
  resources:
    requests:
      storage: 5Gi

Erstelle außerdem ein Deployment mit 3 Replicas, die alle dasselbe Volume nutzen (deploy-files.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: files-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: files-demo
  template:
    metadata:
      labels:
        app: files-demo
    spec:
      containers:
        - name: my-container
          image: nginx:1.29.4
          ports:
            - containerPort: 80
          readinessProbe:
            tcpSocket:
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            tcpSocket:
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 20
          volumeMounts:
            - mountPath: "/usr/share/nginx/html"
              name: my-volume
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "200m"
              memory: "256Mi"
      volumes:
        - name: my-volume
          persistentVolumeClaim:
            claimName: pvc-azure-files
---
apiVersion: v1
kind: Service
metadata:
  name: files-demo
  labels:
    app: files-demo
spec:
  type: LoadBalancer
  selector:
    app: files-demo
  ports:
    - name: http
      port: 80
      targetPort: 80

Wende die Manifeste an und ermittle einen beliebigen Pod-Namen des Deployment

kubectl apply -f pvc-files.yaml
kubectl apply -f deploy-files.yaml
kubectl get pods -l app=files-demo

Kopiere nun wieder die HTML-Datei in das Volume:

kubectl cp index.html PODNAME_BITTE_ERSETZEN:/usr/share/nginx/html/index.html -c my-container

Deploye und teste den gemeinsamen Zugriff. Egal, wie oft du Pods löschst und dadurch neu erstellen lässt: Der Zugriff auf das Azure Files-Volume sollte weiterhin funktionieren.

Bonus

Versuche, über das Azure Portal den erstellen File-Share zu finden und deine Datei im Portal anzeigen zu lassen. Wenn du sie gefunden hast, kannst du sie bearbeiten und live sehen, wie dein NGINX eine andere Antwort zurückgibt.