一. 基础解释
- 假设当前使用的是k8s集群,有多个节点, 在部署pod时底层会通过scheduler调度器计算调度,选择其中一个节点进行部署, 默认情况下这个计算调度过程是k8s决定的, 也可以通过设置一定的规则,根据规则选择指定的节点,例如部署pod时通过"spec.nodeName"属性设置选择指定节点部署
- 提出了一下调度设策略
- 通过"spec.nodeName"属性设置选择指定节点
- 通过nodeSelector选择器,根据节点标签选中
- Affinity: 亲和
- anti-affinity: 反亲和
nodeSelector
- nodeSelector是PodSpec的一个字段,包含键值对的映射,为了使pod在某个节点上运行,该节点标签中必须包含这里的键值对
实际可以理解为给k8s节点设置对应的标签,在部署pod时设置节点选择器,通过节点选择器选中指定节点安装部署
- nodeSelector 是硬亲和的一种
NodeAffinity 亲和性
- NodeAffinity意为Node节点亲和性的调度策略,是用于替换NodeSelector的全新调度策略,分为:硬亲和性required和软亲和性preferred两种
1. node硬亲和性
- 例如nodeSelector节点选择器,可以设置Pod对象根据标签匹配的方式将Pod对象强制调度至某一类特定的节点之上 ,不过nodeSelector节点选择器只能设置简单的等值关系,而nodeAffinity中支持使用 matchExpressions属性构建更为复杂的标签选择机制
- 可以通过requiredDuringSchedulinglgnoredDuringExecution属性设置一个对象列表,用于定义节点硬亲和性,它可由一到多个nodeSelectorTerm定义的对象组成,彼此间为“逻辑或”的关系,进行匹配度检查时,在多个nodeSelectorTerm之间只要满足其中之一 即可
- 硬亲和支持:
- nodeAffinity: 节点亲和设置
- podAffinity: pod亲和设置
- podAntiAffinity: pod反亲和设置
- 注意点: 在Pod资源基于节点亲和性规则调度至某节点之后,节点标签发生了改变而不再符合此节点亲和性规则时 ,调度器不会将Pod对象从此节点上移出,因为,它仅对新建的Pod对象生效。
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
labels:
app: web
spec:
replicas: 6
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx-deploy
image: nginx:latest
imagePullPolicy: IfNotPresent
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
nodeSelectorTerms:
- matchExpressions:
- key: app
operator: In ##表示键与一组值的关系,有效的运算符有:In、NotIn、Exist、DoesNotExsit。GT和LT
values:
- web
#podAffinity: #指定亲和的pod(与选中的亲和pod安装到同一个节点上)
#podAntiAffinity: #反亲和pod(与反亲和pod不能安装到同一节点上)
2. node软亲和性
- 节点软亲和性为节点选择机制提供了一种柔性控制逻辑,被调度的Pod对象不再是“必须”而是“应该”放置于某些特定节点之上,当条件不满足时它也能够接受被编排于其他不符合条件的节点之上。另外,它还为每种倾向性提供了weight属性以便用户定义其优先级,取值范围是1 ~ 100,数字越大优先级越高
- 通过preferredDuringSchedulingIgnoredDuringExecution属性设置软亲和,
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
labels:
app: web
spec:
replicas: 6
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx-deploy
image: nginx:latest
imagePullPolicy: IfNotPresent
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution: #设置软亲和
- weight: 60 ###设置app=web的权重为60
preference: #指定亲和的条件
matchExpressions:
- key: app
operator: In
values:
- web
preference: #指定亲和的条件
matchExpressions:
- key: disk #表示磁盘,综合起来看就是磁盘大于40的
values: ["40"]
operator: Gt #大于
- weight: 40 ###设置app=server的权重为40
preference:
matchExpressions:
- key: app
operator: In
values:
- server
3. 拓扑键
- 在设置亲和与反亲和时存在一个topologyKey拓扑键,用来划分逻辑区域,
- pod亲和性调度需要各个相关的pod对象运行于"同一位置", 而反亲和性调度则要求他们不能运行于"同一位置",这里指定“同一位置” 就是通过 topologyKey 来定义的,topologyKey 对应的值是 node 上的一个标签名称,是指一个范围的概念,比如一个 Node、一个机柜、一个机房或者是一个地区(如杭州、上海)等,实际上对应的还是 Node 上的标签, 比如各别节点zone=A标签,各别节点有zone=B标签,pod affinity topologyKey定义为zone,那么调度pod的时候就会围绕着A拓扑,B拓扑来调度,而相同拓扑下的node就为“同一位置”
- 执行命令给"k8s-node1"节点设置zone标签为sh-1
kubectl label node k8s-node1 zone=sh-1
- 如果基于各个节点"kubernetes.io/hostname"标签作为评判标准,那么“同一位置”意味着同一节点,不同节点既为不同位置
也就是拓扑键为"kubernetes.io/hostname"作为标准时,如果在亲和策略中,那么会加入到同一个节点上,如果在反亲和策略中,那么就不能在同一节点上
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity: #pod亲和策略
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: failure-domain.beta.kubernetes.io/zone #设置亲和的拓扑键
podAntiAffinity: #pod反亲和策略
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: kubernetes.io/hostname #反亲和策略拓扑键
containers:
- name: with-pod-affinity
image: k8s.gcr.io/pause:2.0
- 注意事项,原则上topologyKey 可以是任何合法的标签 Key, 出于性能和安全原因,对 topologyKey 有一些限制:
- 对于亲和性和 requiredDuringSchedulingIgnoredDuringExecution 的 Pod 反亲和性,topologyKey 不能为空。
- 对于 requiredDuringSchedulingIgnoredDuringExecution 的 Pod 反亲和性,引入 LimitPodHardAntiAffinityTopology 准入控制器来限制 topologyKey 只能是 kubernetes.io/hostname。如果要使用自定义拓扑域,则可以修改准入控制器,或者直接禁用它。
- 对于 preferredDuringSchedulingIgnoredDuringExecution 的 Pod 反亲和性,空的 topologyKey 表示所有拓扑域。截止 v1.12 版本,所有拓扑域还只能是 kubernetes.io/hostname、failure-domain.beta.kubernetes.io/zone 和 failure-domain.beta.kubernetes.io/region 的组合。
- 除上述情况外,topologyKey 可以是任何合法的标签 key
拓扑分区约束
- 官方文档
- 拓扑键只能粗粒度划分区域,拓扑分区约束可以更细粒度设置
- 我们可以给节点设置标签,如下
- 在部署pod时通过topologySpreadConstraints拓扑分区约束
apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
# 配置一个拓扑分布约束
topologySpreadConstraints:
- maxSkew: 1 #最大倾斜,表示安装选中的pod时节点部署数量允许超过平均值的最大数?
topologyKey: zone #拓扑键,例如根据zone分区此时就会出现zoneA与zoneB
minDomains: <integer> # 可选;自从 v1.25 开始成为 Beta
labelSelector: #选择器(该选择器选的是pod类型,上面使用zone做了分区)
matchLables:
foo: bar #根据标签选中pod
whenUnsatisfiable: <string>
matchLabelKeys: <list> # 可选;自从 v1.25 开始成为 Alpha
nodeAffinityPolicy: [Honor|Ignore] # 可选;自从 v1.25 开始成为 Alpha
nodeTaintsPolicy: [Honor|Ignore] # 可选;自从 v1.25 开始成为 Alpha
二. 污点与容忍
- 官方文档
- 以k8s调度部署pod为例,在部署时首先会按照拓扑键拓扑分区约束进行划分,然后通过亲和与反亲和策略选择指定节点安装部署,然后会通过污点与容忍度去判断选择
- 首先污点是设置到节点上的,容忍是设置在pod上的,默认情况下不会给有污点标签的节点调度,除非pod中设置了容忍,容忍跟污点是有对应关系的
- 进而解释在k8s集群中安装部署时为什么不回安装部署到master节点,因为master节点给打了污点标签,查看污点命令
执行命令后返回的数据中,前面"node-role.kubernetes.io/master"是污点名,冒号后面是污点的作用效果,例如 “NoSchedule”
kubectl describe node 节点名称|grep Taint
5. 污点类型三种:
- NoSchedule: 不调度,不给有该类型污点的节点部署pod
- PreferNoSchedule: 比NoSchedule宽泛,尽量不会在该类型的节点上调度
- NoExecute: 不能在节点上运行,如果已经运行将被驱逐(被赶走后基于k8s的恢复机制,可以在其它节点重新拉起)
- 节点添加污点命令
kubectl taint node 节点名称 污点key=污点值(值是可选参数):污点类型
- 并且在k8s 1.6版本后如果发现节点存在一些特殊情况,会自动给节点添加污点,针对这些节点进行特殊处理,例如隔离防止应用部署到问题节点上
- pod上设置容忍
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploymentdemo
labels:
app: deploymentdemo
spec:
replicas: 10
template:
metadata:
name: deploymentdemo
labels:
app: deploymentdemo
spec:
tolerations: #设置容忍
- key: "offline" #容忍的污点key
value: "testtaint" #容忍的污点key对应的value
operator: "Equal" #容忍方式,Equal等值匹配,Exists存在
effect: "NoSchedule" #容忍污点类型(如果不指定该属性表示可以容忍通过key拿到的任何类型污点)
#tolerationSeconds: #容忍时间(指定时间内节点还是污点状态,则不再容忍)
containers:
- name: deploymentdemo
image: nginx:1.17.10-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
restartPolicy: Always
selector:
matchLabels:
app: deploymentdemo
三. 资源限制与调度策略
- 在部署pod时,containers容器中可以设置requests与limit, 在调度部署时,k8s底层会根据这个限制判断选择合适的节点安装