一.Taint和Toleration
1.为什么使用taint
(1)不让pod被部署到被设置为污点的节点上。
(2)不让master节点部署业务,只部署系统组件
(3)除了指点pod外,不想让节点部署其他pod
2.为什么使用Toleration
让被设置为污点的节点能部署pod
3.污点和容忍的基本概念
Taint(污点)作用在节点上,能够是节点排斥一类特定的pod
Toleration(容忍)作用在pod上,也就是可以兼容某类污点
比如有一批GPU服务器只能部署要使用GPU的Pod。每个节点上都可以应用一个或多个Taint,这表示对于那些不能容忍这些Taint的Pod是不能部署在该服务器上的。如果Pod配置了Toleration,则表示这些Pod可以被调度到设置了Taint的节点上,当然没有设置Taint的节点也是可以部署的。
Taint(污点)和Toleration(容忍)可以作用于node和pod上,其目的是优化pod在集群间的调度,这跟节点亲和性类似,只不过它们作用的方式相反,具有taint的node和pod是互斥关系,而具有节点亲和性关系的node和pod是相吸的。另外还有可以给node节点设置label,通过给pod设置nodeSelector将pod调度到具有匹配标签的节点上。
Taint和Toleration相互配合,可以用来避免Pod被分配到不合适的节点上。每个节点上都可以应用一个或多个taint,这表示对于那些不能容忍这些taint的Pod,是不会被该节点接受的。如果将toleration应用于Pod上,则表示这些Pod可以(但不一定)被调度到具有匹配taint的节点上
使用kubeadm部署的k8s集群,应用是不会调度到master节点上的。因为kubeadm部署的k8s集群默认为master节点添加了Taints(污点)
4.污点的使用
(1)创建污点语法
ku Taint node 节点名称 键=值:effect
(2)查看节点是否为污点
ku describe node 节点名 | grep Taints
(3)移除污点,只需在添加污点的命令后加一个“-”即可
ku Taint node 节点名 键=值:effect
每个污点有一个key和value作为污点的标签,其中value可以为空,effect描述污点的作用key=value:effect
(4)effect支持的选项
- NoSchedule:表示k8s将不会将Pod调度到具有该污点的Node上,不会驱逐已存在该节点上的pod
- PreferNoSchedule:表示k8s将尽量避免将pod调度到具有该污点的node上,不会驱逐已存在该节点上的pod
- NoExecute:表示k8s将不会将pod调度到具有该污点的Node上,同时回将Node上已存在的Pod驱逐出去,若节点上设置了污点并用的是NoExecute策略,node节点上的pod会被全部驱逐,但是如果是Deployment和StatefulSet资源类型,为了维持副本数量则会在别的Node上创建新的pod
5.容忍的定义
设置了污点的Node将根据taint的effect :NoSchedule、PreferNoSchedule、NoExecute和Pod之间产生互斥的关系,Pod将在一定程度上不会被调度到Node上。 但我们可以在Pod上设置容忍(Toleration),意思是设置了容忍的Pod将可以容忍污点的存在,可以被调度到存在污点的Node上
6.示例
(1)设置污点
[root@k8s-master ~]# ku taint node node01 check=mycheck:NoSchedule
node/node01 tainted
[root@k8s-master ~]# ku taint node node02 check=mycheck:NoSchedule
node/node02 tainted
(2)创建测试模版
[root@k8s-master ~]# vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp01
labels:
app: myapp01
spec:
containers:
- name: with-node-affinity
image: nginx:1.7.9
(3)运行
[root@k8s-master ~]# ku create -f pod1.yaml
pod/myapp01 created
(4)查看pod
[root@k8s-master ~]# ku get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp01 0/1 Pending 0 22s <none> <none> <none> <none>
备注:因为设置了污点,在查看到的NODE字段上值为<none>,并每一节点对应的名称
(5)修改测试模版(为pod1添加容忍)
[root@k8s-master ~]# vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp01
labels:
app: myapp01
spec:
containers:
- name: with-node-affinity
image: nginx:1.7.9
tolerations:
- key: check
operator: Equal
value: mycheck
effect: NoSchedule
#tolerationSeconds: 60
备注:当effect为NoExecute时可以设置TolerationSeconds用于描述当Pod需要被驱逐时可以在Node上继续保留运行的时间,即60秒后该pod会被驱逐掉,默认的是一天。
在pod中定义容忍度说明
(6) 运行pod
[root@k8s-master ~]# ku create -f pod2.yaml
pod/myapp01 created
(7)查看运行结果
[root@k8s-master ~]# ku get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp01 1/1 Running 0 9s 10.244.140.92 node02 <none> <none>
(8)取消污点
[root@k8s-master ~]# ku taint node node01 check=mycheck:NoSchedule-
node/node01 untainted
[root@k8s-master ~]# ku taint node node02 check=mycheck:NoSchedule-
node/node02 untainted
[root@k8s-master ~]# ku describe node node02 | grep Taint
Taints: <none>
[root@k8s-master ~]# ku describe node node01 | grep Taint
Taints: <none>
7.多污点和多容忍配置
系统允许在同一个node上设置多个taint,也可以在pod上设置多个Toleration
Kubernetes调度器处理多个Taint和Toleration能够匹配的部分,剩下的没有忽略掉的Taint就是对Pod的效果了。下面是儿种特殊情况
- 如果剩余的Taint中存在effect=NoSchedule,则调度器不会把该pod调度到这一节点上。
- 如果剩余的Taint中没有NoSchedule的效果,但是有PreferNoSchedule效果,则调度器会尝试不会将pod指派给这个节点。
- 如果剩余Taint的效果有NoExecute的,并且这个pod已经在该节点运行,则会被驱逐;如果没有在该节点运行,也不会再被调度到该节点上。
ubecti taint nodesK8nodeke L:NoSchedule
kubectl taint nodes k8s-node1 keyl=valuel:NoExecute
kubectl taint nodes k8s-node1 key2=value2:NoSchedule
去除污点:
kubectl taint nodes k8s-node1 keyl=valuel:NoSchedule
kubectl taint nodes k8s-node1 keyl=valuel:NoExecute-
ubecttaintodes 8 key2=value2:Noschedule
二.警戒(cordon)和转移(drain)
1.警戒
(1)警戒是指将Node标记为不可调度的状态
(2)设置警戒(node01)
[root@k8s-master ~]# ku cordon node01
node/node01 cordoned
(3)查看警戒(node将会变成SchedulingDisabled)
[root@k8s-master ~]# ku get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane,master 9d v1.23.0
node01 Ready,SchedulingDisabled <none> 9d v1.23.0
node02 Ready <none> 9d v1.23.0
(4)取消警戒
[root@k8s-master ~]# ku uncordon node01
node/node01 uncordoned
[root@k8s-master ~]# ku get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane,master 9d v1.23.0
node01 Ready <none> 9d v1.23.0
node02 Ready <none> 9d v1.23.0
2.驱逐(转移)pod
kubectl drain 可以让Node节点开始释放所有pod,并且不接收新的pod进程。drain本意排水,意思是将出问题的Node下的Pod转移到其他Node下运行
[root@k8s-master ~]# ku drain node02 --ignore-daemonsets --delete-local-data --force
Flag --delete-local-data has been deprecated, This option is deprecated and will be deleted. Use --delete-emptydir-data.
node/node02 cordoned
WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: default/myapp01; ignoring DaemonSet-managed Pods: kube-system/calico-node-dzh75, kube-system/kube-proxy-52t4l
evicting pod kube-system/coredns-6d8c4cb4d-tl7gc
evicting pod kubernetes-dashboard/dashboard-metrics-scraper-7fcdff5f4c-wcddq
evicting pod kube-system/metrics-server-66bdc46d86-p5rsg
evicting pod default/myapp01
pod/myapp01 evicted
pod/dashboard-metrics-scraper-7fcdff5f4c-wcddq evicted
pod/metrics-server-66bdc46d86-p5rsg evicted
pod/coredns-6d8c4cb4d-tl7gc evicted
node/node02 drained
执行上述操作:节点会被设置为警戒状态(cordon),evict(驱逐)了Pod
备注:
--ignore-daemonsets:无视Daemonset管理下的Pod
--delete-local-data:如果有mount local volume的pod,会强制杀掉该pod
--force:强制释放不是控制器管理的pod,例如Kube-proxy
3.取消警戒(做了转移后节点会进入警戒状态)
[root@k8s-master ~]# ku uncordon node02
node/node02 uncordoned
[root@k8s-master ~]# ku get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane,master 9d v1.23.0
node01 Ready <none> 9d v1.23.0
node02 Ready <none> 9d v1.23.0
三. k8s亲和性和非亲和性
1.亲和性调度可以分成软策略和硬策略两种
- 硬策略:可以理解为必须,就是如果没有满足条件的节点的话,就不断重试直到满足条件为止。对应的配置规则为requiredDuringSchedulingIgnoredDuringExecution。
- 软策略:可以理解为尽量,就是如果没有满足调度要求的节点的话,pod就会忽略这条规则,继续完成调度的过程,即:满足条件最好,不满足也无所谓。对应的配置规则为preferredDuringSchedulingIgnoredDuringExecution。
2.亲和性的配置规则
分为Node亲和,Pod亲和,Pod反亲和:
- nodeAffinity:节点亲和性,用来控制Pod要部署在哪些节点上,以及不能部署在哪些节点上,这个是Pod与Node之间的匹配规则
- PodAffinity:Pod亲和性,这个是Pod与Pod之间匹配规则的。
- PodAntiAffinity:Pod反亲和性,与PodAffinity相反,用来指定Pod不要部署到哪些节点
备注:
节点的亲和性通过pod.spec.affinity.nodeAffinity字段定义,支持使用matchExpressions属性构建更为复杂的标签选择器。
3.Node节点亲和
节点亲和分为节点硬亲和和节点软亲和
节点硬亲和性实验
(1)设置节点标签
首先对两个node加标签,设置两个node标签分别为node01和node02。
加标签的语法:kubectl label Nodes 节点名称 标签键=标签值
[root@k8s-master ~]# ku label node node01 type=node01
[root@k8s-master ~]# ku label node node02 type=node02
(2)查看节点标签
[root@k8s-master ~]# ku get node --show-labels;
NAME STATUS ROLES AGE VERSION LABELS
k8s-master Ready control-plane,master 9d v1.23.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
node01 Ready <none> 9d v1.23.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux,type=node01
node02 Ready <none> 9d v1.23.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node02,kubernetes.io/os=linux,type=node02
(3)设置pod亲和性为type=node01
[root@k8s-master ~]# vim test01.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod01
spec:
#亲和性调度
affinity:
#节点亲和性调度
nodeAffinity:
#亲和策略:节点硬亲和
requiredDuringSchedulingIgnoredDuringExecution:
#指定亲和性
nodeSelectorTerms:
- matchExpressions:
- {key: type, operator: In, values: ["node01"]}
containers:
- name: pod01
image: nginx:1.7.9
(4)部署pod并查看其信息
[root@k8s-master ~]# ku create -f test01.yaml
pod/pod01 created
[root@k8s-master ~]# ku get pod pod01 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod01 1/1 Running 0 24s 10.244.196.151 node01 <none> <none>
也可以将{key: type, operator: In, values: ["node01"]}的node01改为node02,让其pod部署到node02节点上
[root@k8s-master ~]# ku create -f test02.yaml
pod/pod02 created
[root@k8s-master ~]# ku get pod pod02 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod02 1/1 Running 0 20s 10.244.140.93 node02 <none> <none>
节点软亲和性实验
节点软亲和性为节点选择提供了一种柔性的控制器逻辑,当条件满足时,也能够接受被编排在其他不符合条件的节点之上。同时他为每种倾向性提供了weight属性以便用于自定义优先级,范围时1-100,越大越优先。但是在节点软亲和并不适用,而是按照节点的先后顺序部署。
(1)为pod设置软亲和
[root@k8s-master ~]# vim test03.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod03
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 60
preference:
matchExpressions:
- {key: type, operator: In, values: ["node02"]}
- weight: 90
preference:
matchExpressions:
- {key: tpye, operator: In, values: ["node01"]}
containers:
- name: pod03
image: nginx:1.7.9
(2)创建pod并查看其部署情况
[root@k8s-master ~]# ku create -f test03.yaml
pod/pod03 created
[root@k8s-master ~]# ku get pod pod03 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod03 1/1 Running 0 10s 10.244.140.94 node02 <none> <none>
备注:可以发现pod被部署到了node02上,并没有被部署到权重为90的node01上,所以权重对于节点软亲和并不适用。
4.pod亲和性
出于某些需求,将一些Pod对象组织在相近的位置(同一个节点,机架,区域等)此时这些Pod对象间的关系为Pod亲和性。
Pod的亲和性调度也存在硬软/亲和性的区别,它们表示的约束意义同节点亲和性相似。
Pod硬亲和性
Pod硬亲和性调度也使用 requiredDuringSchedulingIgnoredDuringExecution 属性进行定义
首先创建两个基础Pod,并对它打标签,分别部署到node01和node02上
(1)部署第一个基础Pod(标签pod04,节点node01)
[root@k8s-master ~]# vim test04.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod04
labels:
app: pod04
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: type, operator: In, values: ["node01"]}
containers:
- name: pod04
image: nginx:1.7.9
[root@k8s-master ~]# ku create -f test04.yaml
pod/pod04 created
[root@k8s-master ~]# ku get pod pod04 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod04 1/1 Running 0 17s 10.244.196.152 node01 <none> <none>
(2)部署第二个基础Pod (标签pod05,节点node02)
[root@k8s-master ~]# vim test05.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod05
labels:
app: pod05
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: type, operator: In, values: ["node02"]}
containers:
- name: pod05
image: nginx:1.7.9
[root@k8s-master ~]# ku create -f test05.yaml
pod/pod05 created
[root@k8s-master ~]# ku get pod pod05 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod05 1/1 Running 0 5s 10.244.140.95 node02 <none> <none>
(3)创建亲和Pod05的Pod
[root@k8s-master ~]# vim test06.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod06
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["pod05"]}
topologyKey: kubernetes.io/hostname
containers:
- name: pod06
image: nginx:1.7.9
注意:
matchExpressions的values值为Pod的标签。是哪个Pod的标签,就亲和到那个Pod所在的弄的节点
(4)部署此pod (并查看所在节点)
[root@k8s-master ~]# ku create -f test06.yaml
pod/pod06 created
[root@k8s-master ~]# ku get pod pod06 pod05 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod06 1/1 Running 0 93s 10.244.140.96 node02 <none> <none>
pod05 1/1 Running 0 7m35s 10.244.140.95 node02 <none> <none>
此时pod05和pod06在同一个节点
Pod软亲和
Pod软亲和和node软亲和使用方法类似
(1)编写pod7的pod
[root@k8s-master ~]# vim test07.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod07
spec:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 20
podAffinityTerm:
labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["pod05"]}
topologyKey: kubernetes.io/hostname
- weight: 80
podAffinityTerm:
labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["pod04"]}
topologyKey: kubernetes.io/hostname
containers:
- name: pod07
image: nginx:1.7.9
注释:
values:["pod05"]是pod5的pod的标签
values:["pod04"]是pod04的pod的标签
正则匹配了pod的标签“pod04”,带有pod4标签的pod是pod04,该pod在node1上,于是pod07的pod也调度到了node01上。
注意:
node软亲和中的权重值不影响pod的调度,谁在前面,就亲和谁。
pod软亲和中的权重值是会影响调度到的节点的,pod软亲和中谁的权重高就调度到谁那里
(2)创建并查看所在节点
[root@k8s-master ~]# ku create -f test07.yaml
pod/pod07 created
[root@k8s-master ~]# ku get pod pod07 pod05 pod04 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod07 1/1 Running 0 19s 10.244.196.153 node01 <none> <none>
pod05 1/1 Running 0 15m 10.244.140.95 node02 <none> <none>
pod04 1/1 Running 0 16m 10.244.196.152 node01 <none> <none>
5.Pod反亲和
Pod反亲和就是不亲和该Pod所在的节点
(1)编写反亲和文件(反亲和node05)
[root@k8s-master ~]# vim test09.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod09
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["pod05"]}
topologyKey: kubernetes.io/hostname
containers:
- name: test09
image: nginx:1.7.9
(2)创建反亲和并查看
[root@k8s-master ~]# ku create -f test09.yaml
pod/pod09 created
[root@k8s-master ~]# ku get pod pod09 pod05 pod04 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod09 1/1 Running 0 19s 10.244.196.154 node01 <none> <none>
pod05 1/1 Running 0 22m 10.244.140.95 node02 <none> <none>
pod04 1/1 Running 0 23m 10.244.196.152 node01 <none> <none>