Kubernetes Kubernetes

Persistenter Speicher: Volumes, PersistentVolumes und Claims

Halte Daten über Pod-Neustarts hinweg am Leben mit PVCs und verstehe, wie StorageClasses die Teile verbinden.

14 min Fortgeschritten

Das Dateisystem eines Containers hält nur so lange wie der Container. Wird ein Pod ersetzt, ist alles, was er geschrieben hat, weg. Für zustandslose Webserver ist das in Ordnung, für Datenbanken, Uploads und alles andere, was überleben muss, ein Problem. Diese Anleitung zeigt, wie Kubernetes dauerhaften Speicher an Pods anbindet.

Warum Container-Speicher nicht ausreicht

Container sollen klein und wegwerfbar sein, Daten in ihnen abzulegen untergräbt also das Modell. Daten müssen außerhalb des Containers und außerhalb des Pods liegen, auf Speicher, den Kubernetes beim Start eines Pods anbindet. Kubernetes ist agnostisch darüber, was dieser Speicher ist: eine Cloud-Disk, eine Netzwerkfreigabe oder ein lokales Laufwerk. Es sichert die Daten auch nicht für dich. Das bleibt deine Aufgabe.

Die Speicherkette

Vier Objekte arbeiten zusammen:

  • Eine StorageClass beschreibt eine Art von Speicher und wie man ihn bei Bedarf erstellt (zum Beispiel „schnelle SSD-Volumes vom Cloud-Anbieter“).
  • Ein PersistentVolume (PV) ist ein tatsächliches Stück Speicher im Cluster.
  • Ein PersistentVolumeClaim (PVC) ist eine Anforderung von Speicher durch einen Benutzer oder eine Anwendung: „Ich brauche 1 GiB, das ein Knoten lesen und beschreiben kann.“
  • Der Pod referenziert den Claim als Volume und mountet ihn in einen Container.
Container ─ mountPath ─▶ Pod-Volume ─▶ PVC ─ bindet an ─▶ PV ─▶ echter Speicher
                                                          ▲
                                        StorageClass erstellt PVs bei Bedarf

Ein PVC bindet an genau ein PV. Der Pod verweist nie auf das PV, nur auf den Claim, was Anwendungen von den Speicherdetails unabhängig hält.

Speicher mit einem PVC anfordern

Die meisten Cluster haben eine Standard-StorageClass, die Volumes bei Bedarf erstellt (dynamische Bereitstellung genannt), und minikube bringt eine mit. Prüfe deine:

kubectl get storageclass

Fordere dann Speicher an:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
kubectl apply -f pvc.yaml
kubectl get pvc,pv

Der Claim sollte Bound werden, und ein passendes PV erscheint. Manche Storage-Klassen warten, bis ein Pod den Claim tatsächlich nutzt, bevor sie das Volume erstellen, Pending ist an dieser Stelle also nicht zwingend ein Fehler.

In einem Pod mounten und die Persistenz beweisen

apiVersion: v1
kind: Pod
metadata:
  name: storage-demo
spec:
  containers:
    - name: app
      image: busybox:1.36
      command: ["sh", "-c", "sleep 3600"]
      volumeMounts:
        - name: data
          mountPath: /data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data

Schreibe eine Datei, zerstöre den Pod, erstelle ihn neu und prüfe, ob die Datei überlebt hat:

kubectl apply -f pod.yaml
kubectl exec storage-demo -- sh -c 'echo persisted > /data/proof.txt'
kubectl delete pod storage-demo
kubectl apply -f pod.yaml
kubectl exec storage-demo -- cat /data/proof.txt

Der neue Pod ist ein völlig anderer Container, aber der Claim und die Daten dahinter wurden wieder angebunden.

Zugriffsmodi, Reclaim-Policy und statische Volumes

  • Zugriffsmodi sagen, wie ein Volume gemountet werden kann. ReadWriteOnce bedeutet Lesen und Schreiben durch einen einzelnen Knoten, sodass mehrere Pods auf diesem Knoten es trotzdem teilen können. ReadOnlyMany und ReadWriteMany erlauben viele Knoten, wenn der Speicher das unterstützt. ReadWriteOncePod beschränkt es auf einen einzelnen Pod.
  • Reclaim-Policy entscheidet, was mit dem Volume passiert, wenn der Claim gelöscht wird. Dynamisch bereitgestellte Volumes haben meist standardmäßig Delete, was den zugrunde liegenden Speicher und seine Daten entfernt. Nutze Retain, wenn du die Daten behalten willst.
  • Statische Bereitstellung bedeutet, dass ein Administrator PVs von Hand erstellt und Claims an das jeweils passende binden. Ein hostPath-PV, das ein Verzeichnis auf einem Knoten nutzt, ist eine gängige Demo, bindet Daten aber an eine Maschine und eignet sich nur für Einzelknoten-Entwicklung.

Datenbanken und StatefulSets

Du kannst einen Claim in die Pods eines Deployments mounten, aber Replikas eines Deployments sind austauschbar und identisch, und die meisten Datenbanken funktionieren so nicht. Ein StatefulSet ist für zustandsbehaftete Workloads gebaut. Es gibt jedem Pod eine stabile Identität (db-0, db-1), startet und aktualisiert sie in Reihenfolge und kann für jedes Replikat einen eigenen PVC erstellen:

spec:
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 5Gi

Ein StatefulSet behandelt Identität und Speicher, nicht Datenreplikation. Replikas untereinander konsistent zu halten, ist Aufgabe der Datenbank, weshalb der Betrieb von Datenbanken auf Kubernetes schwieriger ist als der von zustandslosen Services. Viele Teams nutzen eine verwaltete Datenbank oder einen Datenbank-Operator und halten die zustandslosen Anwendungen im Cluster.

Beliebte Anleitungen