- Authors

- Name
- Phillip Pham
- @ddppham
PVC Pending: StorageClass, Provisioner, Zone
TL;DR
Ein PVC auf Pending hat noch kein Volume. Der Pod, der es mountet, bleibt oft ebenfalls Pending, mit dem Event unbound PersistentVolumeClaims. Zuerst die Klasse und der Modus:
kubectl get pvc PVC -o wide
kubectl describe pvc PVC
kubectl get storageclass
Keine StorageClass und kein Default: der Claim weiß nicht, wer das Volume anlegen soll. WaitForFirstConsumer: Pending ohne Pod ist normal. Provisioner-Pod fehlt oder eine Zone passt nicht: der Claim bleibt Pending, auch mit Pod.
Pending, das kein Fehler ist
volumeBindingMode: WaitForFirstConsumer bindet erst, wenn ein Pod den Claim benutzt und der Scheduler den Node kennt. Vorher bleibt der PVC auf Pending, Events melden sinngemäß, dass auf den ersten Consumer gewartet wird. Wer den PVC allein anlegt und sofort Bound erwartet, debuggt einen korrekten Zustand.
Erst wenn ein Pod den Claim referenziert und trotzdem nichts bindet, lohnt die weitere Suche. Der Pod zeigt dann Pod Pending mit einem Volume-Grund, oder er ist geschedult und hängt in ContainerCreating an FailedMount.
Keine Klasse, kein Default
kubectl get storageclass
kubectl get pvc PVC -o jsonpath='{.spec.storageClassName}{"\n"}'
(default) steht an genau einer Klasse. Fehlt sie, und der PVC nennt keine storageClassName, bleibt er Pending. Auf einem frischen Cluster oder nach dem Löschen des Default-Add-ons ist das der häufigste Fall.
Fix: im PVC die Klasse setzen, die es wirklich gibt, oder eine Klasse als Default markieren.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: daten
spec:
accessModes:
- ReadWriteOnce
storageClassName: managed-premium
resources:
requests:
storage: 20Gi
Ein leerer String storageClassName: "" schaltet dynamische Provisionierung aus. Der Claim wartet dann auf ein passendes, von Hand angelegtes PV. Gibt es keines, bleibt er Pending. Das ist Absicht, kein Bug der Klasse.
Provisioner läuft nicht
Die Klasse nennt einen provisioner, zum Beispiel disk.csi.azure.com, ebs.csi.aws.com oder pd.csi.storage.gke.io. Das dazugehörige Controller-Deployment muss laufen.
kubectl get pods -A | grep -i csi
kubectl describe pvc PVC
describe sagt waiting for a volume to be created und danach einen Provisioner-Fehler: Quota in der Cloud, unbekannte SKU, keine Berechtigung der Node- oder Controller-Identität. Das ist kein Kubernetes-Quota aus dem Namespace, sondern das Kontingent beim Cloud-Anbieter. kubectl describe quota bleibt dann grün.
failed to provision volume mit zone oder topology heißt: der Pod sitzt in einer Zone, in der die Klasse kein Volume anlegen darf, oder das bestehende Volume liegt in einer anderen Zone als der Node. ReadWriteOnce bindet an eine Zone. Ein Pod mit festem nodeSelector auf Zone A und ein Volume in Zone B mountet nie. Entweder die Affinity an die Volume-Zone anpassen oder die Klasse neu provisionieren lassen, nachdem der Pod in der richtigen Zone geplant wird. Dafür ist WaitForFirstConsumer da.
Access Mode und Größe
ReadWriteMany auf einer Klasse, die nur ReadWriteOnce kann, wird nicht gebunden. Die Klasse sagt nicht immer laut nein. Im describe des PVC steht, dass kein PV die Modes erfüllt. Dieselbe Falle bei einer Größe, die über dem erlaubten Maximum der Klasse liegt.
Ein Resize auf einem bestehenden Claim ist ein anderes Thema: die Klasse braucht allowVolumeExpansion: true, und der Pod muss das Dateisystem oft neu einhängen. Ein Pending beim ersten Anlegen hat mit Expansion nichts zu tun.
Backup hängt am selben Claim
Wer den Cluster sichert, sichert das Volume, nicht den Pending-Claim. Ein Claim, der nie Bound war, hat keine Daten. Ein Claim, der Bound ist und dessen Pod in Terminating festhängt, blockiert oft den nächsten Mount desselben Volumes. Erst den Pod lösen, dann den Restore prüfen. Der Ablauf für Datenbanken im Cluster steht im Backup-Artikel.
Quellen
📖 Verwandte Artikel
Weitere interessante Beiträge zu ähnlichen Themen
kubectl connection refused 6443 beheben
kubectl connection refused auf Port 6443: der API-Server antwortet nicht. kubeconfig, Kontext, Firewall, API-Prozess. Der Pod-Status kommt erst danach.
Error from server Forbidden: RBAC-Recht
kubectl Forbidden: Error from server (Forbidden) nennt User, Verb und Ressource. kubectl auth can-i zeigt das Recht, bevor jemand cluster-admin vergibt.
ContainerCreating hängt: Volume, Sandbox, CNI
ContainerCreating hängt: der Pod hat einen Node, der Container startet nicht. FailedMount, Pod-Sandbox und CNI stehen in den Events, nicht in den Logs.
CreateContainerConfigError: Secret und ConfigMap
CreateContainerConfigError: fehlendes Secret, falscher Key oder Namespace. Der Container startet nicht, logs --previous bleibt leer. Das Event nennt das Objekt.
Kubernetes DNS fehlgeschlagen: CoreDNS, ndots
Kubernetes DNS fehlgeschlagen: CoreDNS-Pods, das Service-ClusterIP und ndots:5. Wann ein Name im Cluster auflöst und wann die NetworkPolicy UDP 53 schluckt.
Exit Code 1: die erste Zeile im Previous-Log
Exit Code 1 auf Kubernetes: die Anwendung beendet sich selbst. kubectl logs --previous zeigt die Zeile. Speicher, Image-Pull und SIGKILL sind andere Codes.
Exit Code 143: SIGTERM und Graceful Shutdown
Exit Code 143 ist SIGTERM: 128 plus 15. Beim Rollout ist das normal. Im Loop fehlt ein Handler oder die Grace-Period ist kürzer als der Stopp der Anwendung.
Ingress ohne Address: Controller und Class
Ingress ohne Address: kein Controller, falsche IngressClass oder der LoadBalancer dahinter bleibt Pending. ADDRESS leer ist der Controller, nicht das Backend.