Lab 13 – Taints, tolerations a affinity
Lab 13 – Taints, tolerations a affinity
Cíl: řídit, kam pody přistanou – a vidět rozdíl mezi povoleno a přitahováno. Kapitola: Plánování
Tainty odpuzují
# 1 – výchozí stav: 6 podů rozprostřených po třech workerech
kubectl create deploy filler --image nginx:1.27 --replicas 6
kubectl get pods -o wide | sort -k7
# 2 – otaintujte worker03 a sledujte, jak se mu nové pody vyhnou
kubectl taint node worker03 disk=ssd:NoSchedule
kubectl describe node worker03 | grep -i -A2 taint
kubectl scale deploy filler --replicas 12
kubectl get pods -o wide | grep -c worker03 # beze změny
Pody, které na worker03 už byly, tam pořád jsou. NoSchedule ovlivňuje jen
umístění; nic nevystěhuje.
# 3 – NoExecute vystěhuje
kubectl taint node worker03 disk=ssd:NoSchedule- # odeberte první
kubectl taint node worker03 maint=true:NoExecute
kubectl get pods -o wide | grep worker03 # během sekund prázdno
kubectl get events --sort-by=.lastTimestamp | tail -5
Přesně tohle dělá kubectl drain pod kapotou – jen zdvořile, pod po podu.
# 4 – ukliďte taint
kubectl taint node worker03 maint=true:NoExecute-
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
Tolerance povolují
# 5 – vyhraďte worker03 pro „databázovou“ zátěž
kubectl taint node worker03 workload=db:NoSchedule
cd ~
cat > tolerant.yaml <<'YAML'
apiVersion: v1
kind: Pod
metadata:
name: tolerant
spec:
tolerations:
- key: workload
operator: Equal
value: db
effect: NoSchedule
containers:
- name: box
image: busybox
command: ["sleep", "3600"]
YAML
kubectl apply -f tolerant.yaml
kubectl get pod tolerant -o wide
Podívejte se, který uzel si vybral. Nejspíš to není worker03. Tolerance řekla „ten taint mi nevadí“, ne „dej mě tam“ – scheduler si mohl vybrat kterýkoli uzel a ten prázdný nemusel být nejlepší volba.
Tohle je nejčastěji nepochopená věc kolem taintů. Odpuzování a přitahování jsou dvě samostatná rozhodnutí.
# 6 – teď ho ještě přitáhněte
kubectl label node worker03 workload=db
kubectl delete -f tolerant.yaml
cat > pinned.yaml <<'YAML'
apiVersion: v1
kind: Pod
metadata:
name: pinned
spec:
tolerations:
- key: workload
operator: Equal
value: db
effect: NoSchedule
nodeSelector:
workload: db
containers:
- name: box
image: busybox
command: ["sleep", "3600"]
YAML
kubectl apply -f pinned.yaml
kubectl get pod pinned -o wide # worker03, zaručeně
Taint + tolerance + selektor je kompletní recept na „vyhrazené uzly“: taint tam nikoho jiného nepustí, tolerance pustí tenhle pod, selektor ho tam pošle.
Node affinity
# 7 – označte dva uzly a vyžádejte si jeden z nich
kubectl label node worker01 disktype=ssd
kubectl label node worker02 disktype=hdd
kubectl get nodes -L disktype
cat > affinity.yaml <<'YAML'
apiVersion: v1
kind: Pod
metadata:
name: needs-ssd
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values: ["ssd"]
containers:
- name: box
image: busybox
command: ["sleep", "3600"]
YAML
kubectl apply -f affinity.yaml
kubectl get pod needs-ssd -o wide # worker01
# 8 – co když nic neodpovídá?
kubectl label node worker01 disktype=hdd --overwrite
kubectl delete pod needs-ssd
kubectl apply -f affinity.yaml
kubectl get pod needs-ssd # Pending
kubectl describe pod needs-ssd | tail -6
didn't match Pod's node affinity/selector. Required pravidlo, kterému nic
neodpovídá, znamená, že pod nikdy nepoběží – nemá záložní variantu.
# 9 – měkká varianta naplánuje vždy
kubectl delete pod needs-ssd
cat > prefer.yaml <<'YAML'
apiVersion: v1
kind: Pod
metadata:
name: prefers-ssd
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: disktype
operator: In
values: ["ssd"]
containers:
- name: box
image: busybox
command: ["sleep", "3600"]
YAML
kubectl apply -f prefer.yaml
kubectl get pod prefers-ssd -o wide # běží, i když žádný uzel ssd nemá
# 10 – IgnoredDuringExecution v praxi
kubectl label node worker02 disktype=ssd --overwrite
kubectl get pod prefers-ssd -o wide # NEpřesunul se
Affinity se vyhodnocuje jednou, při plánování. Pozdější změna labelů s běžícími pody nic neudělá.
Objevovací část
InfodiscoveryÚkol A. Zařiďte, aby Deployment filler rozprostřel repliky tak, že žádné
dva jeho pody nesedí na stejném uzlu, pokud to jde. Očekávaný výsledek: se třemi
replikami jeden pod na každý worker.
Úkol B. Najděte jedním příkazem všechny tainty v clusteru včetně těch, které si nastavil Kubernetes sám.
Úkol C. Bez použití kubectl drain zařiďte, aby worker02 odmítal nové pody
a ty stávající poslal jinam. Pak to vraťte.
Úkol D. Vysvětlete, proč kubectl cordon worker01 nepotřebuje taint, který
byste psali sami.
Úklid
kubectl delete pod pinned needs-ssd prefers-ssd --ignore-not-found
kubectl delete deploy filler
kubectl taint node worker03 workload=db:NoSchedule-
kubectl label node worker01 disktype- ; kubectl label node worker02 disktype-
kubectl label node worker03 workload-
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints