Taints et Affinity
Prérequis
Jusqu’à présent, lorsque nous déployions un Pod dans le cluster Kubernetes, il était exécuté sur n’importe quel nœud répondant aux exigences (c’est-à-dire les exigences en matière de mémoire, de CPU, …).
Cependant, dans Kubernetes, il existe deux concepts qui vous permettent de configurer davantage le planificateur, de sorte que les pods soient affectés aux nœuds en fonction de certains critères commerciaux.
Preparation
Si vous exécutez ce tutoriel dans Minikube, vous devez déployer un premier noeud en utilisant le driver docker :
minikube stop
minikube delete --all
minikube start --driver=dockerSi vous avez un proxy
minikube stop
minikube delete --all
minikube start --docker-env HTTPS_PROXY=$HTTPS_PROXY --docker-env HTTP_PROXY=$HTTP_PROXY --docker-env=NO_PROXY=$no_proxyAjouter des nœuds supplémentaires pour exécuter cette partie du tutoriel. Vérifiez le nombre de nœuds que vous avez delpoyés en exécutant :
kubectl get nodesSi un seul nœud est présent, vous devez créer un nouveau nœud en suivant les étapes suivantes :
NAME STATUS ROLES AGE VERSION
kube Ready master 54m v1.23.1Ayant minikube installé et dans votre PATH, puis exécutez :
minikube node addkubectl get nodesNAME STATUS ROLES AGE VERSION
kube Ready master 54m v1.23.1
kube-m02 Ready <none> 2m50s v1.23.1Taints et Tolérance
Une taint est appliquée à un nœud Kubernetes qui signale au planificateur d’éviter ou de ne pas planifier certains pods.
Une tolérance est appliquée à la définition d’un pod et fournit une exception au taint.
Décrivons les nœuds actuels, dans ce cas comme un cluster Minikube est utilisé, vous pouvez voir plusieurs nœuds :
kubectl describe nodes | egrep "Name:|Taints:"Name: minikube
Taints: <none>
Name: minikube-m02
Taints: <none>Notez que dans ce cas, les nœuds ne contient pas de taint.
Taints
Ajoutons une tache à tous les noeuds :
kubectl taint nodes --all=true color=blue:NoSchedulenode/minikube tainted
node/minikube-m02 taintedLa couleur=bleue est simplement une paire clé=valeur pour identifier la taint et NoSchedule est l’effet spécifique.
Maintenant, déployez un nouveau pod.
vim apps/kubefiles/myboot-nginx-deployment.ymlapiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myboot
name: myboot
spec:
replicas: 1
selector:
matchLabels:
app: myboot
template:
metadata:
labels:
app: myboot
spec:
containers:
- name: myboot
image: nginx
ports:
- containerPort: 8080kubectl apply -f apps/kubefiles/myboot-nginx-deployment.yml
kubectl get podsLe pod restera en statut Pending car il n’a pas de nœud programmable disponible.
NAME READY STATUS RESTARTS AGE
myboot-7f889dd6d-n5z55 0/1 Pending 0 55skubectl describe pod myboot-7f889dd6d-n5z55Name: myboot-7f889dd6d-n5z55
Namespace: kubetut
Priority: 0
Node: <none>
Labels: app=myboot
pod-template-hash=7f889dd6d
Annotations: openshift.io/scc: restricted
Status: Pending
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling <unknown> default-scheduler 0/9 nodes are available: 9 node(s) had taints that the pod didn't tolerate.
Warning FailedScheduling <unknown> default-scheduler 0/9 nodes are available: 9 node(s) had taints that the pod didn't tolerate.Maintenant, enlevons une tare d’un noeud et voyons ce qui se passe :
kubectl get nodesNAME STATUS ROLES AGE VERSION
minikube Ready control-plane,master 120m v1.23.1
minikube-m02 Ready <none> 119m v1.23.1Choisissez un nœud.
kubectl taint node minikube-m02 color:NoSchedule-node/minikube-m02 untaintedkubectl describe nodes | egrep "Name:|Taints:"Name: minikube
Taints: color=blue:NoSchedule
Name: minikube-m02
Taints: <none>Et vous devriez voir le pod en attente programmé sur le nouveau nœud non taint.
kubectl get podsNAME READY STATUS RESTARTS AGE
myboot-7f84d7cfc9-2m4lh 1/1 Running 0 7mSupprimer les ressources
kubectl delete -f apps/kubefiles/myboot-nginx-deployment.yml
kubectl taint node minikube-m02 color=blue:NoScheduleTolerations
Créons un Pod mais contenant une tolérance, afin qu’il puisse être programmé vers un nœud taint.
spec:
tolerations:
- key: "color"
operator: "Equal"
value: "blue"
effect: "NoSchedule"
containers:
- name: myboot
image: nginxvim apps/kubefiles/myboot-toleration.yamlapiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myboot
name: myboot
spec:
replicas: 1
selector:
matchLabels:
app: myboot
template:
metadata:
labels:
app: myboot
spec:
tolerations:
- key: "color"
operator: "Equal"
value: "blue"
effect: "NoSchedule"
containers:
- name: myboot
image: nginx
ports:
- containerPort: 8080kubectl apply -f apps/kubefiles/myboot-toleration.yaml
kubectl get podsNAME READY STATUS RESTARTS AGE
myboot-84b457458b-mbf9r 1/1 Running 0 3m18sMaintenant, bien que tous les nœuds contiennent une taint, le Pod est programmé et exécuté comme nous avons défini une tolérance contre la taint color=blue.
Supprimer les ressources
kubectl delete -f apps/kubefiles/myboot-toleration.yamlPas d’exécution de taint
Jusqu’à présent, vous avez vu l’effet du défaut NoSchedule qui signifie que les pods nouvellement créés ne seront pas planifiés à cet endroit, à moins qu’ils ne disposent d’une tolérance prioritaire. Mais remarquez que si nous ajoutons cette taint à un nœud qui a déjà des pods en cours d’exécution/planifiés, cette taint ne les arrêtera pas.
Changeons cela en utilisant l’effet NoExecution.
Tout d’abord, supprimons toutes les altérations précédentes.
kubectl taint nodes --all=true color=blue:NoSchedule-Ensuite, déployez un service :
kubectl apply -f apps/kubefiles/myboot-nginx-deployment.yml
kubectl get podsNAME READY STATUS RESTARTS AGE
myboot-7f889dd6d-bkfg5 1/1 Running 0 16skubectl get pod myboot-7f889dd6d-bkfg5 -o json | jq '.spec.nodeName'"minikube-m02"kubectl taint node minikube-m02 color=blue:NoExecute
kubectl get podsNAME READY STATUS RESTARTS AGE
myboot-7f889dd6d-8fm2v 1/1 Running 0 14s
myboot-7f889dd6d-bkfg5 1/1 Terminating 0 5m51sSi vous avez plus de nœuds disponibles, alors le Pod est terminé et déployé sur un autre nœud, si ce n’est pas le cas, alors le Pod restera en statut Pending.
Vous pouvez observer cette “reprogrammation” à l’aide de -o wide.
watch kubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODE
myboot-7f889dd6d-b9tks 1/1 Running 0 6s 10.88.0.5 minikube
myboot-7f889dd6d-l897f 1/1 Terminating 0 9m11s 172.17.0.4 minikube-m02Supprimer les ressources
kubectl delete -f apps/kubefiles/myboot-deployment.ymlEt supprimer la taint NoExecute
kubectl taint node minikube-m02 color=blue:NoExecute-Affinité et antiaffinité
Il existe une autre façon de changer l’endroit où les Pods sont programmés en utilisant l’affinité et l’anti-affinité Node/Pod. Vous pouvez créer des règles qui non seulement interdisent les endroits où les Pods peuvent s’exécuter mais aussi qui favorisent les endroits où ils doivent s’exécuter.
En plus de créer des affinités entre les pods et les nœuds, vous pouvez également créer des affinités entre les pods. Vous pouvez décider qu’un groupe de pods doit toujours être déployé ensemble sur le(s) même(s) nœud(s). Des raisons telles qu’une communication réseau importante entre les Pods et vous voulez éviter les appels réseau externes ou peut-être les périphériques de stockage partagés.
Affinité des nœuds
Déployons un nouveau pod avec une affinité de nœud :
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: color
operator: In
values:
- blue
containers:
- name: myboot
image: nginxvim apps/kubefiles/myboot-node-affinity.ymlapiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myboot
name: myboot
spec:
replicas: 1
selector:
matchLabels:
app: myboot
template:
metadata:
labels:
app: myboot
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: color
operator: In
values:
- blue
containers:
- name: myboot
image: nginx
ports:
- containerPort: 8080kubectl apply -f apps/kubefiles/myboot-node-affinity.yml
kubectl get podsNAME READY STATUS RESTARTS AGE
myboot-54d788fdc8-f6wks 0/1 Pending 0 13sCréons une étiquette sur un nœud correspondant à l’expression d’affinité :
kubectl get nodesNAME STATUS ROLES AGE VERSION
minikube Ready control-plane,master 27m v1.23.1
minikube-m02 Ready <none> 25m v1.23.1NAME STATUS ROLES AGE VERSION
minikube Ready control-plane,master 27m v1.23.1
minikube-m02 Ready <none> 25m v1.23.1kubectl label nodes minikube-m02 color=bluenode/minikube-m02 labeledkubectl get podsNAME READY STATUS RESTARTS AGE
myboot-54d788fdc8-f6wks 1/1 Running 0 7m57sSupprimons l’étiquette du nœud :
kubectl label nodes minikube-m02 color-
kubectl get podsNAME READY STATUS RESTARTS AGE
myboot-54d788fdc8-f6wks 1/1 Running 0 7m57sComme pour les taints, la règle est définie pendant la phase d’ordonnancement, par conséquent, le Pod n’est pas supprimé.
Il s’agit d’un exemple de règle stricte, si le planificateur de Kubernetes ne trouve pas de nœud avec l’étiquette requise, le pod est rappelé dans l’état Pending. Il est également possible de créer une règle souple, dans laquelle le planificateur Kubernetes tente de répondre aux règles, mais s’il n’y parvient pas, le pod est programmé vers n’importe quel nœud. Dans l’exemple ci-dessous, vous pouvez voir l’utilisation du mot préféré par rapport au mot requis.
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: color
operator: In
values:
- blueSupprimer les ressources
kubectl delete -f apps/kubefiles/myboot-node-affinity.ymlPod Affinity/Anti-Affinity
Déployons un nouveau pod avec un Pod Affinity :
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname (1)
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myboot (2)
containers:1- La clé de l’étiquette du nœud. Si deux noeuds sont étiquetés avec cette clé et ont des valeurs identiques, l’ordonnanceur traite les deux noeuds comme étant dans la même topologie. Dans ce cas, le nom d’hôte est une étiquette qui est différente pour chaque noeud. 2- L’affinité est avec les pods étiquetés avec app=myboot.
vim apps/kubefiles/myboot-pod-affinity.ymlapiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myboot2
name: myboot2
spec:
replicas: 1
selector:
matchLabels:
app: myboot2
template:
metadata:
labels:
app: myboot2
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myboot
containers:
- name: myboot
image: nginx
ports:
- containerPort: 8080kubectl apply -f apps/kubefiles/myboot-pod-affinity.yml
kubectl get podsNAME READY STATUS RESTARTS AGE
myboot2-784bc58c8d-j2l74 0/1 Pending 0 19sLe Pod myboot2 est en attente car il n’a pas pu trouver de Pod correspondant à la règle d’affinité. Déployons l’application myboot étiquetée avec app=myboot.
kubectl apply -f apps/kubefiles/myboot-nginx-deployment.yml
kubectl get podsNAME READY STATUS RESTARTS AGE
myboot-7f889dd6d-tr7gr 1/1 Running 0 3m27s
myboot2-64566b697b-snm7p 1/1 Running 0 18sMaintenant, les deux applications sont exécutées dans le même nœud :
kubectl get pod myboot-7f889dd6d-tr7gr -o json | jq '.spec.nodeName'minikubekubectl get pod myboot2-64566b697b-snm7p -o json | jq '.spec.nodeName'minikubeCe que vous avez vu ici est une règle stricte, vous pouvez également utiliser des règles “douces” dans Pod Affinity.
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
topologyKey: kubernetes.io/hostname
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- mybootL’anti-affinité est utilisée pour s’assurer que deux pods ne fonctionnent PAS ensemble sur le même nœud.
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- mybootDéployer un myboot3 avec une règle d’anti-affinité
vim apps/kubefiles/myboot-pod-antiaffinity.yamlapiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myboot3
name: myboot3
spec:
replicas: 1
selector:
matchLabels:
app: myboot3
template:
metadata:
labels:
app: myboot3
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myboot
containers:
- name: myboot
image: nginx
ports:
- containerPort: 8080kubectl apply -f apps/kubefiles/myboot-pod-antiaffinity.yamlPuis utilisez la commande kubectl get pods -o wide pour voir quels pods atterrissent sur quels noeuds.
kubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODE
myboot-7f889dd6d-tr7gz 1/1 Running 0 4m27s 10.88.0.9 minikube
myboot2-64566b697b-snm7p 1/1 Running 0 48s 10.88.0.10 minikube
myboot3-78656b637r-suy1t 1/1 Running 0 1s 172.17.0.2 minikube-m02Le pod myboot3 est déployé dans un nœud différent de celui du pod myboot.
Supprimer les ressources
kubectl delete -f apps/kubefiles/myboot-pod-affinity.yml
kubectl delete -f apps/kubefiles/myboot-pod-antiaffinity.yml
kubectl delete -f apps/kubefiles/myboot-deployment.yml