17、Kubernetes核心技术 - 污点(Taints)和污点容忍(Tolerations)

目录

一、概述

二、污点和污点容忍示例

2.1、NoSchedule

2.2、NoExecute

三、污点和污点容忍应用场景

四、k8s内置的一些污点


一、概述

上一篇文章介绍了节点亲和性,它主要实现的是将Pod强制或者尽可能调度到满足某些条件的node节点上**【通过在Pod上添加属性,来确定Pod是否要调度到指定的节点上**】,k8s中的污点,它的行为刚好与节点亲和性相反,污点可以将节点和 Pod 达到互斥的效果,让Pod不被调度到存在污点的那些节点上**【在Node节点上添加污点属性(Taints),来避免Pod被分配到不合适的节点上】**;k8s中的污点容忍,则可以让 Pod 调度到带有污点的节点上。

  • taints(污点)

污点是定义在节点上的键值型属性数据,用于让节点拒绝将Pod 调度运行于其上,除非 Pod 有接纳节点污点的容忍度;

  • tolerations (污点容忍)

污点容忍是定义在 Pod 上的键值型属性数据,用于配置可容忍的污点,且调度器将 Pod 调度至其能容忍该节点污点的节点上或没有污点的节点上;

在k8s中,我们可以给节点添加一些污点,以便在该节点上不能调度任何 Pod,除非Pod明确定义了Tolerations,Tolerations 应用于 Pod,并允许(但不要求)Pod 调度到具有匹配污点的节点上。

可以使用命令 kubectl taint 给节点增加一个污点。比如:

java 复制代码
kubectl taint node <node_name> key=value[effect]   

示例:
# 给节点 master 增加一个污点,它的键名是 key1,键值是 value1,效果是 NoSchedule。 这表示只有拥有和这个污点相匹配的容忍度的 Pod 才能够被分配到这个节点。
kubectl taint node master key1=value1:NoSchedule       # 设置value值

effect可选值有三个:

  • NoSchedule:表示 Pod 将不会被调度到具有该污点的节点上,注意,已经正在运行中的Pod不受影响
  • PreferNoSchedule:表示 Pod 将尽量避免调度到具有该污点的节点上,注意,已经正在运行中的Pod不受影响
  • NoExecute:表示 Pod 将不会被调度到具有该污点的节点上,同时将节点上已经存在的 Pod 进行驱逐,注意,已经正在运行中的Pod也会受影响,因节点污点变动或Pod容忍度变动而不再满足匹配规则时,Pod对象将被驱逐

可以对单个节点应用多个污点,对单个 Pod 应用多个容忍度。

二、污点和污点容忍示例

2.1、NoSchedule

NoSchedule表示 Pod 将不会被调度到具有该污点的节点上,注意,已经正在运行中的Pod不受影响。

假设当前k8s集群有两个node节点,node01和controlplane。我们先给node01节点添加一个NoSchedule类型的污点。

NoSchedule:表示 Pod 将不会被调度到具有该污点的节点上

java 复制代码
#给节点添加污点
$ kubectl taint nodes node01 a=b:NoSchedule
node/node01 tainted

#查看某个节点的污点
$ kubectl describe node node01 | grep Taints
Taints:             a=b:NoSchedule

$ kubectl describe node controlplane | grep Taints
Taints:             <none>

然后我们创建一个三个副本的nginx的Pod:

vim taint-demo.yaml

java 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx

创建三个副本的Pod:

java 复制代码
$ kubectl apply -f taint-demo.yaml 
deployment.apps/nginx created

$ kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-748c667d99-5t842   1/1     Running   0          13s   192.168.0.8   controlplane   <none>           <none>
nginx-748c667d99-dptjw   1/1     Running   0          13s   192.168.0.6   controlplane   <none>           <none>
nginx-748c667d99-gvt5s   1/1     Running   0          13s   192.168.0.7   controlplane   <none>           <none>

我们看到,当前三个Pod都被调度到了controlplane这个节点,因为我们给node01节点设置了一个【a=b:NoSchedule】的污点,并且我们的Pod也没有配置污点容忍,所以Pod不能被调度到node01节点。

如果说我们希望Pod能调度到node01上,我们可以给Pod添加污点容忍,需要修改一下Pod的资源清单,添加tolerations污点容忍的配置:

java 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
      tolerations:  # 污点容忍
        - key: "a"
          operator: "Equal"		# operator的默认值为Equal。(如果键相同且值相同,则容忍匹配污点)
          value: "b"
          effect: "NoSchedule"

如上配置表示Pod能够容忍节点中存在【a=b:NoSchedule】这个污点,说明Pod有资格被调度到存在这个污点的node上,但是,这并不能保证这个 Pod 一定被调度到该节点,因为我们没有指定任何node affinity或者nodeSelector。修改完成后重新应用Pod 清单文件:

java 复制代码
$ vim taint-demo.yaml 
$ kubectl apply -f taint-demo.yaml 
deployment.apps/nginx configured

$ kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-6bfd64d99c-4g9v9   1/1     Running   0          6s    192.168.0.9   controlplane   <none>           <none>
nginx-6bfd64d99c-lf8qv   1/1     Running   0          12s   192.168.1.3   node01         <none>           <none>
nginx-6bfd64d99c-ttscz   1/1     Running   0          4s    192.168.1.4   node01         <none>           <none>

我们看到,当给node01添加了污点容忍后,Pod也能够正常被调度到node01上了。

若要移除上述命令所添加的污点,可以执行:

java 复制代码
#删除污点  kubectl taint node <node名称> key:[effect]-
$ kubectl taint nodes node01 a=b:NoSchedule- 
node/node01 untainted

$ kubectl describe node node01 | grep Taints
Taints:             <none>

2.2、NoExecute

NoExecute表示 Pod 将不会被调度到具有该污点的节点上,同时将节点上已经存在的 Pod 进行驱逐。

vim noexecute-taint-demo.yaml

java 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
java 复制代码
$ kubectl apply -f noexecute-taint-demo.yaml 
deployment.apps/nginx created

$ kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-748c667d99-2s88m   1/1     Running   0          9s    192.168.1.4   node01         <none>           <none>
nginx-748c667d99-lgndm   1/1     Running   0          9s    192.168.1.3   node01         <none>           <none>
nginx-748c667d99-tj4tc   1/1     Running   0          9s    192.168.0.6   controlplane   <none>           <none>

$ kubectl describe node node01 | grep Taints
Taints:             <none>
$ kubectl describe node controlplane | grep Taints
Taints:             <none>

可以看到,Pod被分别调度到两个节点上。接下来,我们给node01节点添加一个NoExecute类型的污点:

java 复制代码
$ kubectl taint nodes node01 c=d:NoExecute
node/node01 tainted

$ kubectl describe node node01 | grep Taints
Taints:             c=d:NoExecute

然后我们再查看Pod详情:

java 复制代码
$ kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP            NODE           NOMINATED NODE   READINESS GATES
nginx-748c667d99-tj4tc   1/1     Running   0          2m58s   192.168.0.6   controlplane   <none>           <none>
nginx-748c667d99-tt5db   1/1     Running   0          34s     192.168.0.7   controlplane   <none>           <none>
nginx-748c667d99-v687w   1/1     Running   0          34s     192.168.0.8   controlplane   <none>           <none>

可以看到,之前调度到node01的两个Pod,已经被驱逐了,然后重新被调度到controlplane节点上。

实际上任何不容忍NoExecute污点的Pod都将被立即驱逐,而能够容忍污点的Pod 将永远不会被驱逐。但是可以指定一个可选tolerationSeconds字段,该字段指示在添加污点后Pod 将保持绑定到节点的时间。例如:

java 复制代码
tolerations:
- key: "c"
  operator: "Equal"
  value: "d"
  effect: "NoExecute"
  tolerationSeconds: 3600  # 表示当 Pod 被驱逐时,还可以在节点上继续运行的时间(仅可以和NoExecute配合使用)

如果这个Pod 正在运行并且有一个匹配的污点被添加到该节点,那么该Pod将保持绑定到该节点 3600 秒,然后被驱逐。如果在该时间之前移除了污点,则Pod不会被驱逐。

三、污点和污点容忍应用场景

  • 1、专用节点:当想将一组节点专用于专有工作负载或特定用户时,您可以向这些节点添加一个污点,然后向它们的Pod 添加相应的容忍度。
  • 2、具有特殊硬件的节点:对于具有专用硬件的节点,我们只希望具有这些要求的Pod 在这些节点上运行。污染将帮助我们并为使用特殊硬件的Pod 添加相应的容忍度。
  • 3、基于污点的驱逐:当节点存在问题时,每个Pod可配置的驱逐行为。

四、k8s内置的一些污点

Kubernetes自1.6版本起支持使用污点自动标识问题节点,它通过节点控制器在特定条件下自动为节点添加污点信息实现。目前,内建使用的此类污点包含如下几个。

Kubernetes的核心组件通常都要容忍此类的污点,以确保其相应的DaemonSet控制器能够无视此类污点,便于节点上部署相应的关键性Pod对象,例如kube-proxy或kube- flannel等。

我们可以通过kubectl describe pod xx查看污点容忍信息,例如下面是kube-proxy的一些污点容忍配置:

java 复制代码
Tolerations:                 op=Exists
                             node.kubernetes.io/disk-pressure:NoSchedule op=Exists
                             node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                             node.kubernetes.io/network-unavailable:NoSchedule op=Exists
                             node.kubernetes.io/not-ready:NoExecute op=Exists
                             node.kubernetes.io/pid-pressure:NoSchedule op=Exists
                             node.kubernetes.io/unreachable:NoExecute op=Exists
                             node.kubernetes.io/unschedulable:NoSchedule op=Exists

参考:污点和容忍度 | Kubernetes

相关推荐
moppol26 分钟前
Serverless 架构入门与实战:AWS Lambda、Azure Functions、Cloudflare Workers 对比
云原生·serverless·aws
IvanCodes1 小时前
一、Docker:一场颠覆应用部署与运维的容器革命
docker·容器
栗子~~1 小时前
Milvus docker-compose 部署
docker·容器·milvus
没有名字的小羊3 小时前
2.安装Docker
运维·docker·容器
xiezhr3 小时前
50 个常用 Docker 命令
运维·docker·容器
退役小学生呀9 天前
三、kubectl使用详解
云原生·容器·kubernetes·k8s
被困者10 天前
Linux部署Sonic前后端(详细版)(腾讯云)
spring cloud·云原生·eureka
程序员小潘10 天前
Kubernetes多容器Pod实战
云原生·容器·kubernetes
进击的码码码码N10 天前
Docker 镜像加速
运维·docker·容器