一般情况下我们部署的
Pod
是通过集群自动调度选择某个节点的,默认情况下调度器考虑的是资源足够,并且负载尽量平均,但是有的时候我们需要能够更加细粒度的去控制 POD 的调度。这就需要用到 Kubernetes 里面的一个概念:亲和性,亲和性主要分为两类:nodeAffinity
和podAffinity
。
一、概述
Kubernetes 支持限制 Pod 在指定的 Node 上运行,或者指定更倾向于在某些特定 Node 上运行。
有几种方式可以实现这个功能:
NodeName
: 最简单的节点选择方式,直接指定节点,跳过调度器。
NodeSelector
: 早期的简单控制方式,直接通过键—值对将 Pod 调度到具有特定 label 的 Node 上。
NodeAffinity
: NodeSelector
的升级版,支持更丰富的配置规则,使用更灵活。(NodeSelector 将被淘汰)
PodAffinity
: 根据已在节点上运行的 Pod 标签来约束 Pod 可以调度到哪些节点,而不是根据 node label。
二、指定调度节点
1. NodeName
Pod.spec.nodeName
将 Pod
直接调度到指定的 Node
节点上,会跳过 Scheduler
的调度策略,该规则是强制匹配。如果选择的节点不存在则 Pod
处于 Pending
状态。
apiVersion: v1
kind: Pod
metadata:
name: nginx-nodename
spec:
containers:
- name: nginx
image: nginx:1.7.9
nodeName: loc-node36
2. NodeSelector
通过 kubernetes
的 label-selector
机制选择节点,由调度器策略匹配 label
,而后调度 Pod
到目标节点,该规则属于强制约束。如果选择的节点不存在则 Pod
处于 Pending
状态。
设置标签到 node 上:
# kubectl label nodes loc-node36 zone=guangzhou
示例如下:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeSelector:
zone: guangzhou
三、亲和性
1. 节点亲和性
pod.spec.affinity.nodeAffinity
-
requiredDuringSchedulingIgnoredDuringExecution # 硬策略
硬策略是必须(不)落在指定的节点上,如果不符合条件,则一直处于Pending状态
-
preferredDuringSchedulingIgnoredDuringExecution # 软策略
软策略是偏向于,更想(不)落在某个节点上,但如果实在没有,落在其他节点也可以
软硬结合达到一个更为准确的 node
选择,以下配置意思为此 Pod
必须不存在 loc-node36
节点中,其他的节点都可以,但最好落在 label
中 app
的值为 loc-node37
的节点中。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-node-affinity
labels:
app: nginx-node-affinity
spec:
replicas: 2
selector:
matchLabels:
app: node-affinity # 这个lable需要对应下面metadata lables
template:
metadata:
labels:
app: node-affinity
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
name: nginx-web
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
nodeSelectorTerms: # 在nodeAffinity下面,如果是required,则需要使用nodeSelectorTerms #多个nodeSelectorTerms是或的关系,满足一个即可
- matchExpressions: # 多个matchExpressions是与的关系,全部满足才会调度
- key: kubernetes.io/hostname
operator: NotIn
values:
- loc-node36
preferredDuringSchedulingIgnoredDuringExecution: # 软策略
- weight: 1
preference:
matchExpressions:
- key: app
operator: In
values:
- loc-node37
# 节点存在默认的 label
# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
loc-master35 Ready master 5d7h v1.18.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=loc-master35,kubernetes.io/os=linux,node-role.kubernetes.io/master=
loc-node36 Ready <none> 5d5h v1.18.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=loc-node36,kubernetes.io/os=linux
loc-node37 Ready <none> 5d4h v1.18.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=loc-node37,kubernetes.io/os=linux
# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-node-affinity-7fcff98c5c-8whzf 1/1 Running 0 7h58m 172.16.100.209 loc-node37 <none> <none>
nginx-node-affinity-7fcff98c5c-nnwgr 1/1 Running 0 7h58m 172.16.100.210 loc-node37 <none> <none>
键值运算关系
In
:label 的值在某个列表中NotIn
:label 的值不在某个列表中Gt
:label 的值小于某个值Exists
:某个 label 存在DoesNotExist
:某个 label 不存在
2. Pod 亲和性
上面两种方式都是让 Pod
去选择节点的,有的时候我们也希望能够根据 Pod
之间的关系进行调度,Kubernetes 在1.4版本引入的 podAffinity
概念就可以实现我们这个需求。
和 nodeAffinity
类似,podAffinity
也有如下两种两种调度策略,唯一不同的是如果使用互斥性,我们需要使用 podAntiAffinity
字段。
pod.spec.affinity.podAffinity/podAntiAffinity
- requiredDuringSchedulingIgnoredDuringExecution # 硬策略
- preferredDuringSchedulingIgnoredDuringExecution # 软策略
以下策略表示 pod-affinity-pod
和 label
中 app
值为 nginx
在同一个拓扑域部署,最好不和 label
中 app
值为 nginx2
的 Pod
不在同一个拓扑域下。
如何理解拓扑域? 当前是以 kubernetes.io/hostname
基本上表示一个主机是一个拓扑域,我们也可以在主机上打上新的标签 kubernetes.io/zone = gz
, 那 Pod
可以随意部署在该拓扑域下的一台 Node
上,并不需要与匹配的一定要在同一个 Node
。
apiVersion: v1
kind: Pod
metadata:
name: pod-affinity-pod
labels:
app: nginx-affinity-pod
spec:
containers:
- name: pod-affinity-pod
image: nginx:1.7.9
imagePullPolicy: IfNotPresent
ports:
- name: web
containerPort: 80
affinity:
podAffinity: # 在同一域下
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app # 标签key
operator: In
values:
- nginx # 标签value
topologyKey: kubernetes.io/hostname # 域的标准为node节点的名称
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx2
topologyKey: kubernetes.io/hostname
# kubectl get pods --show-labels -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
nginx 1/1 Running 0 5m30s 172.16.100.235 loc-node37 <none> <none> app=nginx
pod-affinity-pod 1/1 Running 0 5m26s 172.16.100.236 loc-node37 <none> <none> app=nginx-affinity-pod
亲和性/反亲和性调度策略如下:
调度策略 | 匹配标签 | 操作符 | 拓扑域支持 | 调度目标 |
---|---|---|---|---|
nodeAffinity | 主机 | In,NotIn,Exists,DoesNotExists,Gt,Lt | 否 | 指定主机 |
podAffinity | Pod | In,NotIn,Exists,DoesNotExists | 是 | pod与指定pod在一拓扑域 |
podAnitAffinity | Pod | In,NotIn,Exists,DoesNotExists | 是 | pod与指定pod不在一拓扑域 |
四、污点
节点亲和性,是 Pod
的一种属性(偏好或硬性要求),它使 Pod
被吸引到一类特定的节点。Trint
则相反,它使节点能够排斥一类特定的 Pod
。
Taint
和 Toleration
相互配合,可以用来避免 Pod
被分配到不合适的节点上。每个节点上都可以应用一个或多个 Taint
, 这表示对于那些不能容忍这些 Taint
的 Pod
,是不会被节点接受的。如果 Toleration
应用于 Pod
上,则表示这些 Pod
可以(但不要求)被调度到具有匹配 Taint
的节点上。
1. 污点组成
每个污点的组成:
key=value:effect
每个污点有一个 key 和 value 作为污点的标签,其中 vlaue 可以为空,effect 描述污点的作用。当前 taint effect
支持如下三个选项:
Noscedule
: 表示 k8s 将不会将Pod
调度到具有该污点的Node
上PreferNoSchedule
: 表示 k8s 将尽量避免将Pod
调度到具有该污点的Node
上NoExecute
: 表示 k8s 将不会将Pod
调度到具有该污点的Node
上,同时会将Node
上已经存在的Pod
驱逐出去
2. 污点设置
使用 kubectl taint
命令可以给某个 Node
节点设置污点,Node
将设置上污点之后就和 Pod
之间存在了一种相斥的关系,可以让 Node
拒绝 Pod
的调度执行,甚至将 Node
已经存在的 Pod
驱逐出去。
# 设置污点
kubectl taint nodes loc-node36 key1=value:Noscedule
# 节点说明中,查找 Taints 字段
kubectl describe node loc-master35
# 去除污点
kubectl taint nodes loc-node36 key1:Noscedule-
五、容忍
设置了污点的 Node
将要根据 taint
的 effect: Noscedule、PreferNoSchedule
、NoExecute
和 Pod
之间产生互斥的关系,Pod
将在一定程度上不会被调度到 Node
上,但我们可以在 Pod
上设置容忍(Toleration),意思是设置了容忍的 Pod
将可以容忍污点的存在,可以被调度到存在污点的 Node
上。
pod.spec.tolerations
tolerations:
- key: "key1"
operator: "Equal"
value: "Value"
effect: "NoSchedule"
tolerationSeconds: 3600
- key: "key1"
operator: "Equal"
value: "Value"
effect: "NoExecute"
- key: "key2"
operator: "Exists"
effect: "NoSchedule"
- 其中
key
,value
,effect
要与Node
上设置的taint
保持一致 operator
的值为Exists
将会忽略value
值tolerationsSeconds
用于描述当Pod
需要被驱逐时可以在Pod
上继续保留运行的时间
1、当不指定 key 值时,表示容忍所有的污点 key:
tolerations:
- operator: "Exists"
2、当不指定 effect 值试,表示容忍所有的污点作用
tolerations:
- key: "key"
operator: "Exists"
3、当有多个 Master 存在时,为防止资源浪费,可以如下设置
kubectl taint nodes master-nodename node-role.kubernetes.io/master:PreferNoSchedule
Reference:
https://segmentfault.com/a/1190000018446833