在前面的两种方式中,都是由pod去选择的,节点被动选择运行。而污点调度方式就给了节点的选择权。让节点可以选择让那些pod运行在节点上。总的来说,污点就是定义在节点上的键值属性数据。
- 此前,我们知道,键值属性有三类,第一类叫标签,第二类叫注解,第三类便是污点。污点用在节点之上,而前两类所有资源对象都可以使用。
- pod亲和性和node亲和性都是pod的属性,而污点是节点的属性
污点也是一种键值属性,主要用来让节点拒绝那些不能容忍的pod,因此需要在pod对象上定义容忍度。而容忍度也是pod对象上的第三类键值数据,并且是一个列表。
kubernetes分别有一个预选策略PodToleratesNodeTaints和优选函数taint_toleration,分别完成基于所谓的污点和容忍度的调用逻辑,并且作为选择中标准的一种来进行定义。
污点定义在node.spec.taints:
- effect
定义当pod不能容忍这个污点时, 采取的行为是什么。这种排斥的效果有三种,分别是:
Noschedule: 仅仅影响调度过程,对现存的pod对象不产生影响。如果不能容忍,就不进行调度。
NoExecute: 不仅影响调度,也影响现存pod对象; 如果不能容忍的pod将会被驱逐。
PreferNoschedule:不能容忍就不能调度,但是如果没有其他地方运行,那也可以。
- key
- timeAdded
- value 可以为空
在pod对象上定义容忍度的时候,还支持两种操作,等值比较,存在性判断
等值比较
容忍度与污点必须在key,value和effect上完全匹配,
存在性判断
表示二者的key,timeAdded必须匹配,value 可以为空
另外一个节点可以配置多个污点,一个pod也可以有多个容忍度,只不过两者匹配的时候需要遵循以下逻辑:
1,检查每个有着容忍匹配容忍度的污点,不能匹配到的污点如果存在,如果有一个使用Noschedule标识,pod就无法调度
- 我们在pod上定义三个容忍度,在节点之上定义两个污点。如果容忍度中只包含了容忍了一个污点,那将只会匹配一个污点,这样的情况是存在的!所以我们要检查这种匹配度有多高!事实上这个pod不一定会运行在这个节点之上的。如下图:
逐一检查容忍度和对方的污点相匹配,节点上的每一个污点都需要被容忍,如果存在一个不被容忍,就需要看这个污点的条件。如果污点是effect.PreferNoschedule,那就可以运行的。如果是Noschedule就不能调度成功。如上图。
如果至少有一个污点不匹配,如果是NoExecute,且节点已经运行有此pod,此pod将被驱逐。
总结:如果一个节点定义了污点,一个pod能否调度上来。首先检查能够被匹配到的污点和容忍度,检查完能够被容忍的污点后,检查不能够被容忍度容忍的污点,检查不能够被容忍度容忍污点,就检查effect 排斥的三种行为,如果是PreferNoschedule就可以继续调度,如果是Noschedule,且pod尚未调度到节点,就不能被调度到节点,Noschedule调度之前已经运行在节点的的pod仍然能够运行。如果是NoExecute,且pod尚未调度到节点,就不能被调度到节点,而且此前调度过来的已经运行的pod,如果被修改了污点,就意味着运行的这个pod也会被驱逐。
在master节点上,就是有污点的.NoSchedule.如果pod不能够容忍这个污点,pod就不能够调度到master节点上
[root@linuxea schedule]# kubectl describe node linuxea.master-1.com|grep Taints
Taints: node-role.kubernetes.io/master:NoSchedule
并且master这个污点在启动的时候就被打上去。如果pod不能够容忍这个污点,就不会调度到master这个节点上,而一些其他的kubernetes组件肯定是容忍这个污点的。否则将调度不到master上,像api server就是NoExecute
[root@linuxea schedule]# kubectl describe pods kube-apiserver-linuxea.master-1.com -n kube-system|grep Tolerations
Tolerations: :NoExecute
另外还有flannel,flannel就更清楚地标记容忍度,包含master 污点node-role.kubernetes.io/master
,并且是NoSchedule。这些信息就影响这调度
[root@linuxea schedule]# kubectl describe pods kube-flannel-ds-amd64-mnrwp -n kube-system
Node-Selectors: beta.kubernetes.io/arch=amd64
Tolerations: node-role.kubernetes.io/master:NoSchedule
node.kubernetes.io/disk-pressure:NoSchedule
node.kubernetes.io/memory-pressure:NoSchedule
node.kubernetes.io/not-ready:NoExecute
node.kubernetes.io/unreachable:NoExecute
Events: <none>
管理节点污点
NoSchedule
此刻有三个节点,将node1标记为线上,容忍行为效果是NoSchedule。pod不运行在node1,node1只会运行生产pod
[root@linuxea schedule]# kubectl taint node linuxea.node-1.com node_type=produce:NoSchedule
node/linuxea.node-1.com tainted
- 随意apply几个pod,不设置容忍度
apiVersion: apps/v1
kind: Deployment
metadata:
name: dpment-linuxea
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: linuxea_app
version: v0.1.32
template:
metadata:
labels:
app: linuxea_app
version: v0.1.32
spec:
containers:
- name: nginx-a
image: marksugar/nginx:1.14.b
ports:
- name: http
containerPort: 80
apply
[root@linuxea schedule]# kubectl apply -f demo.yaml
deployment.apps/dpment-linuxea created
在查看,pod运行在node2和node3,跳过了node1
[root@linuxea schedule]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
dpment-linuxea-648d599b5f-j68cb 1/1 Running 0 5s 172.16.5.20 linuxea.node-3.com <none>
dpment-linuxea-648d599b5f-sh2tn 1/1 Running 0 5s 172.16.4.26 linuxea.node-2.com <none>
dpment-linuxea-648d599b5f-vrjtl 1/1 Running 0 5s 172.16.5.21 linuxea.node-3.com <none>
甚至,我们可以删掉在apply一次
[root@linuxea schedule]# kubectl delete -f demo.yaml
deployment.apps "dpment-linuxea" deleted
这些pod没有设置node上的容忍度,仍然不会调度到node1,说明污点是有效的。
[root@linuxea schedule]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
dpment-linuxea-648d599b5f-hc9n6 1/1 Running 0 5s 172.16.4.27 linuxea.node-2.com <none>
dpment-linuxea-648d599b5f-kjsgd 1/1 Running 0 5s 172.16.5.22 linuxea.node-3.com <none>
dpment-linuxea-648d599b5f-wp4pz 1/1 Running 0 5s 172.16.4.28 linuxea.node-2.com <none>
NoExecute
此刻,尝试NoExecute。现在node2节点上运行了一个pod,我们在node2上在打一个污点node_type=dev:NoExecute
,并且是容忍的行为是NoExecute,也就是说,如果node2上的pod不是污点dev的,并且此前运行不是dev的pod,也会被驱逐
[root@linuxea schedule]# kubectl taint node linuxea.node-2.com node_type=dev:NoExecute
node/linuxea.node-2.com tainted
node2上的pod没有容忍这个污点,被驱逐了,但是还有node3没有任何污点,所以运行在node3之上
[root@linuxea schedule]# kubectl get pods -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
dpment-linuxea-648d599b5f-87jhp 1/1 Running 0 12s 172.16.5.23 linuxea.node-3.com <none>
dpment-linuxea-648d599b5f-fgwhd 1/1 Running 0 12s 172.16.5.25 linuxea.node-3.com <none>
dpment-linuxea-648d599b5f-hc9n6 1/1 Terminating 0 31m 172.16.4.27 linuxea.node-2.com <none>
dpment-linuxea-648d599b5f-kjsgd 1/1 Running 0 31m 172.16.5.22 linuxea.node-3.com <none>
dpment-linuxea-648d599b5f-wp4pz 1/1 Terminating 0 31m 172.16.4.28 linuxea.node-2.com <none>
dpment-linuxea-648d599b5f-hc9n6 0/1 Terminating 0 31m 172.16.4.27 linuxea.node-2.com <none>
dpment-linuxea-648d599b5f-hc9n6 0/1 Terminating 0 31m 172.16.4.27 linuxea.node-2.com <none>
dpment-linuxea-648d599b5f-hc9n6 0/1 Terminating 0 31m 172.16.4.27 linuxea.node-2.com <none>
dpment-linuxea-648d599b5f-hc9n6 0/1 Terminating 0 31m 172.16.4.27 linuxea.node-2.com <none>
dpment-linuxea-648d599b5f-wp4pz 0/1 Terminating 0 31m <none> linuxea.node-2.com <none>
dpment-linuxea-648d599b5f-wp4pz 0/1 Terminating 0 31m <none> linuxea.node-2.com <none>
dpment-linuxea-648d599b5f-wp4pz 0/1 Terminating 0 31m <none> linuxea.node-2.com <none>
而后都运行在node3之上,如果node3也有污点,且pod不能容忍,那就会pending.
[root@linuxea schedule]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
dpment-linuxea-648d599b5f-87jhp 1/1 Running 0 1m 172.16.5.23 linuxea.node-3.com <none>
dpment-linuxea-648d599b5f-fgwhd 1/1 Running 0 1m 172.16.5.25 linuxea.node-3.com <none>
dpment-linuxea-648d599b5f-kjsgd 1/1 Running 0 32m 172.16.5.22 linuxea.node-3.com <none>
管理Pod容忍度
在pods.spec.tolerations字段中
- tolerationSeconds 表示,如果被驱逐,驱逐前等待时间。默认0秒 ,立即被驱逐
- key 列表
-
operator 操作符
Exists : 判断污点存在与否,存在就可以,且不管是什么值都匹配
Equal: 容忍度必须能够精确容忍对方的污点值
在上述中,使用Exists ,只要是node_type在就容忍,如果是Equal,只要是node_type且要么容忍dev污点值,元要么produce的污点值,需要明确指定
- 我们先将linuxea.node-3.com添加污点
node_type=Pre-production:NoSchedule
,容忍行为NoSchedule
[root@linuxea schedule]# kubectl taint node linuxea.node-3.com node_type=Pre-production:NoSchedule
node/linuxea.node-3.com tainted
此刻在apply 刚才没有容忍度的pod就会pending
[root@linuxea schedule]# kubectl get pods
NAME READY STATUS RESTARTS AGE
dpment-linuxea-648d599b5f-cxfv6 0/1 Pending 0 3s
dpment-linuxea-648d599b5f-ghphv 0/1 Pending 0 3s
dpment-linuxea-648d599b5f-rvpw2 0/1 Pending 0 3s
NoExecute
此刻使用NoExecute也会pending.因为污点和容忍度不完全等。如下:
- 首先操作符为Equal,精确容忍,而node1的污点node_type:produce的容忍行为是NoSchedule,而在文件中定义的是容忍行为是NoExecute,唯一的键值匹配produce也不符合NoExecute
- tolerationSeconds表示,一旦容忍将在30秒后进行驱逐
综上所述,pod没有容忍任何node的污点,所以pending
tolerations:
- key: "node_type"
operator: "Equal"
value: "produce"
effect: "NoExecute"
tolerationSeconds: 30
完整yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dpment-linuxea
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: linuxea_app
version: v0.1.32
template:
metadata:
labels:
app: linuxea_app
version: v0.1.32
spec:
containers:
- name: nginx-a
image: marksugar/nginx:1.14.b
ports:
- name: http
containerPort: 80
tolerations:
- key: "node_type"
operator: "Equal"
value: "produce"
effect: "NoExecute"
tolerationSeconds: 30
NoSchedule
使用NoSchedule就不需要指定tolerationSeconds的驱逐时间,因为NoSchedule只会拒绝不能容忍的,对于在上一次已经运行的pod不驱逐
- 操作符精确匹配具有污点为node_type为produce的节点
- 而node_type为produce污点的节点是node1
精确满足容忍度的节点是node1,这三个pod将会调度到node1上。如下:
tolerations:
- key: "node_type"
operator: "Equal"
value: "produce"
effect: "NoSchedule"
# tolerationSeconds: 10
yaml如下
[root@linuxea schedule]# cat demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dpment-linuxea
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: linuxea_app
version: v0.1.32
template:
metadata:
labels:
app: linuxea_app
version: v0.1.32
spec:
containers:
- name: nginx-a
image: marksugar/nginx:1.14.b
ports:
- name: http
containerPort: 80
tolerations:
- key: "node_type"
operator: "Equal"
value: "produce"
effect: "NoSchedule"
# tolerationSeconds: 10
apply
[root@linuxea schedule]# kubectl apply -f demo.yaml
deployment.apps/dpment-linuxea configured
而后就调度到具有kye是node_type:produce,行为是NoSchedule污点的node1之上,因为yaml文件中容忍了node1的污点
[root@linuxea schedule]# kubectl get pods -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
dpment-linuxea-df4b6f749-5jlcb 1/1 Running 0 5s 172.16.3.4 linuxea.node-1.com <none>
dpment-linuxea-df4b6f749-rzndk 1/1 Running 0 4s 172.16.3.5 linuxea.node-1.com <none>
dpment-linuxea-df4b6f749-wwpck 1/1 Running 0 3s 172.16.3.6 linuxea.node-1.com <none>
Exists
我们在改改,修改成污点只要键是node_type的就容忍,也就是只要键是node_type的污点都调度到上面,将操作符改成Exists,我们知道Exists,只要是匹配到的就可以被容忍,如果没有其他的条件的话
上述中,node污点分别是:
linuxea.node-1.com node_type=produce:NoSchedule
linuxea.node-2.com node_type=dev:NoExecute
linuxea.node-3.com node_type=Pre-production:NoSchedule
yaml修改后如下
tolerations:
- key: "node_type"
operator: "Exists"
value: ""
effect: "NoSchedule"
注意:尽管污点的键值在三个节点都是node_type。但是node1和node3的行为效果是NoSchedule,而node2行为效果是NoExecute,因为行为效果不同,所以也只会调度在node1和node3的污点节点上
yaml完整如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: dpment-linuxea
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: linuxea_app
version: v0.1.32
template:
metadata:
labels:
app: linuxea_app
version: v0.1.32
spec:
containers:
- name: nginx-a
image: marksugar/nginx:1.14.b
ports:
- name: http
containerPort: 80
tolerations:
- key: "node_type"
operator: "Exists"
value: ""
effect: "NoSchedule"
apply
[root@linuxea schedule]# kubectl apply -f demo.yaml
deployment.apps/dpment-linuxea configured
apply后会进行重新调度,调度后到了node1和node3之上
[root@linuxea schedule]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
dpment-linuxea-798ff6bc87-8kpw2 1/1 Running 0 12s 172.16.5.33 linuxea.node-3.com <none>
dpment-linuxea-798ff6bc87-9fgn4 1/1 Running 0 14s 172.16.3.7 linuxea.node-1.com <none>
dpment-linuxea-798ff6bc87-fgpcr 1/1 Running 0 15s 172.16.5.32 linuxea.node-3.com <none>
dpment-linuxea-df4b6f749-5jlcb 1/1 Terminating 0 19m 172.16.3.4 linuxea.node-1.com <none>
dpment-linuxea-df4b6f749-rzndk 1/1 Terminating 0 19m 172.16.3.5 linuxea.node-1.com <none>
dpment-linuxea-df4b6f749-wwpck 1/1 Terminating 0 19m 172.16.3.6 linuxea.node-1.com <none>
那如果要调度到node2的污点上,改成NoExecute即可
但是这样一来,就只有node2有污点的行为效果是NoExecute,而node1和node3没有,就只能调度到Node2了。
tolerations:
- key: "node_type"
operator: "Exists"
value: ""
effect: "NoExecute"
而后apply
[root@linuxea schedule]# kubectl apply -f demo.yaml
deployment.apps/dpment-linuxea configured
就都调度到node2上了。
[root@linuxea schedule]# kubectl get pods -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
dpment-linuxea-798ff6bc87-8kpw2 1/1 Terminating 0 14m 172.16.5.33 linuxea.node-3.com <none>
dpment-linuxea-798ff6bc87-9fgn4 1/1 Terminating 0 14m 172.16.3.7 linuxea.node-1.com <none>
dpment-linuxea-798ff6bc87-fgpcr 1/1 Terminating 0 14m 172.16.5.32 linuxea.node-3.com <none>
dpment-linuxea-7b54d565c7-2md6h 1/1 Running 0 2s 172.16.4.31 linuxea.node-2.com <none>
dpment-linuxea-7b54d565c7-5pmth 1/1 Running 0 3s 172.16.4.30 linuxea.node-2.com <none>
dpment-linuxea-7b54d565c7-v6bdq 1/1 Running 0 5s 172.16.4.29 linuxea.node-2.com <none>
那如果我想在三个节点都想被容忍,我们在修改下,将effect制空,如下:
tolerations:
- key: "node_type"
operator: "Exists"
value: ""
effect: ""
这样一来,value值为空,effect的容忍效果也为空,那就只有键生效,相同为node_type的键有node1,node2,node3三个node都符合。就会调度到三个节点上
[root@linuxea schedule]# kubectl apply -f demo.yaml
deployment.apps/dpment-linuxea configured
[root@linuxea schedule]# kubectl get pods -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
dpment-linuxea-7748786749-4s2qv 1/1 Running 0 5s 172.16.4.32 linuxea.node-2.com <none>
dpment-linuxea-7748786749-6llcz 1/1 Running 0 6s 172.16.5.34 linuxea.node-3.com <none>
dpment-linuxea-7748786749-dv4nf 1/1 Running 0 4s 172.16.3.8 linuxea.node-1.com <none>