Skip to main content

Taint and tolerations

Taint são aplicadas aos nodes e tolerations são aplicados aos pods.

As taints funcionam nos nodes para evitar que pods entrem nesses nodes, porém se um pods tiver uma toleration para esta taint ele poderá ser schedulado para os nodes com a respectiva taint.

Vamos pensar numa taint como repelente para o node e os pods como os diferentes tipos te insetos. Temos repelentes que funcionam para alguns insetos, mas não para outros. Se um inseto (Pod) for imune (tolerar) a este repelente poderá chegar (picar) os nodes que utilizam o repelente (taint).

Uma outra analogia que podemos fazer é que as taints são fechaduras e somente os pods que possuem as chaves (tolerations) conseguem abrir e entrar. Essa fechadura não tem nada a ver com segurança ou intrusão é somente restrição entre pods e nodes.

Um pod que possui uma toleration para uma taint é possível ser schedulado para para o node com esta taint, mas isso não garante que isso acontecerá. Se existir algum outro node sem nenhuma taint que seja melhor para receber o pod, esse poderá ser o escolhido. Só seria garantia de um pod entrar em um node com uma taint se todos os nodes do cluster tivessem taints diferentes e o pod a toleration para o node específico. Outros recursos existem para configurar essa garantia.

Podemos usar as taints para separar:

  • Nodes pode ambientes
  • Nodes por tipo de aplicação, exemplo aplicações que exigem processamento gráfico, seriam melhor executadas em nodes com placa gráfica.

As taints podem ter quaisquer conjunto de chave-valor no node, assim como labels, porém se uma taint existe ela precisa ter um efeito do que acontece com um pod se não tiver a toleration e são 3 possíveis valores:

  • NoSchedule: Se uma taint possuir esse efeito, os novos pods devem somente ser schedulados para este node se possuir a toleration respectiva a taint.
  • PreferNoSchedule: Faz uma preferência de não schedular, porém se não existir espaço em outros nodes para um pod, este poderá ser schedulado.
  • NoExecute: Qualquer pod que não tenha essa toleration não deve ser schedulado e os pods que estivem no node e não tiverem a toleration devem ser removidos.

Para aplicar uma taint em um node precisamos executar o comando kubectl taint nodes node_name key=values:taint-effect.

# create taint
kubectl taint node k3d-k3d-cluster-server-0 app=test:NoSchedule
# Remover taint é o mesmo comando com o - no final
kubectl taint node k3d-k3d-cluster-server-0 app=test:NoSchedule-

UMA BOA PRÁTICA, E RECOMENDÁVEL, É NÃO DEPLOYAR APLICAÇÕES NOS NODES MASTERS. LOGO, É IMPORTANTE QUE OS NODE MASTERS TENHAM UMA TAINT QUE NENHUM POD TOLERE COM O EFEITO NoExecute.

No pod, para aplicar uma toleration, é necessário incluir as configurações desejadas dentro do campo tolerations na especificação do pod.

apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
tolerations:
- key: app
operator: Equal
value: test
effect: NoSchedule

Para o exemplo acima, nenhum node possui taint, mas o pod terá uma toleration.

kubectl apply -f pod-toleration.yaml
pod/nginx created

## Nessa sequência abaixo, uma vez ele foi criado no server, outra vez ele foi criado no agent2, ou seja, não muda nada.
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 4m20s 10.42.3.3 k3d-k3d-cluster-server-0 <none> <none>

kubectl delete pod nginx
pod "nginx" deleted

kubectl apply -f pod-toleration.yaml
pod/nginx created

kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 4m20s 10.42.3.3 k3d-k3d-cluster-agent-1 <none> <none>

kubectl delete pod nginx
pod "nginx" deleted

NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k3d-k3d-cluster-agent-2 Ready <none> 70d v1.27.4+k3s1 172.18.0.2 <none> K3s dev 6.2.0-39-generic containerd://1.7.1-k3s1
k3d-k3d-cluster-server-0 Ready control-plane,master 70d v1.27.4+k3s1 172.18.0.4 <none> K3s dev 6.2.0-39-generic containerd://1.7.1-k3s1
k3d-k3d-cluster-agent-1 Ready <none> 70d v1.27.4+k3s1 172.18.0.3 <none> K3s dev 6.2.0-39-generic containerd://1.7.1-k3s1
k3d-k3d-cluster-agent-0 Ready <none> 70d v1.27.4+k3s1 172.18.0.5 <none> K3s dev 6.2.0-39-generic containerd://1.7.1-k3s1

## Vamos aplicar taints ao node server, agent0 agent1, mas não as mesmas do toleration do pod
kubectl taint node k3d-k3d-cluster-server-0 run=test:NoSchedule
node/k3d-k3d-cluster-server-0 tainted
kubectl taint node k3d-k3d-cluster-agent-0 run=test:NoSchedule
node/k3d-k3d-cluster-agent-0 tainted
kubectl taint node k3d-k3d-cluster-agent-1 run=test:NoSchedule
node/k3d-k3d-cluster-agent-1 tainted

# Observe que ele foi para o agent2
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 7s 10.42.2.48 k3d-k3d-cluster-agent-2 <none> <none>

# Aplicando uma taint no agent2 para não schedular e já remover quem não tiver a toleration
kubectl taint node k3d-k3d-cluster-agent-2 run=test:NoExecute
node/k3d-k3d-cluster-agent-2 tainted

kubectl get pods -o wide
No resources found in default namespace. # O pod sumiu e não voltou pq não tem um replicaset

kubectl apply -f pod-toleration.yaml
pod/nginx created
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 0/1 Pending 0 56s <none> <none> <none> <none>

kubectl describe pods nginx
Name: nginx
Namespace: default
Priority: 0
Service Account: default
Node: <none>
Labels: <none>
Annotations: <none>
Status: Pending
IP:
IPs: <none>
Containers:
nginx:
Image: nginx
Port: <none>
Host Port: <none>
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-2nh84 (ro)
Conditions:
Type Status
PodScheduled False
Volumes:
kube-api-access-2nh84:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: app=test:NoSchedule
node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
## Veja que não tem node disponível
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 3m22s default-scheduler 0/4 nodes are available: 4 node(s) had untolerated taint {run: test}. preemption: 0/4 nodes are available: 4 Preemption is not helpful for scheduling..

## Agora vamos aplicar ao agent1 a taint que o pod tem a toleration
files git:(main) ✗ kubectl taint node k3d-k3d-cluster-agent-1 app=test:NoSchedule
node/k3d-k3d-cluster-agent-1 tainted

# E por que não entrou e ainda esta em pending? Pq ele precisaria tolerar as duas taints, então vamos remover a primeira
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 0/1 Pending 0 5m19s <none> <none> <none> <none>

# Removendo a taint que o pod não suporta
kubectl taint node k3d-k3d-cluster-agent-1 run=test:NoSchedule-
node/k3d-k3d-cluster-agent-1 untainted

kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 6m36s 10.42.1.36 k3d-k3d-cluster-agent-1 <none> <none>

Claro que poderíamos ter adicionado um toleration a mais já que é uma lista no pod, mas foi só para ilustrar.

Alt text

DaemonSets são especificados para colocar um pod a cada node, porém um daemonset também respeita as taints, se ele não suportar as taints ele não entrará no node.