Kubernetes-Scheduling-Fehler erklärt: Lösungen und Best Practices
Meistern Sie das Kubernetes-Scheduling! Dieser Leitfaden entmystifiziert, warum Pods im Status 'Pending' stecken bleiben. Lernen Sie, Fehler mit `kubectl describe` zu diagnostizieren, Probleme mit unzureichender CPU/Auslastung zu beheben, Node-Affinity-Einschränkungen zu überwinden und Taints und Tolerations für eine robuste Workload-Platzierung korrekt zu nutzen.
Kubernetes-Scheduling-Fehler erklärt: Lösungen und Best Practices
Kubernetes-Scheduling-Fehler zeigen sich normalerweise als Pod, der im Status Pending steckt. Dieser Status kann vage wirken, hat aber eine spezifische Bedeutung: Kubernetes hat das Pod-Objekt akzeptiert, aber der Scheduler hat keinen Knoten gefunden, der die Anforderungen des Pods erfüllt. Der Container ist nicht abgestürzt. Die App wurde nicht gestartet. In vielen Fällen wurde das Image noch nicht einmal gezogen.
Der schnellste Weg, diese Probleme zu lösen, besteht darin, zu vergleichen, was der Pod anfordert, mit dem, was der Cluster bieten kann. CPU- und Speicheranfragen, Knotenlabels, Affinitätsregeln, Taints, Tolerations, persistente Volumes, Topologieverteilungsregeln und Namespace-Kontingente können die Platzierung blockieren. Der Scheduler ist streng, was erforderliche Einschränkungen betrifft. Wenn eine erforderliche Regel jeden Knoten ausschließt, wartet der Pod.
Diagnose von Pending-Pods: Der erste Schritt
Bevor Sie versuchen, Fehler zu beheben, müssen Sie genau diagnostizieren, warum der Scheduler fehlschlägt. Das primäre Werkzeug für diese Untersuchung ist kubectl describe pod.
Wenn ein Pod im Status Pending steckt, enthält der Abschnitt Events der Describe-Ausgabe kritische Informationen, die den Scheduling-Entscheidungsprozess und etwaige Ablehnungen detailliert beschreiben.
Verwenden von kubectl describe pod
Zielen Sie immer auf den problematischen Pod:
kubectl describe pod <pod-name> -n <namespace>
Untersuchen Sie die Ausgabe und achten Sie besonders auf den Abschnitt Events am Ende. Nachrichten hier geben in der Regel die Einschränkung an, die das Scheduling verhindert hat. Häufige Nachrichten beziehen sich auf Insufficient cpu, Insufficient memory, Node-Selector-Konflikte, nicht tolerierte Taints oder Volume-Bindung.
Häufige Scheduling-Fehlerkategorien und Lösungen
Scheduling-Fehler fallen im Allgemeinen in drei Hauptkategorien: Ressourcenbeschränkungen, Richtlinienbeschränkungen (Affinity/Anti-Affinity) und Knotenkonfiguration (Taints/Tolerations).
1. Ressourcenbeschränkungen (Unzureichende Ressourcen)
Dies ist die häufigste Ursache. Der Scheduler benötigt einen Knoten, der die in der Pod-Spezifikation definierten Anfragen erfüllen kann. Wenn kein Knoten über genügend zuweisbare CPU oder Arbeitsspeicher verfügt, bleibt der Pod im Status Pending.
Identifizieren des Problems
Der Abschnitt Events zeigt Nachrichten wie:
0/3 nodes are available: 3 Insufficient cpu.0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) didn't match node selector.
Diese Nachrichten können kombiniert werden. Bleiben Sie nicht beim ersten Satz stehen. Wenn drei Knoten aus drei verschiedenen Gründen fehlschlagen, kann die Behebung nur eines Grundes dazu führen, dass der Pod immer noch aussteht.
Lösungen für Ressourcenknappheit
- Pod-Anfragen reduzieren: Wenn die Pod-Anfragen übermäßig hoch sind, versuchen Sie, die CPU- oder Speicher-
requestsim Pod- oder Deployment-YAML zu senken. - Cluster-Kapazität erhöhen: Fügen Sie dem Kubernetes-Cluster weitere Knoten hinzu.
- Vorhandene Workloads bereinigen: Skalieren Sie nicht wesentliche Workloads herunter, entfernen Sie verlassene Jobs oder passen Sie überdimensionierte Anfragen in bestehenden Deployments an. Verwenden Sie
kubectl drainfür die Knotenwartung, nicht als beiläufigen Bereinigungsbefehl. - LimitRanges verwenden: Wenn Ihrem Namespace definierte Ressourcengrenzen fehlen, implementieren Sie
LimitRange-Objekte, um zu verhindern, dass einzelne Pods Ressourcen horten.
2. Node-Selectoren und Affinity-/Anti-Affinity-Regeln
Kubernetes ermöglicht eine feinkörnige Kontrolle darüber, wo Pods platziert werden können oder müssen, indem nodeSelector, nodeAffinity und podAffinity/podAntiAffinity verwendet werden.
Node-Selector-Konflikt
Wenn Sie einen nodeSelector definieren, der mit keinem Label übereinstimmt, das auf einem verfügbaren Knoten vorhanden ist, kann der Pod nicht eingeplant werden.
Beispiel-YAML-Ausschnitt (Fehlerursache):
spec:
nodeSelector:
disktype: ssd-fast
containers: [...] # Pod bleibt Pending, wenn kein Knoten disktype=ssd-fast hat
Lösung: Stellen Sie sicher, dass das in nodeSelector angegebene Label auf mindestens einem Knoten vorhanden ist (kubectl get nodes --show-labels) und dass die Groß-/Kleinschreibung genau übereinstimmt.
Verwenden Sie gezielte Label-Prüfungen, wenn der Cluster viele Labels hat:
kubectl get nodes -L disktype,topology.kubernetes.io/zone
kubectl describe node <node-name>
Ein häufiger Fehler ist die Verwendung eines Labels, das in einer vorherigen Knotengruppe existierte, aber nicht in der Ersatzknotengruppe. Nach einem Cluster-Upgrade oder einer Autoscaling-Gruppen-Migration können alte Platzierungsregeln stillschweigend unmöglich werden.
Node-Affinity-Einschränkungen
nodeAffinity bietet flexiblere Regeln (z. B. requiredDuringSchedulingIgnoredDuringExecution oder preferredDuringSchedulingIgnoredDuringExecution). Wenn eine required-Regel nicht erfüllt werden kann, bleibt der Pod im Status Pending.
Diagnosetipp: Bei Verwendung komplexer Affinitätsregeln gibt der Abschnitt Events oft an: node(s) didn't match node selector.
Pod-Affinity und Anti-Affinity
Diese Regeln steuern die Platzierung relativ zu anderen Pods. Wenn beispielsweise eine Anti-Affinity-Regel verlangt, dass ein Pod nicht auf einem Knoten ausgeführt wird, der einen bestimmten Dienst hostet, aber alle Knoten diesen Dienst bereits hosten, schlägt das Scheduling fehl.
Lösung: Überprüfen Sie sorgfältig den Topologieschlüssel und Selektor in Ihren Affinitätsregeln. Wenn eine Anti-Affinitätsregel zu restriktiv ist, lockern Sie die Anforderung oder verifizieren Sie, dass die von der Regel ausgewählten Ziel-Pods tatsächlich auf den Knoten ausgeführt werden, die Sie vermeiden möchten.
Bevorzugen Sie preferredDuringSchedulingIgnoredDuringExecution, wenn die Regel eine Präferenz und keine harte Anforderung ausdrückt. Erforderliche Anti-Affinität ist nützlich, um Replikate kritischer Dienste zu verteilen, kann aber Bereitstellungen in kleinen Clustern blockieren. Beispielsweise können drei Replikate mit strenger Anti-Affinität pro Zone in einem Cluster mit nur zwei nutzbaren Zonen nicht sauber eingeplant werden.
3. Taints und Tolerations
Taints werden direkt auf Knoten angewendet, um Pods abzuweisen, während Tolerations zu Pod-Spezifikationen hinzugefügt werden, um ihnen die Platzierung auf getainteten Knoten zu erlauben.
- Taint: Weist Pods ab, es sei denn, sie haben eine passende Tolerierung.
- Toleration: Erlaubt einem Pod, auf einem Knoten mit einem passenden Taint eingeplant zu werden.
Identifizieren der Taint-Ablehnung
Die Events geben explizit den Ablehnungsgrund an:
0/3 nodes are available: 2 node(s) had taint {dedicated: special-workload, effect: NoSchedule}, that the pod didn't tolerate.
Lösungen für Taints und Tolerations
Sie haben zwei primäre Wege:
Pod ändern (Empfohlen für Anwendungs-Pods): Fügen Sie die erforderlichen
tolerationszur Pod-Spezifikation hinzu, die dem Taint des Knotens entsprechen.Beispiel-Tolerierung:
spec: tolerations: - key: "dedicated" operator: "Equal" value: "special-workload" effect: "NoSchedule" containers: [...]Knoten ändern (Empfohlen für Cluster-Administratoren): Entfernen Sie den Taint vom Knoten, wenn die Einschränkung nicht mehr notwendig ist.
# Um einen Taint zu entfernen kubectl taint nodes <node-name> dedicated:special-workload:NoSchedule-
Best Practice Warnung: Vermeiden Sie es, den globalen
node-role.kubernetes.io/master:NoSchedule-Taint auf Anwendungs-Pods zu tolerieren, es sei denn, Sie planen absichtlich, kritische Steuerungsebenen-Komponenten auf den Master-Knoten zu planen.
In neueren Clustern verwenden Steuerungsebenen-Knoten üblicherweise den node-role.kubernetes.io/control-plane-Taint anstelle von oder neben der älteren Master-Terminologie. Überprüfen Sie die tatsächlichen Taints, bevor Sie eine Tolerierung aus einem alten Manifest kopieren:
kubectl describe node <node-name> | grep -i taints
Fortgeschrittene Scheduling-Einschränkungen
Weniger häufige, aber wichtige Einschränkungen können ebenfalls das Scheduling blockieren:
Speicher-Volume-Einschränkungen
Wenn ein Pod einen PersistentVolumeClaim (PVC) anfordert, der derzeit nicht an einen verfügbaren Knoten gebunden werden kann (z. B. aufgrund spezifischer Anforderungen des Speicher-Provisioners oder Nichtverfügbarkeit des Volumes), kann der Pod im Status Pending bleiben.
Diagnose: Überprüfen Sie zuerst den PVC-Status (kubectl describe pvc <pvc-name>). Wenn der PVC im Status Pending steckt, wird das Pod-Scheduling angehalten, bis das Volume verfügbar ist.
Speicher kann auch absichtlich durch volumeBindingMode: WaitForFirstConsumer auf der StorageClass verzögert werden. In diesem Modus wartet die Bindung, bis der Scheduler einen geeigneten Knoten auswählt, da das Volume möglicherweise in derselben Zone wie der Pod erstellt werden muss. Das ist normal, aber wenn kein Knoten die Pod- und Speicherbeschränkungen zusammen erfüllt, bleibt der Pod ausstehend.
DaemonSets und Topologieverteilungen
DaemonSets werden nur auf Knoten geplant, die ihren Auswahlkriterien entsprechen (falls vorhanden). Wenn ein Cluster partitioniert ist oder ein neuer Knoten nicht mit dem Selektor des DaemonSets übereinstimmt, wird er nicht ausgeführt.
Topologieverteilungsbeschränkungen (falls definiert) gewährleisten eine gleichmäßige Verteilung. Wenn die aktuelle Verteilung die Platzierung auf keinem Knoten unter Berücksichtigung der Verteilungsbeschränkungen zulässt, schlägt das Scheduling fehl.
Topologieverteilungsfehler treten oft nach einem teilweisen Ausfall auf. Angenommen, eine Zone ist nicht verfügbar und ein Deployment hat strenge Verteilungsbeschränkungen über Zonen hinweg. Kubernetes weigert sich möglicherweise, neue Replikate in den verbleibenden Zonen zu platzieren, da dies die Schiefenregel verletzen würde. Dieses Verhalten schützt die Verteilungsziele, aber während eines Ausfalls müssen Sie die Einschränkung möglicherweise vorübergehend lockern, um die Kapazität wiederherzustellen.
Namespace-Kontingente und LimitRanges
Ein Pod kann auch durch die Namespace-Richtlinie blockiert werden. ResourceQuota steuert die aggregierte Nutzung in einem Namespace. LimitRange kann Standardwerte oder minimale und maximale Ressourcenwerte festlegen.
Überprüfen Sie diese, wenn eine Pod-Spezifikation vernünftig aussieht, aber die Erstellung oder das Scheduling dennoch fehlschlägt:
kubectl get resourcequota -n <namespace>
kubectl describe resourcequota -n <namespace>
kubectl get limitrange -n <namespace>
kubectl describe limitrange -n <namespace>
Kontingentprobleme sind in gemeinsam genutzten Entwicklungsclustern häufig. Ein Team hat möglicherweise genügend physische Clusterkapazität, aber sein Namespace-Kontingent ist durch alte Vorschau-Umgebungen oder abgeschlossene Jobs, die nie bereinigt wurden, erschöpft.
Eine realistische Debugging-Sequenz
Wenn ein Pod aussteht, verwenden Sie diese Reihenfolge:
- Führen Sie
kubectl describe podaus und kopieren Sie das neueste Scheduling-Ereignis. - Überprüfen Sie die angeforderte CPU und den Arbeitsspeicher gegen die zuweisbare Knotenkapazität mit
kubectl describe node. - Überprüfen Sie die Knotenlabels, wenn der Pod
nodeSelector, Node-Affinität oder Topologieschlüssel verwendet. - Überprüfen Sie Taints auf Kandidatenknoten und Tolerierungen auf dem Pod.
- Überprüfen Sie PVCs und StorageClasses, wenn der Pod persistenten Speicher bereitstellt.
- Überprüfen Sie Namespace-Kontingente und LimitRanges.
- Wenn der Cluster Autoscaler helfen soll, überprüfen Sie seine Logs oder Ereignisse.
Diese Reihenfolge ist wichtig, da ein ausstehender Pod kein Anwendungslaufzeitproblem ist. Ein Neustart des Deployments hilft selten, es sei denn, die zugrunde liegende Einschränkung hat sich geändert.
Best Practices für erfolgreiches Scheduling
Um Scheduling-Probleme zu minimieren, übernehmen Sie diese operativen Best Practices:
- Ressourcenanfragen explizit definieren: Setzen Sie immer angemessene
requests(und optionalelimits) für CPU und Arbeitsspeicher. Dies ermöglicht dem Scheduler, die Knotenkapazität genau zu bewerten. - Knotenlabels für Zonierung verwenden: Implementieren Sie konsistente Knotenbeschriftungen (z. B.
hardware=gpu,zone=us-east-1a) und verwenden SienodeSelectorodernodeAffinity, um Workloads auf geeignete Hardware zu lenken. - Taints und Tolerations dokumentieren: Wenn Knoten für Wartungs- oder Hardwaretrennung getaintet sind, dokumentieren Sie diese Taints zentral. Stellen Sie sicher, dass Anwendungsmanifeste, die Zugriff auf getaintete Ressourcen benötigen, die entsprechenden Tolerierungen enthalten.
- Cluster Autoscaler überwachen (falls verwendet): Wenn Sie sich auf Skalierungslösungen verlassen, stellen Sie sicher, dass diese funktionsfähig sind. Ein Mangel an Kapazität, der eigentlich eine Skalierung auslösen sollte, könnte stillschweigend fehlschlagen und Pods im Status Pending belassen.
- Scheduler-Logs überprüfen (Fortgeschritten): Für tiefgehende Diagnosen überprüfen Sie die Logs der
kube-scheduler-Komponente selbst. In verwalteten Clustern kann der Zugriff je nach Anbieter variieren. Beginnen Sie daher mit Pod-Ereignissen und anbieterspezifischem Logging der Steuerungsebene.
Beheben Sie die Einschränkung, nicht das Symptom
Die richtige Lösung hängt davon ab, ob die Einschränkung versehentlich oder beabsichtigt ist. Wenn der Pod 8 CPUs anfordert, weil jemand ein Produktionsmanifest in einen winzigen Staging-Cluster kopiert hat, reduzieren Sie die Anfrage für diese Umgebung. Wenn der Pod eine GPU benötigt und kein GPU-Knoten existiert, hilft das Hinzufügen einer Tolerierung nicht; der Cluster benötigt die richtige Hardware. Wenn ein Taint Datenbankknoten vor allgemeinen Workloads schützt, entfernen Sie den Taint nicht nur, um einen nicht verwandten Pod zu planen.
Machen Sie für Produktionsänderungen den Grund in Git sichtbar. Knotenlabels, Taints, Affinitätsregeln und Ressourcenanfragen sind Platzierungsverträge. Zukünftige Betreiber müssen wissen, ob eine Regel aus Leistungs-, Compliance-, Hardwarezugriffs-, Kostenkontroll- oder einfach historischen Zufallsgründen existiert.
Beispiele für irreführende Schnellkorrekturen
Mehrere gängige Korrekturen lassen den sofortigen Pending-Status verschwinden, während sie später ein schlimmeres Problem verursachen.
Das Senken von CPU-Anfragen kann helfen, wenn die ursprüngliche Anfrage überhöht war, aber es ist kein kostenloses Kapazitätswerkzeug. Wenn die Anwendung diese CPU während des Spitzenverkehrs wirklich benötigt, kann der Pod geplant werden und dann unter Last schlecht abschneiden. Überprüfen Sie die Nutzungshistorie und Latenz, bevor Sie Anfragen aggressiv kürzen.
Das Hinzufügen einer breiten Tolerierung kann einen Pod planen, aber er könnte auf Knoten landen, die für einen anderen Zweck reserviert sind. Eine Tolerierung besagt "dieser Pod ist hier erlaubt." Sie besagt nicht "dieser Pod sollte hier bevorzugt werden." Wenn Sie sowohl Erlaubnis als auch Absicht benötigen, kombinieren Sie Tolerierungen mit Node-Affinität oder Node-Selectoren.
Das Entfernen einer Anti-Affinitätsregel kann Replikate schnell wiederherstellen, aber es könnte jedes Replikat auf einen Knoten oder eine Zone setzen. Das ist manchmal während eines Ausfalls akzeptabel, sollte aber eine bewusste vorübergehende Änderung sein, keine stillschweigende permanente Abweichung.
Die Erweiterung des Clusters ist oft die richtige Antwort, aber nur, nachdem Sie wissen, dass der ausstehende Pod die neuen Knoten nutzen kann. Wenn der Pod ein Label benötigt, das die autoskalierte Knotengruppe nicht haben wird, erhalten Sie durch das Hinzufügen von Knoten nur mehr ungeeignete Knoten.
Abschließende Überprüfung
Ein ausstehender Pod ist ein gescheiterter Verhandlungsprozess zwischen dem Pod und dem Cluster. Der Pod fragt nach Ressourcen, Labels, Speicher, Topologie und Erlaubnis, auf bestimmten Knoten zu landen. Der Cluster antwortet mit Kapazität, Taints, Labels, Kontingenten und verfügbaren Volumes. kubectl describe pod zeigt, wo diese Verhandlung gescheitert ist. Sobald Sie das Ereignis sorgfältig gelesen haben, werden die meisten Korrekturen einfach: Ändern Sie die Anforderungen des Pods, ändern Sie die verfügbare Kapazität des Clusters oder korrigieren Sie die Richtlinie, die nicht mehr der Realität entspricht.