Skip to main content

Taint and Tolerations

Taints são aplicadas aos Nodes e Tolerations são aplicadas aos Pods.

As Taints funcionam nos Nodes para evitar que Pods entrem nesses Nodes, porém se um Pod tiver uma Toleration para esta Taint ele poderá ser agendado para os Nodes com a respectiva Taint.

Vamos pensar numa Taint como repelente para o Node e os Pods como os diferentes tipos de 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 agendado 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 tivesse a Toleration para o Node específico. Outros recursos existem para configurar essa garantia.

Podemos usar as Taints para separar:

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

As Taints podem ter qualquer 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 agendados para este Node se possuir a Toleration respectiva à Taint.
  • PreferNoSchedule: Faz uma preferência de não agendar, porém se não existir espaço em outros Nodes para um Pod, este poderá ser agendado.
  • NoExecute: Qualquer Pod que não tenha essa Toleration não deve ser agendado e os Pods que estiverem 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.

# Criar 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 IMPLANTAR APLICAÇÕES NOS NODES MASTERS. LOGO, É IMPORTANTE QUE OS NODES 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 altera 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 da 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 agendar 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 pois 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 está em pending? Porque 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 uma 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.