Kubernetes – ujarzmianie POD-ów
W tym artykule odpowiemy na pytania, w jaki sposób kontrolować to, gdzie zostaną uruchomione POD-y oraz jak działa kube-scheduler? Omówimy także szereg narzędzi służących do ustalania powiązań POD-ów z NODE-ami: labels (etykiety), nodeSelector, affinity oraz oznaczanie „skażonych” (tainted) NODE-ów.
W tym artykule odpowiemy na pytania, w jaki sposób kontrolować to, gdzie zostaną uruchomione POD-y oraz jak działa kube-scheduler. Omówimy także szereg narzędzi służących do ustalania powiązań POD-ów z NODE-ami: labels (etykiety), nodeSelector, affinity oraz oznaczanie „skażonych” (tainted) NODE-ów.
Poniższe przykłady zostały przeprowadzone na laboratorium Kubernetes złożonym z dwóch NODE-ów. Dlatego też zalecamy dostęp do takiego laboratorium. Proces tworzenia takiego klastra testowego opisaliśmy w artykule Połączenie dwóch maszyn EuroLinux 8 w klaster Kubernetes.
kubectl get nodes
NAME STATUS ROLES AGE VERSION
euro1 Ready control-plane 35d v1.24.0
euro2 Ready <none> 35d v1.24.0
Kubernetes scheduler
Scheduling to proces, który zarządza uruchamianiem POD-ów na odpowiednio dopasowanych NODE-ach tak, aby proces kubelet
mógł je obsłużyć.
Proces schedulera można przedstawić w następujących krokach:
1. Oczekiwanie na pojawienie się nowego POD-a, który nie ma przypisanego NODE-a.
2. Znalezienie najlepszego NODE-a dla każdego wykrytego POD-a.
3. Poinformowanie API o wyborze.
kube-scheduler
kube-scheduler
to domyślny scheduler Kubernetes, który działa jako część control-plane. Jest zaprojektowany tak, by umożliwiać użycie innych elementów (scheduling components) napisanych samodzielnie lub przez strony trzecie.
Wybór najlepszego NODE-a dla nowego POD-a wymaga odpowiedniego filtrowania dostępnych NODE-ów. Te NODE-y, które spełniają wymagania schedulingu, nazywa się feasible nodes (NODE-y wykonywalne). Gdy żaden z NODE-ów nie jest odpowiedni, POD pozostaje „nieuruchomiony” (unscheduled) do czasu, gdy scheduler nie znajdzie dla niego odpowiedniego miejsca (NODE). Po wybraniu NODE-ów wykonywalnych, scheduler wykonuje zestaw funkcji punktujących wybrane NODE-y. Następnie, wybiera NODE z najwyższym wynikiem. Ostatnim krokiem jest poinformowanie API serwera o danym wyborze w procesie binding (wiązania).
Przypisanie POD-ów do NODE-ów
Kubernetes umożliwia przypisywanie POD-ów do zdefiniowanych klas NODE-ów. Wszystkie zalecane metody wykorzystują selekcję etykiet (label selector). Najczęściej przypisywanie nie jest konieczne, ponieważ scheduler automatycznie bardzo dobrze przypisuje POD-y do NODE-ów dysponujących odpowiednimi zasobami. Z drugiej strony, łatwo można sobie wyobrazić przypadek, w którym definiowanie dodatkowej klasy NODE-ów może być użyteczne. Przykładowo, gdy potrzebny jest dostęp do „szybkiej” pamięci ssd lub chcemy, by NODE-y należały do jednej „szybkiej” sieci LAN.
NODE labels (etykiety)
Jak wiele innych obiektów Kubernetes, NODE-y posiadają etykiety (labels). Można je przypisywać ręcznie. Ponadto, Kubernetes wprowadza standardowy zbiór etykiet dla wszystkich NODE-ów w klastrze. Warto je poznać na potrzeby troubleshootingu. Jednak nie będziemy tego rozwijać w tym artykule.
Dodawanie etykiet umożliwia uruchamianie POD-ów na wybranej grupie NODE-ów. Ta metoda jest często wykorzystywana do zapewnienia działania aplikacji na specjalnie odizolowanych NODE-ach, spełniających szczególne wymagania bezpieczeństwa. W tym przypadku zalecane jest, by wybrać taki klucz etykiety, którego kubelet
nie może zmodyfikować. Uniemożliwi to zmianę etykiety po uzyskaniu dostępu do pojedynczego worker NODE-a. Takimi etykietami można zarządzić jedynie przez master NODE. Można to zrobić w następujących krokach:
- upewniamy się, że używamy Node authorizera oraz że włączona jest wtyczka rozszerzenia
NodeRestriction
:
kubectl -n kube-system describe po kube-apiserver-euro1|grep NodeRestriction
--enable-admission-plugins=NodeRestriction
- dodajemy etykietę z prefiksem
node-restriction.kubernetes.io/
do wybranych NODE-ów:
kubectl label nodes euro2 restriction.kubernetes.io/supersecure=true
- używamy tych etykiet w polu
nodeSelector
:
cat << EOF | tee deployment-supersecure.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-supersecure
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
nodeSelector:
restriction.kubernetes.io/supersecure: "true"
EOF
Uruchomienie deploymentu:
kubectl apply -f deployment-supersecure.yaml
deployment.apps/deployment-supersecure created
Weryfikacja dystrybucji POD-ów:
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deployment-supersecure-5d4ccb7468-gf54d 1/1 Running 0 20s 10.33.0.20 euro1 <none> <none>
deployment-supersecure-5d4ccb7468-vlncv 1/1 Running 0 20s 10.33.0.18 euro1 <none> <none>
deployment-supersecure-5d4ccb7468-znpfw 1/1 Running 0 20s 10.33.0.19 euro1 <none> <none>
Usunięcie przykładowego deploymentu:
kubectl delete deployments.apps deployment-supersecure
deployment.apps "deployment-supersecure" deleted
nodeSelector
Pole nodeSelector
można dodać do specyfikacji POD-a. Zawiera ono listę etykiet, które musi posiadać NODE, na którym Kubernetes scheduler może uruchomić POD. NODE musi zawierać wszystkie wybrane etykiety.
Przykład:
Nadanie NODE-om euro1 i euro2 etykiety a=a:
kubectl label nodes euro1 euro2 a=a
node/euro1 labeled
node/euro2 labeled
Nadanie NODE-owi euro2 etykiety b=b:
kubectl label nodes euro2 b=b
node/euro2 labeled
Przerobienie poprzedniego przykładowego deploymentu tak, by wymagał etykiet a=a
i b=b
:
cat << EOF | tee deployment-ab.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-ab
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
nodeSelector:
a: "a"
b: "b"
EOF
Uruchomienie deploymentu:
kubectl apply -f deployment-ab.yaml
deployment.apps/deployment-ab created
Weryfikacja dystrybucji POD-ów:
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deployment-ab-74d6cc75b9-74qsq 1/1 Running 0 8s 10.33.2.19 euro2 <none> <none>
deployment-ab-74d6cc75b9-bflh9 1/1 Running 0 8s 10.33.2.18 euro2 <none> <none>
deployment-ab-74d6cc75b9-gvt7l 1/1 Running 0 8s 10.33.2.20 euro2 <none> <none>
Usunięcie starego deploymentu:
kubectl delete deployment deployment-ab
deployment.apps "deployment-ab" deleted
Affinity / anti-affinity
nodeSelector
jest uproszczoną metodą przypisywania POD-ów do NODE-ów. Pole affinity
(powiązanie) i anti-affinity
znacznie rozszerza możliwości pozwiązywania POD-ów z NODE-ami, a także POD-ów z POD-ami.
nodeAffinity
nodeAffinity
(powiązanie NODE-ów) działa podobnie do nodeSelector
. Wyróżnia się dwa rodzaje nodeAffinity
:
requiredDuringSchedulingIgnoreDuringExecution
– Kubernetes scheduler może uruchomić POD-a tylko wtedy, gdy reguła jest spełniona. Reguła może być określona w bardziej złożony sposób, w porównaniu znodeSelectorem
, gdzie jedyną opcją jest dopasowanie wszystkich etykietpreferredDuringSchedulingIgnoredDuringExecution
– Kubernetes spróbuje wybrać NODE-a spełniającego regułę. Jednak jest to tylko preferencja z przypisaną wagą.
IgnoredDuringExecution
należy rozumieć, jako – jeśli NODE zmieni etykietę podczas pracy (DuringExecution), nie zakłóci to pracy tego POD-a.
Przykład konfiguracji POD-a powiązanego z NODE-em o etykiecie a=a
i preferencją wobec NODE-ów o etykietach b=b
(waga minimalna równa 1) i node-role.kubernetes.io/control-plane=
(waga maksymalna równa 100):
cat <<EOF | tee node-affinity-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: node-affinity-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: a
operator: In
values:
- a
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: b
operator: In
values:
- b
- weight: 100
preference:
matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: Exists
containers:
- image: nginx
name: node-affinity
EOF
Uruchomienie POD-a:
kubectl apply -f node-affinity-pod.yaml
Wynik komendy kubectl get pods -o wide
powinien wyglądać następująco:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
node-affinity-pod 1/1 Running 0 19s 10.33.0.23 euro1 <none> <none>
POD można usunąć komendą:
kubectl delete pod node-affinity-pod
W kolejnych przykładach skonfigurujemy deployment oparty na analogicznych POD-ach.
Konfiguracja deploymentu złożonego z 4 POD-ów analogicznych do POD-a z powyższego przykładu:
cat << EOF | tee node-affinity-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-affinity-deployment
labels:
app: nginx
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: a
operator: In
values:
- a
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: b
operator: In
values:
- b
- weight: 100
preference:
matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: Exists
containers:
- name: node-affinity-deployment
image: nginx
EOF
Uruchomienie deploymentu:
kubectl apply -f node-affinity-deployment.yaml
Sprawdzenie dystrybucji POD-ów między NODE-ami:
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
node-affinity-deployment-bbc88d9-25qr2 1/1 Running 1 (2m2s ago) 14m 10.33.0.30 euro1 <none> <none>
node-affinity-deployment-bbc88d9-947x5 1/1 Running 1 (2m2s ago) 14m 10.33.0.28 euro1 <none> <none>
node-affinity-deployment-bbc88d9-pg4zz 1/1 Running 1 (2m2s ago) 14m 10.33.0.33 euro1 <none> <none>
node-affinity-deployment-bbc88d9-s9vsf 1/1 Running 1 (2m2s ago) 14m 10.33.0.32 euro1 <none> <none>
Wszystkie POD-y zostały uruchomione na control-plane NODE ze względu na wyższą wagę preferencji tego NODE-a.
W kolejnym przykładzie ustawimy dwie równe wagi preferencji.
cat << EOF | tee node-affinity-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-affinity-deployment
labels:
app: nginx
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: a
operator: In
values:
- a
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: b
operator: In
values:
- b
- weight: 1
preference:
matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: Exists
containers:
- name: node-affinity-deployment
image: nginx
EOF
Wdrożenie zmian w konfiguracji:
kubectl apply -f node-affinity-deployment.yaml
Weryfikacja dystrybucji POD-ów:
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
node-affinity-deployment-dc8df7bbf-nlkcz 1/1 Running 0 72s 10.33.2.24 euro2 <none> <none>
node-affinity-deployment-dc8df7bbf-nq88k 1/1 Running 0 72s 10.33.0.34 euro1 <none> <none>
node-affinity-deployment-dc8df7bbf-nxt85 1/1 Running 0 70s 10.33.2.25 euro2 <none> <none>
node-affinity-deployment-dc8df7bbf-rpt5k 1/1 Running 0 69s 10.33.0.35 euro1 <none> <none>
POD-y są rozłożone równomiernie pomiędzy NODE-y. euro1
ma przypisaną etykietę node-role.kubernetes.io/control-plane
o wadze 1. euro2
ma również przypisaną etykietę b=b
o wadze 1.
Co się wydarzy, jeżeli usuniemy etykietę a=a
z NODE-a euro1
i etykietę b=b
z NODE-a euro2
?
kubectl label nodes euro1 a- ; kubectl label nodes euro2 b-
node/euro1 unlabeled
node/euro2 unlabeled
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
node-affinity-deployment-dc8df7bbf-nlkcz 1/1 Running 0 32m 10.33.2.24 euro2 <none> <none>
node-affinity-deployment-dc8df7bbf-nq88k 1/1 Running 0 32m 10.33.0.34 euro1 <none> <none>
node-affinity-deployment-dc8df7bbf-nxt85 1/1 Running 0 32m 10.33.2.25 euro2 <none> <none>
node-affinity-deployment-dc8df7bbf-rpt5k 1/1 Running 0 32m 10.33.0.35 euro1 <none> <none>
Nic się nie zmieniło. Usunięcie etykiet nie wpłynęło na dystrybucję uruchomionych już POD-ów. Natomiast po restarcie wszystkie POD-y trafią na euro2
, ponieważ tylko ten POD ma przypisaną etykietę a=a
.
kubectl rollout restart deployment node-affinity-deployment
deployment.apps/node-affinity-deployment restarted
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
node-affinity-deployment-979965644-45kch 1/1 Running 0 114s 10.33.2.27 euro2 <none> <none>
node-affinity-deployment-979965644-88gng 1/1 Running 0 110s 10.33.2.28 euro2 <none> <none>
node-affinity-deployment-979965644-gjlwv 1/1 Running 0 114s 10.33.2.26 euro2 <none> <none>
node-affinity-deployment-979965644-mnl6s 1/1 Running 0 109s 10.33.2.29 euro2 <none> <none>
Można usunąć przykładowy deployment za pomocą komendy:
kubectl delete deployments node-affinity-deployment
deployment.apps "node-affinity-deployment" deleted
Inter-pod affinity / anti-affinity
Zasada powiązywania (inter-pod affinity) lub izolowania (anti-affinity) przyjmuje taką formę:
Ten POD powinien (lub nie powinien) działać na X pod warunkiem, że na X działają już POD-y spełniające regułę Y. X stanowi topologię oznaczoną kluczem topologyKey
. Y stanowi label selector rule z opcjonalną listą namespace’ów.
Wyróżnia się dwa rodzaje (podobnie jak przy nodeAffinity
):
requiredDuringSchedulingIgnoreDuringExecution
preferredDuringSchedulingIgnoredDuringExecution
Na potrzeby demonstracji skonfigurujemy dwa POD-y.
cat << EOF | tee examplePODs.yaml
apiVersion: v1
kind: Pod
metadata:
name: euro1-pod
labels:
nr: "1"
spec:
nodeSelector:
kubernetes.io/hostname: euro1
containers:
- image: nginx
name: nginx
---
apiVersion: v1
kind: Pod
metadata:
name: euro2-pod
labels:
nr: "2"
spec:
nodeSelector:
kubernetes.io/hostname: euro2
containers:
- image: nginx
name: nginx
EOF
Uruchomienie POD-ów:
kubectl apply -f examplePODs.yaml
pod/euro1-pod created
pod/euro2-pod created
kubectl get pods -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
euro1-pod 1/1 Running 0 18m 10.33.0.36 euro1 <none> <none> nr=1
euro2-pod 1/1 Running 0 18m 10.33.2.30 euro2 <none> <none> nr=2
W kolejnym etapie demonstracji uruchomimy 2 POD-y powiązane odpowiednio z POD-ami euro1-pod
i euro2-pod
za pomocą etykiety nr
.
cat << EOF | tee podAffinity-pods.yaml
apiVersion: v1
kind: Pod
metadata:
name: nr1-pod
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: nr
operator: In
values:
- "1"
topologyKey: kubernetes.io/hostname
containers:
- name: nginx
image: nginx
---
apiVersion: v1
kind: Pod
metadata:
name: nr2-pod
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: nr
operator: In
values:
- "2"
topologyKey: kubernetes.io/hostname
containers:
- name: nginx
image: nginx
EOF
Uruchomienie i weryfikacja dystrybucji POD-ów:
kubectl apply -f podAffinity-pods.yaml
pod/nr1-pod created
pod/nr2-pod created
kubectl get pods -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
euro1-pod 1/1 Running 0 70m 10.33.0.36 euro1 <none> <none> nr=1
euro2-pod 1/1 Running 0 70m 10.33.2.30 euro2 <none> <none> nr=2
nr1-pod 1/1 Running 0 2m20s 10.33.0.37 euro1 <none> <none> <none>
nr2-pod 1/1 Running 0 2m20s 10.33.2.31 euro2 <none> <none> <none>
Analogicznie do nodeAffinity
można definiować podAffinity
jako preferencję z przypisaniem wagi (preferredDuringSchedulingIgnoredDuringExecution
). Dodatkowo można definiować podAntiAffinity
(anty-powiązanie), czyli wybrać, z którymi POD-ami konfigurowane POD-y nie powinny lub nie mogą być uruchamiane w tej samej topologii.
Ważne jest, by wybrany topologyKey
był konsekwentnie zdefiniowany dla każdego z NODE-ów. Podany w przykładzie kubernetes.io/hostname
, jest zdefiniowany automatycznie. Można też wybrać inny klucz topologii, np. topologyKey: miasto
. W tym przypadku należy dopilnować, żeby każdy z NODE-ów miał przypisaną tę etykietę (np. za pomocą komendy kubectl label nodes NODE miasto=Krakow
).
Można usunąć POD-y wykorzystywane do demonstracji:
kubectl delete pods euro1-pod euro2-pod nr1-pod nr2-pod
Taints and Tolerations (skazy i tolerancje)
Taints (skazy) stanowią przeciwieństwo nodeAffinity
. NODE oznaczony skazą (taint), nie może być wybrany przez scheduler dla POD-a, który nie ma zdefiniowanej tolerancji na skazę.
Dodanie Taint (skazy) za pomocą kubectl taint
:
kubectl taint nodes euro1 node-role.kubernetes.io/control-plane:NoSchedule
node/euro1 tainted
Najczęściej control-plane NODE ma dodaną tę skazę domyślnie.
Skazy mogą być też definiowane jako pary KEY=VALUE
. Przykład:
kubectl taint nodes euro2 skaza=tragiczna:NoSchedule
Usuwanie skaz (operator -
):
kubectl taint nodes euro2 skaza=tragiczna:NoSchedule-
Po wykonaniu powyższych kroków, próba uruchomienia standardowego deploymentu nginx
powinna przebiec następująco:
kubectl create deployment nginx --image nginx --replicas 3
deployment.apps/nginx created
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-8f458dc5b-jd56c 1/1 Running 0 68s 10.33.2.36 euro2 <none> <none>
nginx-8f458dc5b-p72s6 1/1 Running 0 68s 10.33.2.37 euro2 <none> <none>
nginx-8f458dc5b-tr5jn 1/1 Running 0 68s 10.33.2.38 euro2 <none> <none>
Wszystkie POD-y „wylądowały” na euro2
. NODE euro1
jest skażony.
Taints mogą tworzyć następujące efekty:
NoSchedule
– Kubernetes scheduler nie uruchomi nowych POD-ów bez wyszczególnionej tolerancjiPreferNoSchedule
– preferencja niekorzystania z NODE-a. Jeżeli inne NODE-y nie będą feasible, scheduler uruchomi POD na oznaczonym NODE-dzieNoExecute
– wszystkie POD-y niemające tolerancji na tę skazę, zostaną wyłączone.
Następny przykład dotyczy różnic w zastosowaniu taint NoSchedule
i NoExecute
:
kubectl taint nodes euro2 skaza:NoSchedule
node/euro2 tainted
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-8f458dc5b-jd56c 1/1 Running 0 7m28s 10.33.2.36 euro2 <none> <none>
nginx-8f458dc5b-p72s6 1/1 Running 0 7m28s 10.33.2.37 euro2 <none> <none>
nginx-8f458dc5b-tr5jn 1/1 Running 0 7m28s 10.33.2.38 euro2 <none> <none>
POD-y dalej pracują na skażonym NODE-dzie, ale nowe POD-y nie mogą zostać uruchomione przez scheduler. Wszystkie NODE-y są „skażone”.
kubectl create deployment nginx2 --image nginx
deployment.apps/nginx2 created
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-8f458dc5b-jd56c 1/1 Running 0 11m 10.33.2.36 euro2 <none> <none>
nginx-8f458dc5b-p72s6 1/1 Running 0 11m 10.33.2.37 euro2 <none> <none>
nginx-8f458dc5b-tr5jn 1/1 Running 0 11m 10.33.2.38 euro2 <none> <none>
nginx2-7cc8cd4598-tpp2s 0/1 Pending 0 3s <none> <none> <none> <none>
Następnie dodajemy skazę NoExecute
:
kubectl taint nodes euro2 handsUP:NoExecute
node/euro2 tainted
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-8f458dc5b-29h9v 0/1 Pending 0 48s <none> <none> <none> <none>
nginx-8f458dc5b-2bj96 0/1 Pending 0 48s <none> <none> <none> <none>
nginx-8f458dc5b-twf8z 0/1 Pending 0 48s <none> <none> <none> <none>
nginx2-7cc8cd4598-tpp2s 0/1 Pending 0 8m20s <none> <none> <none> <none>
POD-y działające na euro2
zostały zatrzymane.
Tolerancja (toleration) jest właściwością POD-a, która umożliwia uruchomienie go pomimo tego, że NODE jest „skażony” (taint). Tolerancję definiuje PodSpec. Przykład:
cat << EOF | tee toleration.yaml
apiVersion: v1
kind: Pod
metadata:
name: tolerancyjny-pod
spec:
containers:
- name: nginx
image: nginx
tolerations:
- key: "skaza"
operator: "Exists"
effect: "NoSchedule"
- key: "handsUP"
operator: "Exists"
effect: "NoExecute"
EOF
Uruchomienie POD-a:
kubectl apply -f toleration.yaml
pod/tolerancyjny-pod created
Zweryfikowanie stanu POD-a:
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-8f458dc5b-29h9v 0/1 Pending 0 5m3s <none> <none> <none> <none>
nginx-8f458dc5b-2bj96 0/1 Pending 0 5m3s <none> <none> <none> <none>
nginx-8f458dc5b-twf8z 0/1 Pending 0 5m3s <none> <none> <none> <none>
nginx2-7cc8cd4598-98h5r 0/1 Pending 0 5m3s <none> <none> <none> <none>
tolerancyjny-pod 1/1 Running 0 68s 10.33.2.46 euro2 <none> <none>
POD został uruchomiony na skażonym hościeeuro2
.
Usunięcie „skaz” z euro2
umożliwi ponowne uruchomienie wstrzymanych POD-ów.
kubectl taint nodes euro2 skaza:NoSchedule-
node/euro2 untainted
kubectl taint nodes euro2 handsUP:NoExecute-
node/euro2 untainted
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-7588f7b96-45f9m 1/1 Running 0 11m 10.33.2.50 euro2 <none> <none>
nginx-7588f7b96-f6745 1/1 Running 0 11m 10.33.2.47 euro2 <none> <none>
nginx-7588f7b96-tws56 1/1 Running 0 11m 10.33.2.48 euro2 <none> <none>
nginx2-7cc8cd4598-98h5r 1/1 Running 0 11m 10.33.2.49 euro2 <none> <none>
tolerancyjny-pod 1/1 Running 0 7m46s 10.33.2.46 euro2 <none> <none>
Podsumowanie
W tym artykule przedstawiliśmy najważniejsze mechanizmy Kubernetes umożliwiające zarządzanie POD-ami w klastrze. Pojęcia takie jak nodeSelector
, affinity
i taints
wykorzystaliśmy w nieskomplikowanych przykładach na klastrze złożonym tylko z 2 NODE-ów. Wyjaśniliśmy również, czym zajmuje się kluczowy komponent Kubernetes – scheduler.