k8s 读书笔记 - 详解 Pod 调度(Ⅰ卷)

上一篇 《深入掌握 Pod》 文章我们介绍了 Pod 的知识点,接下来我们来继续学习 Pod  在 k8s 中的调度原理。在 k8s 平台上,通常情况下很少直接创建一个 Pod,大多情况下都是通过 Pod 的资源管理对象 来创建,例如:RC/RS、Deployment、DaemonSet、Job & CornJob 等控制器完成对一组 Pod 创建、调度及全生命周期的自动控制管理等任务。

ffc858d4900e7ab81dc863dc3c9457ca.png

Pod调度

k8s 调度器(kube-scheduler)

kube-scheduler 是 Kubernetes 集群的默认调度器,并且是 集群控制面 的一部分。 如果你真的希望或者有这方面的需求,kube-scheduler 在设计上允许你自己编写一个调度组件并替换原有的 kube-scheduler

对每一个新创建的 Pod 或者是未被调度的 Pod,kube-scheduler 会选择一个最优的节点去运行这个 Pod。 然而,Pod 内的每一个容器对资源都有不同的需求, 而且 Pod 本身也有不同的需求。因此,Pod 在被调度到节点上之前, 根据这些特定的调度需求,需要对集群中的节点进行一次 过滤

在一个集群中,满足一个 Pod 调度请求的所有节点称之为 可调度节点。 如果没有任何一个节点能满足 Pod 的资源请求, 那么这个 Pod 将一直停留在未调度状态直到调度器能够找到合适的 Node。

调度器先在集群中找到一个 Pod 的所有 可调度节点,然后根据一系列函数对这些可调度节点 打分, 选出其中得分最高的节点来运行 Pod。之后,调度器将这个调度决定通知给 kube-apiserver,这个过程叫做 绑定

在做调度决定时需要考虑的因素包括:单独和整体的资源请求、硬件/软件/策略限制、 亲和以及反亲和要求、数据局部性、负载间的干扰等等

了解【集群控制面】更多信息,请查看:https://kubernetes.io/zh-cn/docs/reference/glossary/?all=true#term-control-plane

kube-scheduler 调度流程

kube-scheduler 给一个 Pod 做调度选择时包含两个步骤:过滤打分,如下流程所示:

d9e1c27abc3fc6e0701d2187ad3697eb.png

kube-scheduler 调度流程

过滤阶段】会将所有满足 Pod 调度需求的节点选出来。 例如,PodFitsResources 过滤函数会检查候选节点的可用资源能否满足 Pod 的资源请求。 在过滤之后,得出一个节点列表,里面包含了所有可调度节点;通常情况下, 这个节点列表包含不止一个节点。如果这个列表是空的,代表这个 Pod 不可调度。

打分阶段】调度器会为 Pod 从所有可调度节点中选取一个最合适的节点。 根据当前启用的打分规则,调度器会给每一个可调度节点进行打分。

最后,kube-scheduler 会将 Pod 调度到得分最高的节点上。 如果存在多个得分最高的节点,kube-scheduler 会从中随机选取一个。

支持以下两种方式配置 调度器的过滤和打分 行为:

  1. 调度策略】 允许你配置过滤所用的 断言(Predicates) 和打分所用的 优先级(Priorities)

  2. 调度配置】允许你配置实现不同调度阶段的插件, 包括:QueueSort、Filter、Score、Bind、Reserve、Permit 等等。 你也可以配置 kube-scheduler 运行不同的配置文件。

了解 kube-scheduler 更多信息,请查看:https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/kube-scheduler/

Deployment & ReplicaSet,全自动调度

在早期的 k8s 版本中是没有这么多 Pod 副本控制器的,只有一个 Pod 副本控制器 RC(Replication Controller),RC 的设计实现:RC 独立于所控制的 Pod,并通过 Label 标签松耦合关联关系控制目标 Pod 实例的创建和销毁。在 k8s 的新版本中,RC 已经被 ReplicaSet(RS) 替换,RS 增强了 RC 的功能,RC 的标签选择器只能选择一个标签,而 RS 不但能选择标签,还拥有集合式的标签选择器,可以选择多个 Pod 标签,如下所示:

selector:matchLabels:tier: frontendmatchExpressions: - {key: tier, operator: In, values: [frontend]}

RS 应用场景举例

例如 frontend 应用发布了 v1v2 两个版本,此时你希望 frontend 的 Pod 副本数保持为 3 个,并且可以同时包含 v1v2 版本的 Pod,这种情况就可以使用 RS 来实现控制,写法如下:

selector:matchLabels:version: v2matchExpressions: - {key: version, operator: In, values: [v1,v2]}

从这个例子中可以看出,在 k8s 中的 滚动更新 就是巧妙利用 ReplicaSet(RS) 特性来实现的。

Deployment 默认调度

前面文章介绍了 Deployment 资源对象,这里我们简单的回顾下 Deployment 对象的调用链:

kubectl(client) => Deployment => ReplicaSet => Pod => Container

在大多数情况下,通常都不会直接创建 Pod,而是使用 Deployment 对象来创建 Pod ,而 Deployment 对象底层也是通过 ReplicaSet 来控制 Pod 副本数量的,这也是 官方推荐的方式,而不是直接使用底层的 ReplicaSet 来创建 Pod。

上面举例的 Deployment 对象的 yaml 定义完整文件 nginx-deployment.yaml 如下:

apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deploymentlabels:app: nginx
spec:replicas: 3    # Pod 实例副本数selector:matchLabels:version: v2matchExpressions: - {key: version, operator: In, values: [v1,v2]}template:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.14.2ports:- containerPort: 80

运行命令创建 Deployment 对象:

kubectl create -f nginx-deployment.yaml

查看 Deployment 的状态:

kubectl get deployments

查看创建的 ReplicaSet(RS)对象:

kubectl get rs

查看创建的 Pod 对象的详细信息:

kubectl get pods -o wide
# 等效命令
kubectl get pods --output=wide

k8s 中 Master 上的 Schedule 服务(kube-scheduler 进程)负责实现 Pod 的调度。整个调度过程通过执行一系列复杂的算法,最终为每个 Pod 都计算出一个最佳的目标节点,这一过程是自动完成的。

接下来我们详细的介绍 Pod 的几种调度模式,每种模式都应用于特定的场景。

NodeSelector,节点定向调度

nodeSelector 是节点选择约束的最简单推荐形式。你可以将 nodeSelector 字段添加到 Pod 的规约中设置你希望的目标节点所具有的节点标签。 **k8s 只会将 Pod 调度到拥有指定的标签的节点上**。

举例,将 Pod 调度到拥有 Lable 标签的 disktype: ssd 节点上,该 Pod 的 yaml 文件定义如下:

apiVersion: v1
kind: Pod
metadata:name: nginxlabels:env: test
spec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentnodeSelector:disktype: ssd

Pod 亲和性调度

亲和性调度功能包括 节点亲和性(NodeAffinity)Pod 亲和性(PodAffinity) 两个维度的设置。

NodeSelector 通过 Label 标签的方式,简单的实现了限制 Pod 所在节点的方法。亲和性调度机制则极大的扩展了 Pod 的调度能力,主要增强功能有以下几点:

  • 亲和性、反亲和性语言的表达能力更强。nodeSelector 只能选择拥有所有指定标签的节点。 亲和性、反亲和性为你提供对选择逻辑的更强控制能力。

  • 可以使用 “软限制” 、优先采用等限制方式,代替之前的 “硬限制”,这样调度器在无法满足优先需求的情况下,会退而求其次,继续运行该 Pod。

  • 可以根据节点上正在运行的其他 Pod 的标签来进行限制,而非节点本身的标签。这样就可以定义一种规则来描述 Pod 之间的亲和性和互斥关系。

NodeAffinityNodeSelector 类似,增强了上面前两点优势。Pod 的 PodAffinity(亲和性) 和 PodAntiAffinity(互斥性)限制则是通过 Pod 标签来实现的,而不是 Node 节点标签,Pod 亲和性和互斥性调度都具备上述提到的优点

亲和性功能由两种类型的亲和性组成:

  • NodeAffinit 功能类似于 NodeSelector 字段,但它的表达能力更强,并且允许你指定软规则。

  • Pod 间亲和性/反亲和性 允许你根据其他 Pod 的标签来约束 Pod。

NodeAffinity,节点亲和性调度

节点亲和性概念上类似于 nodeSelector, 它使你可以 根据节点上的 Label 标签来约束 Pod 可以调度到哪些节点上。 节点亲和性有两种:

  • requiredDuringSchedulingIgnoredDuringExecution:(硬性规则)调度器只有在规则被满足的时候才能执行调度。此功能类似于 nodeSelector, 但其语法表达能力更强。

  • preferredDuringSchedulingIgnoredDuringExecution:(软性规则)调度器会尝试寻找满足对应规则的节点。如果找不到匹配的节点,调度器仍然会调度该 Pod。对软性规则可设置权重 weight,其取值范围 1- 100 之间。

使用 Pod 规约中的 .spec.affinity.nodeAffinity 字段来设置 NodeAffinity(节点亲和性)。举例: with-node-affinity.yaml 文件定义如下:

apiVersion: v1
kind: Pod
metadata:name: with-node-affinity
spec:affinity:# 节点亲和性nodeAffinity:# 硬性规则,必须满足条件requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: topology.kubernetes.io/zone  # 地区operator: Invalues:- antarctica-east1  # 南极洲东部1- antarctica-west1  # 南极洲西部1- key: topology.kubernetes.io/arch  # 架构operator: In  # 设置逻辑操作符values:- amd64- arm64# 软性规则,尝试满足,优先满足,不是必须条件preferredDuringSchedulingIgnoredDuringExecution:# 权重,优先级- weight: 1preference:matchExpressions:- key: disk-type  # another-node-label-key,匹配另一个节点标签的 keyoperator: Invalues:- ssd   # another-node-label-value,匹配另一个节点标签的 valuecontainers:- name: with-node-affinityimage: k8s.gcr.io/pause:3.1

从上面的 yaml 定义中可以看到 In 操作符,我们来回顾下 NodeAffinity 语法支持的操作符包括:In、NotIn、Exists、DoesNotExists、Gt、Lt。虽然没有节点互斥功能,但可以用 NotIn 和 DoesNotExists 来实现节点互斥功能

说明:上面的 NodeAffinity 示例中,定义了两个硬性规则条件,分别是 地区(zone)架构(arch ),另外定义了一个软性规则条件,那就是 硬盘类型(disk-type)k8s 的默认调度器 Schedule 服务(kube-scheduler 进程) 则遵循定义规则实现该 Pod 的调度,整个过程全部自动完成,无需人工干预。

逐个调度方案中设置节点亲和性

【特性状态】: Kubernetes v1.20 [beta]

在配置多个调度方案时, 如果某个调度方案仅适用于某组特殊的节点时,可以将该方案与节点亲和性关联起来, 这样做是很有用的。要实现这点,可以在 调度器配置 中为 NodeAffinity 插件的 args 字段添加 addedAffinity

示例:

apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
...
profiles:- schedulerName: default-scheduler- schedulerName: foo-schedulerpluginConfig:- name: NodeAffinityargs:addedAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: scheduler-profileoperator: Invalues:- foo

这里的 addedAffinity 除遵从 Pod 规约 space 中设置的 NodeAffinity(节点亲和性) 之外, 还适用于将 .spec.schedulerName 设置为 foo-scheduler。 换言之,为了匹配 Pod,node 节点需要满足 addedAffinity 和 Pod 的 .spec.NodeAffinity

注意:由于 addedAffinity 对最终用户不可见,其行为可能对用户而言是出乎意料的。 应该使用与调度方案名称有明确关联的节点标签。

说明:DaemonSet 控制器为 DaemonSet 创建 Pods, 但该控制器不理会调度方案。 DaemonSet 控制器创建 Pod 时,默认的 Kubernetes 调度器(kube-scheduler)负责放置 Pod, 并遵从 DaemonSet 控制器中奢侈的 nodeAffinity 规则

NodeAffinity 规则设置说明

  • 如果同时定义了  nodeSelectorNodeAffinity ,这两个条件必须满足(and 关系),Pod 才能最终运行在指定的 Node 上。

  • 如果 NodeAffinity 指定了多个 nodeSelectorTerms ,其中一个条件能够匹配成功即可(or 关系)。

  • 如果在  nodeSelectorTerms  中有多个 matchExpressions ,则目标 Node 必须满足所有 matchExpressions 才能运行该 Pod(and 关系)。

节点亲和性权重(weight)

可以为 preferredDuringSchedulingIgnoredDuringExecution 亲和性类型的每个实例设置 weight 字段,其 取值范围是 1 到 100。 当调度器找到能够满足 Pod 的其他调度请求的 node 节点时,调度器会遍历 node 满足的所有的偏好性规则, 并将对应表达式的 weight 值加和。

最终的加和值会添加到该节点的其他优先级函数的评分之上。 在调度器为 Pod 作出调度决定时,总分最高的节点的优先级也最高。

Pod 规约的 with-affinity-anti-affinity.yaml 文件定义示例:

apiVersion: v1
kind: Pod
metadata:name: with-affinity-anti-affinity
spec:affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/osoperator: Invalues:- linuxpreferredDuringSchedulingIgnoredDuringExecution:- weight: 1preference:matchExpressions:- key: label-1operator: Invalues:- key-1- weight: 50preference:matchExpressions:- key: label-2operator: Invalues:- key-2containers:- name: with-node-affinityimage: k8s.gcr.io/pause:3.1

如果存在两个候选节点,都满足 preferredDuringSchedulingIgnoredDuringExecution 规则, 其中一个节点具有标签 label-1:key-1,另一个节点具有标签 label-2:key-2, 调度器会考察各个节点的 weight 取值,并将该权重值添加到节点的其他得分值之上。

说明:如果你希望 k8s 能够成功地调度此例中的 Pod,你必须拥有打了 kubernetes.io/os=linux 标签的节点。

Pod 间亲和性和互斥性调度(PodAffinity & PodAntiAffinity)

【特性状态】: Kubernetes v1.4 引入

Pod 间亲和性(PodAffinity)与反亲和性(也叫互斥性,PodAntiAffinity)使你可以 基于已经在节点上运行的 Pod 的标签来约束 Pod 可以调度到的节点,而不是基于节点上的标签。

PodAffinityPodAntiAffinity规则格式“如果 **X** 上已经运行了一个或多个满足规则 **Y** 的 Pod, 则这个 Pod 应该(或者在反亲和性的情况下不应该)运行在 **X** 上”。 这里的 **X** 可以是节点、机架、云提供商可用区或地理区域或类似的拓扑域, **Y** 则是 Kubernetes 尝试满足的规则

  • topology.kubernetes.io/hostname,节点

  • topology.kubernetes.io/zone,机架

  • topology.kubernetes.io/region,区域

通过 标签选择算符 的形式来表达规则 (Y),并可根据需要指定选择关联的 Namespace(名字空间) 列表。 Pod 在 k8s 中是 Namespace 作用域的对象,因此 Pod 的标签也隐式地具有 Namespace 属性。 针对 Pod 标签的所有标签选择算符都要指定 Namespace,k8s 会在指定的 Namespace 内寻找 Label 标签。

通过 topologyKey 来表达 拓扑域 (X) 的概念,其取值是系统用来表示域的 节点标签键。 相关示例可参见常用 标签、注解和污点

【标签、注解和污点】参考文档:,https://kubernetes.io/zh-cn/docs/reference/labels-annotations-taints/。

【说明】

  • Pod 间亲和性和反亲和性都需要相当的计算量,因此会在大规模集群中显著降低调度速度不建议在包含数百个节点的集群中使用这类设置。

  • Pod 反亲和性需要节点上存在一致性的标签(交集)。换言之, 集群中每个节点都必须拥有与 topologyKey 匹配的标签。 如果某些或者所有节点上不存在所指定的 topologyKey 标签,调度行为可能与预期的不同。

Pod 间亲和性与反亲和性类型

与节点亲和性(NodeAffinity)类似,Pod 间的 PodAffinity & PodAntiAffinity (亲和性与反亲和性)也有两种类型:

  • requiredDuringSchedulingIgnoredDuringExecution,硬性条件,必须满足。

  • preferredDuringSchedulingIgnoredDuringExecution,软性条件,尝试满足(优先级依据权重 weight)。

要使用 Pod 间亲和性(PodAffinity),可以使用 Pod 规约 spec 中的 spec.affinity.podAffinity 字段。 对于 Pod 间反亲和性(PodAntiAffinity ),可以使用 Pod 规约中的 spec.affinity.podAntiAffinity 字段。

Pod 间亲和性与反亲和性示例

with-pod-affinity.yaml 定义文件

apiVersion: v1
kind: Pod
metadata:name: with-pod-affinity
spec:affinity:podAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: securityoperator: Invalues:- S1topologyKey: topology.kubernetes.io/zonepodAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchExpressions:- key: securityoperator: Invalues:- S2topologyKey: topology.kubernetes.io/zonecontainers:- name: with-pod-affinityimage: k8s.gcr.io/pause:3.1

with-pod-affinity.yaml 文件定义说明:

  • 亲和性(podAffinity.requiredDuringSchedulingIgnoredDuringExecution)规则表示,仅当节点和至少一个已运行且有 security=S1 的标签的 Pod 处于同一区域时,才可以将该 Pod 调度到节点上。 更确切的说,调度器必须将 Pod 调度到具有 topology.kubernetes.io/zone=V 标签的节点上,并且集群中至少有一个位于该可用区的节点上运行着带有 security=S1 标签的 Pod。

  • 反亲和性(podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution)规则表示,如果节点处于 Pod 所在的同一可用区且至少一个 Pod 具有 security=S2 标签,则该 Pod 不应被调度到该节点上。 更确切地说, 如果同一可用区中存在其他运行着带有 security=S2 标签的 Pod 节点, 并且节点具有标签 topology.kubernetes.io/zone=R,Pod 不能被调度到该节点上。

Pod 间亲和性与反亲和性(PodAffinity & PodAntiAffinity)为其  operator(操作符) 字段使用  In、NotIn、Exists、 DoesNotExist 、Gt、Lt 值。

topologyKey 限制规则

原则上,topologyKey(拓扑逻辑) 可以是任何合法的 标签键出于性能和安全原因,topologyKey 有一些限制

  • 对于 Pod 亲和性而言,在 requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution 中,topologyKey 不允许为空。

  • 对于 requiredDuringSchedulingIgnoredDuringExecution 要求的 Pod 反亲和性, 如果 Admission controller(准入控制器)包含了 LimitPodHardAntiAffinityTopology ,针对 requiredDuringScheduling 的 Pod 互斥性要求 topologyKey 只能是 kubernetes.io/hostname。如果要使用其他定制或自定义的 topologyKey,需要更改或禁用该 Admission controller

  • 在  requiredDuringScheduling 类型的 Pod 互斥性定义中,空的  topologyKey  会被解释为 kubernetes.io/hostname、failure-domain.beta.kubernetes.io/zone 及 failure-domain.beta.kubernetes.io/region 的组合。

  • 除开上述情况,可以使用任意合法的   topologyKey  。

PodAffinity 规则设置说明

  • 除了 labelSelectortopologyKey,你也可以指定 labelSelector 要匹配的 Namespace(命名空间)列表,方法是在 labelSelector topologyKey 所在层同一层次上设置 namespaces。 如果 namespaces 被忽略或者为空(""),则默认为 Pod 亲和性/反亲和性的定义所在的 namespaces 命名空间。

  • 在所关联的  requiredDuringSchedulingIgnoredDuringExecution  的 matchExpressions 全部满足之后,系统才能将 Pod 调度到某个 Node 上。

关于【亲和性】更多信息,请查看:https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity

Namespaces 选择算符

【特性状态】: Kubernetes v1.24 [stable]

我们也可以使用 namespaceSelector 选择匹配的 namespacesnamespaceSelector 是对名字空间集合进行标签查询的机制。 亲和性条件会应用到 namespaceSelector 所选择的名字空间和 namespaces 字段中所列举的名字空间之上。 注意,空的 namespaceSelector({}) 会匹配所有名字空间,而 null 或者空namespaces 列表以及 null 值 namespaceSelector 意味着 “当前 Pod 的名字空间”

生产环境中更多的实际示例

Pod 间亲和性与反亲和性在与更高级别的集合(例如 ReplicaSet、StatefulSet、 Deployment 等)一起使用时,它们可能更加有用。 这些规则使得你可以配置一组工作负载,使其位于所定义的同一拓扑中; 例如优先将两个相关的 Pod 置于相同的节点上。

以一个三 node 的集群为例,使用 Pod 间的 PodAffinity & PodAntiAffinity 来尽可能地将该 Web 服务器与缓存服务器(例如:Redis)并置,部署规格如下列表:

node-1node-2node-3
webserver-1webserver-2webserver-3
cache-1cache-2cache-3

redis-cache_web-server.yaml 文件定义如下:

apiVersion: apps/v1
kind: Deployment
metadata:name: redis-cache
spec:selector:matchLabels:app: storereplicas: 3  # 设置 Pod 实例副本数量template:metadata:labels:app: storespec:affinity:# Pod 反亲和性(互斥性)podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- storetopologyKey: "kubernetes.io/hostname"containers:- name: redis-serverimage: redis:7.0.4-alpine
---
apiVersion: apps/v1
kind: Deployment
metadata:name: web-server
spec:selector:matchLabels:app: web-storereplicas: 3template:metadata:labels:app: web-storespec:affinity:# Pod 反亲和性(互斥性)podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- web-storetopologyKey: "kubernetes.io/hostname"podAffinity:# Pod 亲和性requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- storetopologyKey: "kubernetes.io/hostname"containers:- name: web-appimage: nginx:1.23.1-alpine

创建上面的 Deployment 对象资源:

kubectl create -f redis-cache_web-server.yaml

查看创建的 Deployment 对象信息:

kubectl get deployment redis-cache, web-server

参考文档:

  • 将 Pod 指派给节点,https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/assign-pod-node/

Taints & Tolerations,污点和容忍调度

上面介绍的 NodeAffinity (节点亲和性),是在 Pod 上定义的一种属性,使得 Pod 能够被调度到一类特定的节点 (这可能出于一种偏好或软性条件,也可能是硬性强制要求)。接下来我们介绍的 Taints(污点)则与之相反,它 让 Node 拒绝运行 Pod(排斥一类特定的 Pod)

同样 Toleration 也是 Pod 的属性容忍度(Toleration) 是应用于 Pod 上的。容忍度允许调度器调度带有对应  Taints(污点) 的 Pod。 容忍度允许调度但并不保证调度:作为其功能的一部分, 调度器也会评估其他参数。

Taint(污点)需要和 Toleration(容忍调度)配合使用,可以用来避免 Pod 被分配到不合适的 Node 上。在每个 node 上都可以设置一个或多个 Taint ,除非 Pod 明确声明能够 Toleration(容忍)这些 Taint ,否则无法在这些 Node 上运行该 Pod。

使用命令为 Node 设置 Taint 信息:

kubectl taint nodes k8s-node-01 key=value:NoSchedule

接下来在 Pod 上申明 Toleration 属性,如下示例:

tolerations: 
- key: "key"operator: "Equal"value: "value"effect: "NoSchedule"

或者

tolerations: 
- key: "key"operator: "Exists"effect: "NoSchedule"

Pod 的 Toleration  声明中的 key 和 effect 需要与 Taint 的设置保持一致,并且满足以下条件之一:

  • operator 的值是 Exists(无需指定 value)。

  • operator 的值是 Equal 需要设置 value 并且相等。

如果不指定 operator(操作符),默认值是 Equal 。另外,还有两个特例如下:

  • 空("")的 key 配合 Exists 操作符能够匹配所有的 key 和 value。

  • 空("")的 effect 匹配所有的 effect。

在上面的示例中,effect 设置调度优先级,其取值为:NoSchedule,PreferNoSchedule、NoExecute

PreferNoSchedule 可以看作是 NoSchedule 的软限制版,一个 Pod 如果没有声明容忍这个 Taint,则系统会尽量避免把这个 Pod 调度到对应 Taint 标记的 Node 上,但不是强制的。

k8s 系统允许在同一个 Node 上设置多个 Taint,也可以在 Pod 上设置多个 Toleration。

调度器处理污点和容忍的逻辑顺序

k8s 调度器(kube-scheduler) 处理多个 Taint(污点) 和 Toleration(容忍) 的逻辑顺序

  1. 首先列出 node 中的所有 Taint;

  2. 然后忽略 Pod 的 Toleration 能够匹配的部分;

  3. 剩余的没有忽略 Taint 的 node 就是对 Pod 的效果了。

在剩余的没有忽略 Taintnode 中,有以下几种特殊情况:

  • 如果在剩余的 Taint 中存在 effect=NoSchedule,则调度器不会把该 Pod 调度到这个 node 上。

  • 如果在剩余的 Taint 中没有 NoSchedule 效果,但是有 PreferNoSchedule 效果,则调度器会尝试不把该 Pod 指派给这个 node 上。

  • 如果在剩余的 Taint 中有 NoExecute 效果,并且这个 Pod 已经在该 Node 上运行,则会被 驱逐;如果没有在该 Node 上运行,则也不会再被调度到该 Node 上运行。

使用 Toleration 的 Pod 示例

apiVersion: v1
kind: Pod
metadata:name: nginxlabels:env: test
spec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresenttolerations:- key: "example-key"operator: "Exists"effect: "NoSchedule"

Taint 和 Toleration 应用示例

举例,我们使用一个 node(名称为 k8s-node-01) 进行 Taint 设置:

kubectl taint nodes k8s-node-01 key1=value1:NoSchedule
kubectl taint nodes k8s-node-01 key1=value1:NoExecute
kubectl taint nodes k8s-node-01 key2=value2:NoSchedule

然后在 Pod 上设置两个 Toleration :

tolerations: 
- key: "key1"operator: "Equal"value: "value1"effect: "NoSchedule"
- key: "key1"operator: "Equal"value: "value1"effect: "NoExecute"

这样的 Toleration 的设置结果是 Pod 无法调度到 k8s-node-01 上,因为上面命令行中第三个 Taint 没有匹配的 Toleration。但是如果该 Pod 已经在  k8s-node-01 上运行了,那么在运行时设置第三个 Taint,该 Pod 还能继续在  k8s-node-01 上运行,因为该 Pod 可以容忍前两个 Taint

一般情况,如果给 Node 加上 effect=NoSchedule 的 Taint,那么在该 Node 上运行的所有无对应 Toleration 的 Pod 都会被立刻驱逐,而具有相应 Toleration 属性的 Pod 永远不会被驱逐。不过,k8s 系统允许给具有 NoExecute 效果的 Toleration 加入一个可选的 tolerationSeconds 字段,这个字段设置表明 Pod 可以在 Taint  添加到 Node 之后还能在这个 Node 上运行多久(单位:s)。如下示例:

tolerations: 
- key: "key1"operator: "Equal"value: "value1"effect: "NoExecute"tolerationSeconds: 3600

上面 yaml 定义的意思是,如果 Pod 正在运行,所在 node 都被加入一个匹配的 Taint,这个 Pod 会持续在该 node 上存活 3600s 后被驱逐出。如果在这个宽限期内 Taint 被移除,则不会触发驱逐事件。

Taint 和 Toleration 常见用例

通过上面的示例,可以得知 Taint 和 Toleration 是一种处理 node 并且让 Pod 进行规避或者驱逐 Pod 的弹性处理方式,接下来我们列举一些常见的用例。

1. 专用(或独占)node

如果想想要拿出一部分 node 专门给特定的应用使用,则可以为 node 添加这样的 Taint,如下所示:

kubectl taint nodes nodename dedicated=groupName:NoSchedule

然后给这些应用 Pod 加入 Taint 对应的 Toleration。这样,带有合适 Toleration 的 Pod 就会被允许使用其他节点一样使用 Taint 的 node。

通过自定义 Admission Controller 也可以实现这一目标,如果希望让这些应用独占一批 node,并且确保它们只能使用这些 node,则还可以给这些 Taint 节点加人类似的标签 dedicated=groupName,然后 Admission Controller 需要加入 NodeAffinity(节点亲和性) 设置,要求 Pod 只会被调度到具有这一标签的 node 上。

2. 具有特殊硬件设备的 node

在集群里可能有一小部分节点安装了特殊的硬件设备(如 GPU芯片),希望把不需要占用这类硬件的 Pod 排除在外,以确保对这类硬件有需求的 Pod 能够被顺利调度到这些节点。

可以用下面的命令为 node 设置 Taint:

kubectl taint nodes nodename special=true:Roschedule
kubectl taint nodes nodename special=true:PrefezNoschedule

然后在 Pod 中利用对应的 Toleration 来保障特定的 Pod 能够使用特定的硬件环境。

和上面的 独占 node 的示例类似,使用 Admission Controller 来完成这一任务会更方便。例如,Admission Controller 使用 Pod 的一些特征来判断这些 Pod,如果可以使用这些硬件,就添加 Toleration 来完成这一工作。要保障需要使用特殊硬件的 Pod 只被调度到安装这些硬件的节点上,则还需要一些额外的工作,比如:将这些特殊资源使用 opaque-int-resource 的方式对自定义资源进行量化,然后在 PodSpec 中进行请求;也可以使用标签的方式来标注这些安装有特别硬件的节点,然后在 Pod 中定义 NodeAffinity(节点亲和性)来实现这个目标。

3. 基于 Taint(污点)的驱逐

【特性状态】: Kubernetes v1.18 [stable]

定义 Pod 驱逐行为,以应对 node 故障,这是在每个 Pod 中配置的在 node 出现问题时的驱逐行为。前面提到的 NoExecute 这个 Taint 效果对 node 上正在运行的 Pod 有以下影响。

  • 没有设置 Toleration 的 Pod 会被立刻驱逐。

  • 配置了对应 Toleration 的 Pod,如果没有为 tolerationSeconds 赋值,则会一直留在这一 node 中。

  • 配置了对应 Toleration 的 Pod 且指定了 tolerationSeconds 值,则会在指定时间段后驱逐。

举例,当网络出现故障时(网络中断),对于一个与节点本地状态有着深度绑定的应用而言,仍然停留在当前节点上运行一段较长的时间,以等待网络恢复以避免被驱逐。 此时可以为 Pod 设置的容忍度,如下所示:

tolerations:
- key: "node.kubernetes.io/unreachable"operator: "Exists"effect: "NoExecute"tolerationSeconds: 6000

说明: Kubernetes 会自动给 Pod 添加针对 node.kubernetes.io/not-readynode.kubernetes.io/unreachable 的容忍度,且配置 tolerationSeconds=300, 除非用户自身或者某控制器显式设置此容忍度。 这些自动添加的容忍度意味着 Pod 可以在检测到对应的问题之一时,在 5 分钟内保持绑定在该节点上。

DaemonSet 中的 Pod 被创建时,针对以下污点自动添加的 NoExecute 的容忍度将不会指定 tolerationSeconds

  • node.kubernetes.io/unreachable

  • node.kubernetes.io/not-ready

这保证了出现上述问题时 DaemonSet 中的 Pod 永远不会被驱逐

4.  基于 node 状态添加 Taint(污点)

控制平面使用 节点控制器 自动创建 与 节点状况 对应的、效果为 NoSchedule 的 Taint(污点)。

调度器在进行调度时检查污点,而不是检查节点状况。这确保节点状况不会直接影响调度。

例如:

  • 如果 DiskPressure 节点状况处于活跃状态,则控制平面添加 node.kubernetes.io/disk-pressure 污点并且不会调度新的 Pod 到受影响的节点。

  • 如果 MemoryPressure 节点状况处于活跃状态,则控制平面添加 node.kubernetes.io/memory-pressure 污点并且不会调度新的 Pod 到受影响的节点。

推荐参考文档:

  • 《污点和容忍度》https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/taint-and-toleration/

  • 《众所周知的标签、注解和污点》https://kubernetes.io/zh-cn/docs/reference/labels-annotations-taints/

未完待续

“夜好深了,纸窗里怎么亮着?”  好了先分享到这里,下一篇文章我们继续讲解,比如:Pod 优先级调度、DaemonSet 调度,Job 批处理调度,CronJob 定时任务 以及 自定义调度器。感兴趣的小伙伴,欢迎关注我,一起学习,一起成长哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283171.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET MAUI实战 Navigation

1.概要用过WPF的小伙伴一般都用过Prism,Prism里面的导航概念在MAUI中也有类似的概念,在MAUI中是直接集成在框架中我们不需要安装任何其他的nuget包。直接使用Navigation对象即可,通常在移动平台中使用的更多,桌面程序中。我们先来看看微软官方…

python报错 scrolled: false_python 元组tuple - python基础入门(14)

文章首发微信公众号,微信搜索:猿说python在上一篇文章中我们讲解了关于python列表List的相关内容,今天给大家解释一下列表List的兄弟 – 元组,俗称: tuple.元组tuple和列表List类似,元组有如下特点:1.由一个…

开放原子开源峰会 - SmartIDE正式开源并发布v1.0版本丨IDCF

在上周刚刚结束的【2022开放原子全球开源峰会】上 SmartIDE作为正在进行开放原子基金会TOC审核的开源项目,在云原生论坛上向全球的开源开发者介绍了下一代云原生CloudIDE的全新使用体验,并且正式发布了 SmartIDE v1.0 版本。作者:徐磊文章首发…

修改docker的默认存储位置及镜像存储位置

2019独角兽企业重金招聘Python工程师标准>>> 方法一、软链接 默认情况下Docker的存放位置为:/var/lib/docker 可以通过下面命令查看具体位置: sudo docker info | grep "Docker Root Dir" 解决这个问题,最直接的方法当然…

微信小程序第三方服务公司有哪些

虽然微信小程序还没有正式推出,但围绕着微信小程序第三方服务公司之间的战争早已经开始。他们在小程序生成工具(一键生成小程序,无需开发)、微信小程序开发工具、小程序数据统计等领域展开激烈竞争,我们一起来看看微信…

Blazor University (49)依赖注入 —— 比较依赖范围

原文链接:https://blazor-university.com/dependency-injection/dependency-lifetimes-and-scopes/comparing-dependency-scopes/比较依赖范围源代码[1]在本节中,我们将创建一个 Blazor 应用程序来演示各种依赖注入作用域的不同生命周期。为此&#xff0…

设计模式概论

此文转载于 http://blog.csdn.net/hguisu/article/details/74968191. 设计模式设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性…

只需要2个工具,百度云盘大文件就能用迅雷和IDM下载

不会代码,不懂脚本,没关系 ,能找到一座通往它们的桥梁,照样能到达彼岸。 这里以360极速浏览器为例。 在浏览器地址框输入以下地址直接到达浏览器安装扩展插件的地方(偷个懒,复制网址吧)&#xf…

rsync服务器的配置

一、rsync 简介Rsync(remote synchronize)是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件,也可以使用 Rsync 同步本地硬盘中的不同目录。 Rsync 是用于取代rcp的一个工具,Rsync使用所谓的 “Rsync 算法…

Vue学习笔记入门篇——数据及DOM

本文为转载,原文:Vue学习笔记入门篇——数据及DOM 数据 data 类型 Object | Function 详细 Vue 实例的数据对象。Vue 将会递归将 data 的属性转换为 getter/setter,从而让 data 的属性能够响应数据变化。对象必须是纯粹的对象(含有零个或多个…

BZOJ 3144 [Hnoi2013]切糕

3144: [Hnoi2013]切糕 Description Input 第一行是三个正整数P,Q,R,表示切糕的长P、 宽Q、高R。第二行有一个非负整数D,表示光滑性要求。接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤P, 1≤y≤Q, 1≤z≤R)。 100%的数据…

《ASP.NET Core 6框架揭秘》实例演示[18]:HttpClient处理管道

在《《ASP.NET Core 6框架揭秘》实例演示[17]:利用IHttpClientFactory工厂来创建HttpClient》之后,我们将关注点放到HttpClient对象上。我们知道ASP.NET的核心就是由中间件组成的请求处理管道,HttpClient也采用了类似的设计。HttpClient管道由…

雅诗兰黛天猫超级品牌日:未央唇膏、红装小棕瓶“当红不让”

随着年末圣诞季的临近,各大美妆品牌陆续推出了圣诞套装,红红火火的超豪华套装,算是对用户最实在的回馈。高端美妆品牌的“领头羊”雅诗兰黛,当然也“当红不让”,趁着圣诞季,与天猫超级品牌日联手打造了一场…

JAVA常见算法题(三十一)---冒泡排序

package com.jege.spring.boot.hello.world;/*** java算法之冒泡排序<br>* 将数组按照从大到小的顺序排列<br>* * * author Administrator**/ public class BubbleSort{public static void main(String[] args){int score[] {67, 69, 75, 87, 89, 90, 99, 100};fo…

WPF实现物理效果 拉一个小球

原文:WPF实现物理效果 拉一个小球一直以来都对物理效果有神秘感,完全不知道怎么实现的.直到看到了周银辉在老早前写的一篇博客:http://www.cnblogs.com/zhouyinhui/archive/2007/06/23/793724.html 终于知道是怎么实现的了. CompositionTarget类的Rendering事件.在每一帧成功渲…

C# CM框架下一行代码实现多页面管理

概述之前我分享过一个wpf的项目实践&#xff0c;主页面左侧是个listbox&#xff0c;每次选择改变后呈现对应的页面&#xff0c;界面图如下&#xff1a;要实现这样一个功能&#xff0c;我之前是采用传统方式实现的&#xff0c;本节我采用CM框架下的Conductor<T>去实现&…

关于JAVA异常处理的20个最佳实践

关于JAVA异常处理的20个最佳实践 在我们深入了解异常处理最佳实践的深层概念之前&#xff0c;让我们从一个最重要的概念开始&#xff0c;那就是理解在JAVA中有三种一般类型的可抛类: 检查性异常(checked exceptions)、非检查性异常(unchecked Exceptions) 和 错误(errors)。 异…

SSM框架搭建(四) springmvc和mybatis的配置

SSM框架搭建&#xff08;一&#xff09; JDK和MAVEN环境搭建 SSM框架搭建&#xff08;二&#xff09; 创建MAVEN项目 SSM框架搭建&#xff08;三&#xff09; 数据库创建和MyBatis生成器自动生成实体类、DAO接口和Mapping映射文件 SSM框架搭建&#xff08;四&#xff09; sprin…

10 个有关 String 的面试问题

2019独角兽企业重金招聘Python工程师标准>>> 下面是面试中最容易问到的有关String的问题。 1. 如何比较两个字符串&#xff1f;使用“”还是equals()方法&#xff1f; 简单来讲&#xff0c;“”测试的是两个对象的引用是否相同&#xff0c;而equals()比较的是两个字…

基于ASP.NET Core 6.0的整洁架构

背景最近尝试录制了一个系列视频&#xff1a;《ASP.NET Core 6.0Vue.js 3 实战开发》&#xff0c;本节是视频内部整洁架构的理论和实战的文字稿。因为在录制之前&#xff0c;我通常会编写完整的文字内容作为视频文案&#xff0c;这里分享给大家&#xff0c;希望对你有所帮助。如…