k8s 支持三大类调度方式:
一.节点亲和调度
用于约束一个 Pod以便 限制 其只能在特定的节点上运行, 或优先在特定的节点上运行。
1. nodeSelector
nodeSelector 是节点选择约束的最简单的方式,通过添加nodeSelector
字段添加到 Pod 的规约中设置你希望的目标节点所具有的标签,Kubernetes 只会将 Pod 调度到拥有你所指定的每个标签的节点上,常用于节点隔离。
例子:只能调度到具有type: test
标签的节点上
spec:
nodeSelector:
type: test
使用标签来实现节点隔离,建议选择节点上的 无法修改的标签键(
NodeRestriction
准入插件防止 kubelet 使用node-restriction.kubernetes.io/
前缀设置或修改标签)。 这可以防止受感染的节点在自身上设置这些标签, 比如:example.com.node-restriction.kubernetes.io/pci-dss=true
2.通过NodeAffinity调度插件
利用NodeAffinity调度插件实现节点亲和性(.spec.affinity.nodeAffinity
),具有更强的表达能力,且允许定义软规则。
节点亲和性有两种:
-
requiredDuringSchedulingIgnoredDuringExecution
: 调度器只有在规则被满足的时候才能执行调度。此功能类似于 nodeSelector, 但其语法表达能力更强(强制亲和) -
preferredDuringSchedulingIgnoredDuringExecution
: 调度器会尝试寻找满足对应规则的节点。如果找不到匹配的节点,调度器仍然会调度该 Pod(首先亲和或者软亲和)
IgnoredDuringExecution
意味着如果节点标签在 Kubernetes 调度 Pod 后发生了变更,Pod 仍将继续运行
例子:只能运行在具有便签type=dev
或者 type=test
的节点上,且优先选择具有便签键gpu
节点上
···
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- dev
- test
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: gpu
operator: Exists
containers:
···
1.operator 字段支持
In
、NotIn
、Exists
、DoesNotExist
、Gt
和Lt
2.nodeSelectorTerms指定多个条件是逻辑或的关系,单个matchExpressions多个表达式是逻辑与的关系
3.nodeName
nodeName 是比亲和性和nodeSelector 更为直接的形式。nodeName 是 Pod 规约中的一个字段。指定节点上的 kubelet 会尝试将 Pod 放到该节点上。 nodeName 规则的优先级会高于nodeSelector 或亲和性与非亲和性的规则(不建议使用)
直接运行在node-01节点上
spec:
nodeName: node-01
二. Pod间亲和调度
Pod间亲和性和反亲和性调度(PodAffinity、PodUnAffinity)可以基于已经在节点上运行的 Pod 的标签来约束 Pod 可以调度到的节点,而不是基于节点上的标签与节点亲和性类似, 常用于确保相关的Pod运行在“同一位置”,Pod 的亲和性与反亲和性也有两种类型:
-
requiredDuringSchedulingIgnoredDuringExecution
强制亲和 -
preferredDuringSchedulingIgnoredDuringExecution
首选亲和(软亲和)
要使用 Pod 间亲和性,可以使用 Pod 规约中的.affinity.podAffinity
字段。 对于 Pod 间反亲和性,可以使用 Pod 规约中的.affinity.podAntiAffinity
字段
例如Webapp 的Deployment , webapp 副本跟redis调度到同一位置 topologyKey:zone
···
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["redis"]}
topologyKey: zone #拓扑键,用于确定节点位置的节点标签,必须
containers:
···
例如Redis的Deployment, redis 副本不要调度到同一节点上
···
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["redis"]}
topologyKey: "kubernetes.io/hostname"
containers:
···
topologyKey 可以是任何合法的标签键。出于性能和安全原因,topologyKey 有一些限制:
对于 Pod 亲和性而言,在requiredDuringSchedulingIgnoredDuringExecution
和preferredDuringSchedulingIgnoredDuringExecution
中,topologyKey
不允许为空。
对于requiredDuringSchedulingIgnoredDuringExecution
要求的 Pod 反亲和性, 准入控制器 LimitPodHardAntiAffinityTopology 要求 topologyKey 只能是kubernetes.io/hostname
。如果你希望使用其他定制拓扑逻辑, 你可以更改准入控制器或者禁用之
可以通过与 labelSelector 和 topologyKey同层级 labelSelector 指定要匹配的命名空间列表, 如果 namespaces 被忽略或者为空,则默认为 Pod 亲和性/反亲和性的定义所在的命名空间
三.污点容忍调度
通过定义节点上Taints污点,用于让节点有能力主动拒绝调度器将pod调度到节点上,除非该pod具有接纳节点污点的容忍度, 简单说提供主动排斥Pod的能力。
1.定义污点(节点上)
- 添加污点
kubectl taint nodes node1 key1=value1:NoSchedule #语法key=value:affective
- 删除污点
kubectl taint nodes node1 key1=value1:NoSchedule-
2.污点效用标识
- NoSchedule: 不能容忍此污点的Pod对象不可调度至当前节点,对节点上现存的Pod不影响
- PreferNoSchedule:NoSchedule的柔性版本,尽量不会将不能容忍污点的Pod调度到当前节点
- NoExecute:不能容忍此污点的Pod对象不可调度至当前节点,会驱逐节点上不满足污点的Pod
3.定义容忍度(Pod)
通过spec.tolerations
定义容忍度,一个容忍度和一个污点相“匹配”是指它们有一样的键名和效果
容忍污点key1=value1:NoSchedule
...
spec:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
...
或者
...
spec:
tolerations:
- key: "key1"
operator: "Exists" #此时容忍度不能指定value,代表容忍存在键值为key1 效果是NoSchedule的污点
effect: "NoSchedule"
...
存在两种特殊情况:
如果一个容忍度的 key 为空且 operator 为 Exists, 表示这个容忍度与任意的 key、value 和 effect 都匹配,即这个容忍度能容忍任何污点。
如果 effect 为空,则可以与所有键名 key1 的效果相匹配
一个节点可以定义多个污点,Pod必须匹配节点上所有污点才算符合条件
延迟驱逐
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600 #当Pod不能容忍污点,Pod 还将继续在节点上运行 3600 秒,然后被驱逐
4.使用场景
-
专用节点/特殊节点:为特殊/专用的Node定义污点,只有特殊/专用Pod才能在上面运行
比如master节点自动添加污点node-role.kubernetes.io/master:NoSchedule
设置节点不可调度也是设置污点
node.kubernetes.io/unschedulable:NoSchedule
kubectl cordon node1
设置节点不可调度也是设置污点
node.kubernetes.io/unschedulable:NoSchedule
,但是会驱逐节点上的Podkubectl drain node1 # --ignore-daemonsets 忽略daemonset类型的pod
恢复命令
kubectl uncordon node1
-
基于节点的驱逐:控制平面使用节点控制器自动创建 与节点状况 对应的污点(自定增加与删除)
node.kubernetes.io/not-ready
:节点未准备好。这相当于节点状况 Ready 的值为 "False"。
node.kubernetes.io/unreachable
:节点控制器访问不到节点. 这相当于节点状况 Ready 的值为 "Unknown"。
node.kubernetes.io/memory-pressure
:节点存在内存压力。
node.kubernetes.io/disk-pressure
:节点存在磁盘压力。
node.kubernetes.io/pid-pressure
: 节点的 PID 压力。
node.kubernetes.io/network-unavailable
:节点网络不可用。
node.kubernetes.io/unschedulable
: 节点不可调度。
node.cloudprovider.kubernetes.io/uninitialized
:如果 kubelet 启动时指定了一个“外部”云平台驱动, 它将给当前节点添加一个污点将其标志为不可用。在 cloud-controller-manager 的一个控制器初始化这个节点后,kubelet 将删除这个污点。
网友评论