
kubernetes 核心技术-调度器
概述
一个容器平台的主要功能就是为容器分配运行时所需要的计算,存储和网络资源。 容器调度系统负责选择在最合适的主机上启动容器,并且将它们关联起来。
Scheduler是kubernetes的调度器,主要的任务是把定义好的pod分配到集群的节点上。
Kubernetes的资源分为两种属性:
1、可压缩资源(例如CPU、 Disk I/O、带宽)都是可以被限制和被回收的,对于一个Pod来说可以降低这些资源的使用量而不去杀掉 Pod。
2、不可压缩资源(例如内存、硬盘空间)一般来说不杀掉Pod就没法回收。
调度过程
scheduler是kubernetes的调度器,它的主要作用就是根据特定的调度算法和调度策略将Pod调度到合适的Node节点上去,是一个独立的二进制程序,启动之后会一直监听API Server,获取到PodSpec.NodeName为空的 Pod,对每个Pod都会创建一个binding。

调度主要分为以下几个部分:
首先是预选过程,过滤掉不满足条件的节点,这个过程称为Predicates [ˈpredɪkeɪts]。比如Pod指定了所需要的资源,那么就要过滤掉资源不够的主机。
然后是优选过程,对通过的节点按照优先级排序,称之为Priorities [praɪˈɔrətiz]
最后从中选择优先级最高的节点,如果中间任何一步骤有错误,就直接返回错误
Predicates阶段首先遍历全部节点,过滤掉不满足条件的节点,属于强制性规则, 这一阶段输出的所有满足要求的Node将被记录并作为第二阶段的输入,如果所有的节点都不满足条件,那么Pod将会一直处于Pending状态,直到有节点满足条件,在这期间调度器会不断的重试。所以我们在部署应用的时候,如果发现有Pod 一直处于Pending状态,那么就是没有满足调度条件的节点,这个时候可以去检查下节点资源是否可用。
Priorities阶段即再次对节点进行筛选,如果有多个节点都满足条件的话,那么系统会按照节点的优先级(priorites)大小对节点进行排序,最后选择优先级最高的节点来部署Pod应用。
下面是调度过程的简单示意图:

更详细的流程是这样的:
首先,客户端通过API Server的REST API或者kubectl工具创建Pod资源
API Server收到用户请求后,存储相关数据到etcd数据库中
调度器监听watch API Server查看未调度(bind)的Pod列表,循环遍历地为每个Pod尝试分配节点,这个分配过程就是我们上面提到的两个阶段:
预选阶段(Predicates),过滤节点,调度器用一组规则过滤掉不符合要求的Node 节点,比如 Pod 设置了资源的 request, 那么可用资源比 Pod 需要的资源少的主机显然就会被过滤掉。
优选阶段(Priorities),为节点的优先级打分,将上一阶段过滤出来的Node列表进行打分,调度器会考虑一些整体的优化策略,比如把 Deployment 控制的多个 Pod 副本分布到不同的主机上,使用最低负载的主机等等策略。
经过上面的阶段过滤后选择打分最高的Node节点和Pod进行binding操作,然后将结果存储到etcd中。
最后被选择出来的Node节点对应的kubelet去执行创建Pod的相关操作
其中Predicates过滤有一系列的算法可以使用,我们这里简单列举几个:
PodFitsResources:节点上剩余的资源是否大于 Pod 请求的资源
PodFitsHost:如果 Pod 指定了 NodeName, 检查节点名称是否和 NodeName 匹配
PodFitsHostPorts:节点上已经使用的 port 是否和 Pod 申请的 port 冲突
PodSelectorMatches:过滤掉和 Pod 指定的 label 不匹配的节点
NoDiskConflict:已经 mount 的 volume 和 Pod 指定的 volume 不冲突, 除非它们都是只读的
CheckNodeDiskPressure:检查节点磁盘空间是否符合要求
CheckNodeMemoryPressure:检查节点内存是否够用
除了这些过滤算法之外, 还有一些其他的算法, 更多更详细的我们可以查看源码文件:
k8s.io/kubernetes/pkg/scheduler/algorithm/predicates/predicates.go。
而Priorities优先级是由一系列键值对组成的,键是该优先级的名称,值是它的权重值,同样,我们这里给大家列举几个具有代表性的选项:
LeastRequestedPriority: 通过计算CPU和内存的使用率来决定权重,使用率越低权重越高,换句话说,这个优先级指标倾向于资源使用比例更低的节点,当然正常肯定也是资源使用率越低权重越高,能给别的Pod运行的可能性就越大
SelectorSpreadPriority: 为了更好的高可用, 对同属于一个 Deployment 或者 RC 下面的多个 Pod 副本, 尽量调度到多个不同的节点上, 当一个 Pod 被调度的时候, 会先去查找该 Pod 对应的 controller, 然后查看该 controller 下面的已存在的 Pod,运行 Pod越少的节点权重越高。
ImageLocalityPriority:倾向于已经又要使用镜像的节点,就是如果在某个节点上已经有要使用的镜像了,镜像总大小值越大,权重就越高。
NodeAffinityPriority: 这个就是根据节点的亲和性来计算一个权重值, 后面我们会详细讲解亲和性的使用方法
通过算法对所有的优先级项目和权重进行计算,得出最终的结果。
亲和性和反亲和性
亲和特性包括两种类型:node节点亲和性/反亲和性和pod亲和性/反亲和性。pod亲和性/反亲和性约束针对的是pod标签而不是节点标签。
注拓扑域是什么:多个node节点,拥有相同的label标签【节点标签的键值相同】,那么这些节点就处于同一个拓扑域。
节点亲和性
节点亲和性(nodeAffinity)主要是用来控制 Pod 要部署在哪些节点上,以及不能部署在哪些节点上的
节点亲和性规则分为:硬亲和性required、软亲和性preferred。
requiredDuringSchedulingIgnoredDuringExecution:硬策略
preferredDuringSchedulingIgnoredDuringExecution:软策略
硬亲和性表示Pod要调度到的节点必须满足规则条件,不满足则不会调度,pod会一直处于Pending状态;软亲和性表示优先调度到满足规则条件的节点,如果不能满足会选择一个不匹配的节点。
当节点标签改变而不再符合此节点亲和性规则时,不会将 Pod从该节点移出,仅对新建的 Pod 对象生效。
节点硬亲和性
方式一:Pod 使用 spec.nodeSelector (基于等值关系)
方式二:Pod 使用 spec.affinity 支持 matchExpressions 属性 (复杂标签选择机制)
1、nodeSelector
k8s非常常用的一个调度方式:nodeSelector
用户可以灵活的利用label来管理集群中的资源,比如常见的service对象通过label去匹配pod资源,而pod的调度也可以根据节点的label来进行调度
查看node的label命令
bash
[root@master1 ~]# kubectl get nodes --show-labels
给一个节点(例如node1)增加标签
bash
[root@master1 ~]# kubectl label nodes node1 zone=foo
node/node1 labeled
Pod yaml文件:
[root@master1 ~]# vim pod-selector-demo.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: busybox-pod
name: test-busybox
spec:
containers:
- command:
- sleep
- "3600"
image: busybox
imagePullPolicy: Always
name: test-busybox
nodeSelector:
zone: foo
创建pod
bash
[root@master1 ~]# kubectl create -f pod-selector-demo.yaml
pod/test-busybox created
查看pod
bash
[root@master1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-busybox 1/1 Running 0 61s 10.244.1.18 node1 <none> <none>
[root@master1 ~]# kubectl describe pod test-busybox
.................................
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m5s default-scheduler Successfully assigned default/test-busybox to node1
Normal Pulling 3m4s kubelet Pulling image "busybox"
Normal Pulled 2m32s kubelet Successfully pulled image "busybox" in 31.483229769s
Normal Created 2m32s kubelet Created container test-busybox
Normal Started 2m32s kubelet Started container test-busybox
我们可以看到Events下面的信息,我们的Pod通过默认的default-scheduler调度器被绑定到了node1节点。不过需要注意的是nodeSelector 属于强制性的,如果我们的目标节点没有可用的资源,我们的 Pod 就会一直处于 Pending 状态。
通过上面的例子我们可以感受到 nodeSelector 的方式比较直观,但是还够灵活,控制粒度偏大,接下来我们再和大家了解下更加灵活的方式:节点亲和性(nodeAffinity)。
2、pod.spec.nodeAffinity
requiredDuringSchedulingIgnoredDuringExecution:硬策略
调度至 zone = foo 的节点
先将之前在node1节点创建的label(zone=foo)删除
bash
[root@master1 ~]# kubectl label nodes node1 zone-
Pod yaml文件
[root@master1 ~]# vim required-node-affinity-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: with-required-nodeaffinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #定义硬亲和性
nodeSelectorTerms:
- matchExpressions: #集合选择器
- {key: zone,operator: In,values: ["foo"]}
containers:
- name: test1-busybox
image: busybox:1.30
command:
- sleep
- "3600"
创建pod
bash
[root@master1 ~]# kubectl create -f required-node-affinity-demo.yaml
pod/with-required-nodeaffinity created
查看Pod
bash
[root@master1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
with-required-nodeaffinity 0/1 Pending 0 5s <none> <none> <none> <none>
发现pod的状态为pending,因为节点硬亲和性规则没有匹配zone=foo的标签的节点。
给节点Node2设置label zone=foo
bash
[root@master1 ~]# kubectl label nodes node2 zone=foo
node/node2 labeled
查看Pod
bash
[root@master1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
with-required-nodeaffinity 1/1 Running 0 32s 10.244.2.15 node2 <none> <none>
节点软亲和性
preferredDuringSchedulingIgnoredDuringExecution
节点软亲和性,优先调度到满足条件的节点,如果都不满足也会调度到其他节点。
权重weight定义优先级,1-100值越大优先级越高
Pod yaml文件
bash
[root@master1 ~]# vim preferred-node-affinity-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy-with-node-affinity
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
name: myapp-pod
labels:
app: myapp
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution: #节点软亲和性
- weight: 60
preference:
matchExpressions:
- {key: zone,operator: In,values: ["foo"]} #表示node标签存在zone=foo
- weight: 30
preference:
matchExpressions:
- {key: ssd,operator: Exists,values: []}
containers:
- name: myapp
image: busybox:1.30
command:
- sleep
- "3600"
创建pod
bash
[root@master1 ~]# kubectl create -f preferred-node-affinity-demo.yaml
deployment.apps/myapp-deploy-with-node-affinity created
查看pod
bash
[root@master1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-deploy-with-node-affinity-679d97f649-clw44 1/1 Running 0 31s 10.244.2.17 node2 <none> <none>
myapp-deploy-with-node-affinity-679d97f649-s2dv6 1/1 Running 0 31s 10.244.2.16 node2 <none>
由上可见,再根据之前打的标签,很容易推断出当前pod会优先调度在node2节点。
思考题:如果给node1节点设置标签ssd=goo,会是什么效果?
重要说明:
1、如果同时指定nodeSelector和nodeAffinity,则必须满足两个条件,才能将Pod调度到候选节点上。
2、如果在nodeAffinity类型下指定了多个nodeSelectorTerms对象【对象不能有多个,如果存在多个只有最后一个生效】,那么只有最后一个nodeSelectorTerms对象生效。
3、如果在nodeSelectorTerms下指定了多个matchExpressions列表,那么只要能满足其中一个matchExpressions,就可以将pod调度到某个节点上【针对节点硬亲和】。

4、如果在matchExpressions下有多个key列表,那么只有当所有key满足时,才能将pod调度到某个节点【针对硬亲和】。

5、在key下的values只要有一个满足条件,那么当前的key就满足条件

6、如果pod已经调度在该节点,当我们删除或修该节点的标签时,pod不会被移除。换句话说,亲和性选择只有在pod调度期间有效。
键值运算关系
节点亲和性语法支持以下运算符:In,NotIn,Exists,DoesNotExist,Gt,Lt。可以使用NotIn和DoesNotExist实现节点的反亲和行为。
运算符关系:
In:label的值在某个列表中
NotIn:label的值不在某个列表中
Gt:label的值大于某个值
Lt:label的值小于某个值
Exists:某个label存在
DostNotExists:某个label不存在
Pod 亲和性与反亲和性
Pod对象间亲和性,将一些Pod对象组织在相近的位置(同一节点、机架、区域、地区)
Pod对象间反亲和性,将一些Pod在运行位置上隔开
pod亲和性主要解决pod可以和哪些pod部署在同一个拓扑域中的问题(其中拓扑域用主机标签实现,可以是单个主机,也可以是多个主机组成的cluster、zone等等),而pod反亲和性主要是解决pod不能和哪些pod部署在同一个拓扑域中的问题,它们都是处理的pod与pod之间的关系,比如一个pod在一个节点上了,那么我这个也得在这个节点,或者你这个pod在节点上了,那么我就不想和你待在同一个节点上。
Pod亲和性/反亲和性语法支持以下运算符:In,NotIn,Exists,DoesNotExist
准备环境
由于我们这里只有一个集群,并没有区域或者机房的概念,所以我们这里直接使用主机名来作为拓扑域,把 pod 创建在同一个主机上面。
bash
[root@master1 ~]# kubectl get nodes --show-labels

通过deployment运行一个pod,或者直接运行一个pod也可以。为后续的Pod亲和性与反亲和性测验做基础。
Yaml文件
bash
[root@master1 ~]# vim pod_deplay.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-deploy
labels:
app: pod-deploy
spec:
replicas: 1
selector:
matchLabels:
app: app-pod
template:
metadata:
labels:
app: app-pod
version: v1
spec:
containers:
- name: app-pod
image: busybox:1.30
imagePullPolicy: IfNotPresent
command:
- sleep
- "3600"
创建pod
bash
[root@master1 ~]# kubectl create -f pod_deplay.yaml
deployment.apps/pod-deploy created
查看pod
bash
[root@master1 ~]# kubectl get pod -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
pod-deploy-68549d8f54-lcw54 1/1 Running 0 3m41s 10.244.2.26 node2 <none> <none> app=app-pod,pod-template-hash=68549d8f54,version=v1
当前pod在node2节点,其中pod的标签app=app-pod,version=v1,会在后面pod亲和性/反亲和性示例中使用。
Pod 硬亲和性
Pod亲和性描述一个Pod与具有某特征的现存Pod运行位置的依赖关系;即需要事先存在被依赖的Pod对象
requiredDuringSchedulingIgnoredDuringExecution #硬亲和性策略
对于硬亲和性,如果不满足则pod会一直处于Pending状态。
要运行的yaml文件
bash
[root@master1 ~]# vim pod_required_affinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-podaffinity-deploy
labels:
app: podaffinity-deploy
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp-pod
image: busybox:1.30
imagePullPolicy: IfNotPresent
command:
- sleep
- "3600"
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
# 由于是Pod亲和性/反亲和性;因此这里匹配规则写的是被依赖Pod的标签信息
matchExpressions:
#- {key: app,operator: In,values: ["app-pod"]}
- key: app
operator: In
values:
- app-pod
# 拓扑域,若多个node节点具有相同的标签信息【标签键值相同】,则表示这些node节点就在同一拓扑域
topologyKey: kubernetes.io/hostname
运行yaml文件并查看状态
bash
[root@master1 ~]# kubectl create -f pod_required_affinity.yaml
deployment.apps/pod-podaffinity-deploy created
查看pod
bash
[root@master1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-deploy-68549d8f54-lcw54 1/1 Running 0 33m 10.244.2.26 node2 <none> <none>
pod-podaffinity-deploy-b7cf97b44-55vwg 1/1 Running 0 44s 10.244.2.27 node2 <none> <none>
pod-podaffinity-deploy-b7cf97b44-rsh6x 1/1 Running 0 44s 10.244.2.28 node2 <none> <none>
我们看到这个 pod-deploy 运行在了 node2 的节点上面,所以按照上面的亲和性来说,上面我们部署的2个 pod 副本也应该运行在 node2 节点上。
Pod 软亲和性
preferredDuringSchedulingIgnoredDuringExecution #pod软亲和性策略
要运行的yaml文件
bash
[root@master1 ~]# vim pod_preferred_affinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-podaffinity-deploy1
labels:
app: podaffinity-deploy1
spec:
replicas: 2
selector:
matchLabels:
app: myapp1
template:
metadata:
labels:
app: myapp1
spec:
containers:
- name: myapp-pod1
image: busybox:1.30
imagePullPolicy: IfNotPresent
command:
- sleep
- "3600"
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
#- {key: app,operator: In,values: ["app-pod"]}
- key: app
operator: In
values:
- app-pod
topologyKey: kubernetes.io/hostname
创建pod
bash
[root@master1 ~]# kubectl create -f pod_preferred_affinity.yaml
deployment.apps/pod-podaffinity-deploy1 created
查看pod
bash
[root@master1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-deploy-68549d8f54-lcw54 1/1 Running 0 57m 10.244.2.26 node2 <none> <none>
pod-podaffinity-deploy1-677899589b-4zf8t 1/1 Running 0 8s 10.244.2.30 node2 <none> <none>
pod-podaffinity-deploy1-677899589b-5ttx5 1/1 Running 0 8s 10.244.2.29 node2 <none> <none>
由上可见,很容易推断出当前pod会优先调度在node2节点。
Pod 硬反亲和性
Pod反亲和调度用于分散同一类应用,调度至不同的区域、机架或节点等
将spec.affinity.podAffinity替换为spec.affinity.podAntiAffinity
反亲和调度也分为硬反亲和性与软反亲和性
比如一个节点上运行了某个 pod,那么我们的 pod 则希望被调度到其他节点上去,同样我们把上面的 podAffinity 直接改成 podAntiAffinity
Yaml文件
bash
[root@master1 ~]# vim pod_required_antiaffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-podantiaffinity-deploy
labels:
app: podantiaffinity-deploy
spec:
replicas: 3
selector:
matchLabels:
app: myapp1
template:
metadata:
labels:
app: myapp1
spec:
containers:
- name: myapp-pod1
image: busybox:1.30
imagePullPolicy: IfNotPresent
command:
- sleep
- "3600"
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
#- {key: app,operator: In,values: ["app-pod"]}
- key: app
operator: In
values:
- app-pod
# 拓扑域,若多个node节点具有相同的标签信息【标签键值相同】,则表示这些node节点就在同一拓扑域
topologyKey: kubernetes.io/hostname
创建pod
bash
[root@master1 ~]# kubectl create -f pod_required_antiaffinity.yaml
deployment.apps/pod-podantiaffinity-deploy created
查看pod
bash
[root@master1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-deploy-68549d8f54-k2h9f 1/1 Running 0 7m45s 10.244.2.32 node2 <none> <none>
pod-podantiaffinity-deploy-565f575c7d-qv697 1/1 Running 0 7s 10.244.1.27 node1 <none> <none>
pod-podantiaffinity-deploy-565f575c7d-rbd26 1/1 Running 0 7s 10.244.1.28 node1 <none> <none>
pod-podantiaffinity-deploy-565f575c7d-xm44n 1/1 Running 0 7s 10.244.1.29 node1 <none> <none>
污点和容忍
概述
对于nodeAffinity无论是硬策略还是软策略方式,都是调度Pod到预期节点上,而污点(Taints)恰好与之相反,如果一个节点标记为Taints,除非Pod也被标识为可以容忍污点节点,否则该Taints节点不会被调度 Pod。
总结:节点亲和性使得Pod对象被吸引到一类特定的节点 (nodeSelector 和 affinity),污点提供让节点排斥特定 Pod 对象的能力
比如用户希望把Master节点保留给Kubernetes系统组件使用,或者把一组具有特殊资源预留给某些Pod,则污点就很有用了,Pod不会再被调度到taints标记过的节点。我们使用 kubeadm 搭建的集群默认就给master节点添加了一个污点标记,所以我们看到我们平时的Pod都没有被调度到master上去:
bash
[root@master1 ~]# kubectl describe node master1
..................
Taints: node-role.kubernetes.io/master:NoSchedule
.................
我们可以使用上面的命令查看master节点的信息,其中有一条关于Taints的信息:node-role.kubernetes.io/master:NoSchedule,就表示master节点打了一个污点的标记,其中影响的参数是NoSchedule,表示Pod不会被调度到标记为taints的节点,除了NoSchedule外,还有另外两个选项:
PreferNoSchedule:NoSchedule的软策略版本,表示尽量不调度到污点节点上去。
NoExecute:该选项意味着一旦Taints生效,如该节点内正在运行的Pod没有对应容忍(tolerations)设置,则会直接被逐出。
污点taints是定义在节点上的键值型属性数据,用于让节点拒绝将 Pod 调度运行于其上,除非Pod有接纳节点污点的容忍度,容忍度tolerations[ˌtɑːləˈreɪʃn]是定义在Pod上的键值属性数据,用于配置可容忍的污点,且调度器将Pod调度至其能容忍污点的节点上或没有污点的节点上。
污点和容忍的设置
污点 taint 标记节点
污点taints标记节点的命令如下:
(1)定义污点
污点定义于 nodes.spec.taints
语法:key=value:effect
(2)effect定义排斥等级
NoSchedule,表示k8s不会将pod调度到具有该污点的node上,但仅影响调度过程,已调度上去的pod不受影响,仅对新增加的pod生效。
PreferNoSchedule,柔性约束,表示k8s尽量避免将pod调度到具有该污点的node上,如果实在是没有符合的节点,也可以调度上来。节点现存Pod不受影响
NoExecute,表示k8s不会将pod调度到具有该污点的Node上,同时会将node上已经存在的Pod驱逐出去。
(3)管理节点的污点
同一个键值数据,effect不同,也属于不同的污点
给节点添加污点:
语法:kubectl taint node <node-name> <key>=<value>:<effect>
bash
[root@master1 ~]# kubectl taint node node2 node-type=production:NoSchedule
node/node2 tainted
查看节点污点
bash
[root@master1 ~]# kubectl get nodes node2 -o go-template={{.spec.taints}}
[map[effect:NoSchedule key:node-type value:production]]
也可以describe说明中,查找Taints字段
bash
[root@master1 ~]# kubectl describe node node2
.................
Taints: node-type=production:NoSchedule
..................
删除节点污点
语法:
kubectl taint node <node-name> <key>[:<effect>]-
kubectl patch nodes <node-name> -p '{"spec":{"taints":[]}}'
删除key为node-type,effect为NoSchedule的污点
bash
[root@master1 ~]# kubectl taint node node2 node-type:NoSchedule-
node/node2 untainted
删除key为node-type的所有污点
bash
[root@master1 ~]# kubectl taint node node2 node-type-
删除所有污点
bash
[root@master1 ~]# kubectl patch nodes node2 -p '{"spec": {"taints": []}}'
pod设置容忍tolerations
容忍度定义于pods.spec.tolerations
(1)等值判断
tolerations:
- key: "key1"
operator: "Equal" #判断条件为 Equal
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600 #用于定义延迟驱逐Pod的时长
等值比较容忍度与污点在key、value、effect三者完全匹配
如果不指定operator属性,则默认值为Equal
(2)存在性判断
tolerations:
- key: "key1"
operator: "Exists" #存在性判断,只要污点键存在,就可以匹配
effect: "NoExecute"
tolerationSeconds: 3600
存在性判断容忍度与污点在key、effect完全匹配,value使用空值
(3)但不指定key时,表示容忍所有的污点key
tolerations:
- operator: "Exists"
(4)但不指定effect时,表示容忍所有的污点effect
tolerations:
- operator: "Exists"
注:一个节点可配置多个污点,一个Pod也可有多个容忍度
污点、容忍应用案例
在node2上加污点,不允许pod调度到node2节点
root@master1 \~\]# kubectl taint node node2 node-type=production:NoSchedule node/node2 tainted
编写Pod部署的yaml文件
bash
[root@master1 ~]# vim taint-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: taint
labels:
app: taint
spec:
replicas: 3
selector:
matchLabels:
app: taint
template:
metadata:
labels:
app: taint
spec:
containers:
- name: busybox
image: busybox:1.30
command:
- sleep
- "3600"
创建pod
bash
[root@master1 ~]# kubectl create -f taint-demo.yaml
deployment.apps/taint created
查看pod
bash
[root@master1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
taint-5f968d8c4f-lxnb6 1/1 Running 0 8s 10.244.1.32 node1 <none> <none>
taint-5f968d8c4f-lzhv7 1/1 Running 0 8s 10.244.1.31 node1 <none> <none>
taint-5f968d8c4f-wzmmd 1/1 Running 0 8s 10.244.1.30 node1 <none> <none>
由上面可以看到,3个pod的副本都调度到了node1节点,而node2节点没有调度pod。
删除pod
bash
[root@master1 ~]# kubectl delete -f taint-demo.yaml
deployment.apps "taint" deleted
接下来在pod上加容忍
由于node2节点被标记为了污点,所以我们这里要想Pod能够调度到该节点去,就需要增加容忍的声明:
修改taint-demo.yaml文件,添加pod容忍
bash
apiVersion: apps/v1
kind: Deployment
metadata:
name: taint
labels:
app: taint
spec:
replicas: 3
selector:
matchLabels:
app: taint
template:
metadata:
labels:
app: taint
spec:
containers:
- name: busybox
image: busybox:1.30
command:
- sleep
- "3600"
tolerations:
- key: "node-type"
operator: "Equal"
value: "production"
effect: "NoSchedule"
创建Pod
bash
[root@master1 ~]# kubectl create -f taint-demo.yaml
deployment.apps/taint created
查看pod
bash
[root@master1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
taint-5d74f4c548-crdpg 1/1 Running 0 8s 10.244.1.39 node1 <none> <none>
taint-5d74f4c548-cvqzf 1/1 Running 0 8s 10.244.2.34 node2 <none> <none>
taint-5d74f4c548-ksvtk 1/1 Running 0 8s 10.244.2.33 node2 <none> <none>
我们可以看到有Pod副本被调度到了node2节点,这就是容忍的使用方法。
注:有多个master节点存在时,为了防止资源浪费,可以加如下设置
bash
[root@master1 ~]# kubectl taint node nodename node-role.kubernetes.io/master=:PreferNoSchedule