Kurs › Folge 21
Scheduling: nodeSelector, Taints, Affinity
Pods gezielt platzieren — und warum auf der Control Plane nichts landet.
Das Video zu dieser Folge ist noch nicht veröffentlicht. Die Notizen stehen trotzdem schon hier.
Was du danach kannst
- mit Labels und nodeSelector Pods gezielt verteilen
- Taints und Tolerations erklaeren, setzen und wieder entfernen
- Affinity und Anti-Affinity fuer Ausfallsicherheit nutzen
- erklaeren, warum dieselbe Mechanik auch bei einem Knotenausfall greift
Worum es geht
Der Scheduler sucht für jeden Pod einen Knoten aus. Meistens ist das genau richtig so — man muss ihm nicht hineinreden. Diese Folge handelt von den Fällen, in denen doch: wenn ein Dienst auf einen bestimmten Rechner gehört, wenn ein Knoten in Wartung geht, oder wenn zwei Repliken nicht auf derselben Maschine liegen dürfen.
Der Einstieg steht im eigenen Cluster: Auf der Control Plane läuft kein einziger Anwendungspod — und eingestellt hat das niemand.
nodeSelector — der einfachste Weg
Der Knoten bekommt ein Label, der Pod verlangt es:
kubectl label node w2-k8n platte=ssd
spec:
nodeSelector:
platte: ssd
Passt kein Knoten, bleibt der Pod auf Pending — und kubectl describe pod
sagt, warum. Das ist kein Fehler, sondern eine Auskunft.
Taint und Toleration
Ein Taint ist eine Markierung am Knoten: „Hier landet nur, wer das aushält." Die Toleration steht am Pod: „Ich halte das aus."
schlüssel=wert:wirkung
Auf jeder Control Plane steht standardmäßig:
node-role.kubernetes.io/control-plane:NoSchedule
Und deshalb laufen dort keine Anwendungspods. Cilium und kube-proxy laufen trotzdem — sie bringen die passende Toleration mit:
spec:
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
Die drei Wirkungen
| Wirkung | Bedeutung |
|---|---|
NoSchedule |
Keine neuen Pods hierher. Was läuft, bleibt. |
PreferNoSchedule |
Nur ein Wunsch — der Scheduler weicht aus, wenn er kann. |
NoExecute |
Keine neuen Pods und die vorhandenen werden vertrieben. |
Setzen und entfernen
kubectl taint nodes w2-k8n wartung=ja:NoSchedule # setzen
kubectl taint nodes w2-k8n wartung=ja:NoSchedule- # entfernen
Das Minus am Ende ist die ganze Syntax zum Entfernen. Und man vergisst es zuverlässig.
Der Unterschied, der oft verwechselt wird
Beide steuern die Platzierung, aber aus entgegengesetzten Richtungen:
- nodeSelector und Affinity ziehen an — der Pod sagt, wohin er will
- Taints stoßen ab — der Knoten sagt, wen er nicht will
Wer sicherstellen will, dass nur bestimmte Pods auf einem Knoten laufen und diese Pods nur dort, braucht beides zusammen. Genau so binden wir später Prometheus an die Control Plane.
Affinity und Anti-Affinity
nodeAffinity ist der große Bruder von nodeSelector: mehrere Bedingungen,
harte (required...) und weiche (preferred...).
Wichtiger im Alltag ist Pod-Anti-Affinity: „Verteile meine Repliken auf verschiedene Knoten." Ohne sie kann der Scheduler alle drei Repliken auf denselben Rechner legen — und beim Ausfall dieses Rechners ist der Dienst komplett weg, obwohl er dreifach lief.
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: web
topologyKey: kubernetes.io/hostname
IgnoredDuringExecution heißt: Die Regel gilt beim Platzieren, nicht
rückwirkend. Ein laufender Pod wird nicht verschoben, wenn sich die Lage
ändert.
Wo Kubernetes selbst Taints setzt
Und hier wird es interessant — das ist keine reine Handsteuerung:
kubectl drainvor einem Update setzt einen Taint und schiebt alles weg- bei knappem Speicher oder voller Platte setzt der Knoten
memory-pressurebzw.disk-pressure - fällt ein Knoten aus, setzt der Node-Controller
node.kubernetes.io/unreachable:NoExecute
Die Brücke zum Stromstecker
Genau der letzte Punkt ist die Mechanik hinter Folge 28:
- Ein Knoten meldet sich nicht mehr → nach etwa 40 Sekunden gilt er als
NotReady - Der Node-Controller setzt
unreachable:NoExecute - Jeder Pod bekommt automatisch eine Toleration für diesen Taint — mit
tolerationSeconds: 300 - Nach fünf Minuten ist die Geduld zu Ende, und die Pods werden auf anderen Knoten neu erstellt
Diese fünf Minuten sind kein Zufallswert und keine Trägheit. Sie sind eine Voreinstellung, die man sehen, verstehen und ändern kann.
Taints sind also nicht nur ein Platzierungswerkzeug, sondern die Mechanik, mit der Kubernetes auf Ausfälle reagiert. Wer sie verstanden hat, versteht die Umverteilung beim Stromausfall von selbst.
Zum Nachlesen
Eine geordnete Übersicht über die offizielle Dokumentation steht unter Nachlesen.
Befehle aus dieser Folge
kubectl describe node control-1 | grep -i -A2 taintkubectl label node w2-k8n platte=hddkubectl taint nodes w2-k8n wartung=ja:NoSchedulekubectl taint nodes w2-k8n wartung=ja:NoSchedule-kubectl get pods -o widekubectl drain w3-k8n --ignore-daemonsets
Begriffe
- Taint
- eine Markierung am Knoten — hier landet nur, wer das aushaelt
- Toleration
- die Erlaubnis am Pod, einen bestimmten Taint auszuhalten
- nodeSelector
- die einfachste Form der Zuweisung — Pod nennt ein Label, das der Knoten tragen muss
- Affinity
- dasselbe in flexibel, mit weichen und harten Bedingungen
- Anti-Affinity
- verteilt Repliken absichtlich auf verschiedene Knoten
- tolerationSeconds
- wie lange ein Pod einen NoExecute-Taint aushaelt, bevor er vertrieben wird
Übung — mach es selbst
Bau dir den Fall nach, der spaeter in echt kommt.
- Setze auf einen Worker einen Taint:
kubectl taint nodes w2-k8n wartung=ja:NoSchedule - Starte ein Deployment mit 4 Repliken. Wo landen sie? Warum nicht auf w2?
- Was passiert mit den Pods, die auf w2 schon liefen? (Nichts —
NoSchedulegilt nur fuer Neuzugaenge.) - Jetzt dasselbe mit
NoExecutestattNoSchedule. Beobachte mitkubectl get pods -o wide -w, was mit den vorhandenen Pods geschieht. - Taints wieder entfernen (Minus am Ende nicht vergessen).
Zusatz: Gib dem Deployment eine Anti-Affinity auf kubernetes.io/hostname
und setze die Repliken auf 3, obwohl du nur 2 Worker hast. Eine Replik
bleibt auf Pending — sieh dir mit kubectl describe pod an, wie der
Scheduler das begruendet. Diese Meldung zu lesen ist die eigentliche
Faehigkeit.