news 2026/11/3 10:43:50

Kubernetes权威指南——深入掌握Pod(Pod调度(二))

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kubernetes权威指南——深入掌握Pod(Pod调度(二))

深入掌握Pod

    • 9、玩转Pod调度
      • 9.5、Taints和Tolerations(污点和容忍)
      • 9.6、Pod Priority Preemption:Pod优先级调度

9、玩转Pod调度

9.5、Taints和Tolerations(污点和容忍)

前面介绍的NodeAffinity节点亲和性,是在Pod上定义的一种属性,使得Pod能够被调度到某些Node上运行(优先选择或强制要求)​。Taint则正好相反,它让Node拒绝Pod的运行。

Taint需要和Toleration配合使用,让Pod避开那些不合适的Node。在Node上设置一个或多个Taint之后,除非Pod明确声明能够容忍这些污点,否则无法在这些Node上运行。Toleration是Pod的属性,让Pod能够(注意,只是能够,而非必须)运行在标注了Taint的Node上。

可以用kubectl taint命令为Node设置Taint信息:

$ kubectl taint nodes node1key=value:NoSchedule

这个设置为node1加上了一个Taint。该Taint的键为key,值为value,Taint的效果是NoSchedule。这意味着除非Pod明确声明可以容忍这个Taint,否则就不会被调度到node1上。

然后,需要在Pod上声明Toleration。下面的两个Toleration都被设置为可以容忍(Tolerate)具有该Taint的Node,使得Pod能够被调度到node1上:

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操作符能够匹配所有的键和值。
  • 空的effect匹配所有的effect。

在上面的例子中,effect的取值为NoSchedule,还可以取值为PreferNoSchedule,这个值的意思是优先,也可以算作NoSchedule的软限制版本—一个Pod如果没有声明容忍这个Taint,则系统会尽量避免把这个Pod调度到这一节点上,但不是强制的。后面还会介绍另一个effect“NoExecute”​。

系统允许在同一个Node上设置多个Taint,也可以在Pod上设置多个Toleration。Kubernetes调度器处理多个Taint和Toleration的逻辑顺序为:首先列出节点中所有的Taint,然后忽略Pod的Toleration能够匹配的部分,剩下的没有忽略的Taint就是对Pod的效果了。下面是几种特殊情况。

  • 如果在剩余的Taint中存在effect=NoSchedule,则调度器不会把该Pod调度到这一节点上。
  • 如果在剩余的Taint中没有NoSchedule效果,但是有PreferNoSchedule效果,则调度器会尝试不把这个Pod指派给这个节点。
  • 如果在剩余的Taint中有NoExecute效果,并且这个Pod已经在该节点上运行,则会被驱逐;如果没有在该节点上运行,则也不会再被调度到该节点上。

例如,我们这样对一个节点进行Taint设置:

$ kubectl taint nodes node1key1=value1:NoSchedule $ kubectl taint nodes node1key1=value1:NoExecute $ kubectl taint nodes node1key2=value2:NoSchedule

然后在Pod上设置两个Toleration:

apiVersion: v1 kind: Pod metadata: name: pod-with-multiple-tolerations spec: tolerations:# 容忍带有 key1=value1 且效果为 NoSchedule 的污点- key:"key1"operator:"Equal"value:"value1"effect:"NoSchedule"# 容忍带有 key1=value1 且效果为 NoExecute 的污点- key:"key1"operator:"Equal"value:"value1"effect:"NoExecute"containers: - name: nginx image: nginx

这样的结果是该Pod无法被调度到node1上,这是因为第3个Taint没有匹配的Toleration。但是如果该Pod已经在node1上运行了,那么在运行时设置第3个Taint,它还能继续在node1上运行,这是因为Pod可以容忍前两个Taint。

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

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

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

Taint和Toleration是一种处理节点并且让Pod进行规避或者驱逐Pod的弹性处理方式,下面列举一些常见的用例。

  • 1.独占节点
    如果想要拿出一部分节点专门给一些特定应用使用,则可以为节点添加这样的Taint:

    $ kubectl taint nodes nodenamededicated=groupName:NoSchedule

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

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

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

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

    $ kubectl taint nodes nodenamespecial=true:NoSchedule $ kubectl taint nodes nodenamespecial=true:PreferNoSchedule

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

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

  • 3.定义Pod驱逐行为,以应对节点故障(为Alpha版本的功能)
    前面提到的NoExecute这个Taint效果对节点上正在运行的Pod有以下影响。

    • 没有设置Toleration的Pod会被立刻驱逐。
    • 配置了对应Toleration的Pod,如果没有为tolerationSeconds赋值,则会一直留在这一节点中。
    • 配置了对应Toleration的Pod且指定了tolerationSeconds值,则会在指定时间后驱逐。
    • Kubernetes从1.6版本开始引入一个Alpha版本的功能,即把节点故障标记为Taint(目前只针对nodeunreachable及node not ready,相应的NodeCondition "Ready"的值分别为Unknown和False)​。激活TaintBasedEvictions功能后(在–feature-gates参数中加入TaintBasedEvictions=true)​,NodeController会自动为Node设置Taint,而在状态为Ready的Node上,之前设置过的普通驱逐逻辑将会被禁用。注意,在节点故障的情况下,为了保持现存的Pod驱逐的限速(rate-limiting)设置,系统将会以限速的模式逐 步给Node设置Taint,这就能避免在一些特定情况下(比如Master暂时失联)大量的Pod被驱逐。这一功能兼容于tolerationSeconds,允许Pod定义节点故障时持续多久才被逐出。

    例如,一个包含很多本地状态的应用可能需要在网络发生故障时,还能持续在节点上运行,期望网络能够快速恢复,从而避免被从这个节点上驱逐。

    Pod的Toleration可以这样定义:

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

    对于Node未就绪状态,可以把Key设置为node.alpha.kubernetes.io/notReady。

    如果没有为Pod指定node.alpha.kubernetes.io/notReady的Toleration,那么Kubernetes会自动为Pod加入tolerationSeconds=300的node.alpha.kubernetes.io/notReady类型的Toleration。

    同样,如果Pod没有定义node.alpha.kubernetes.io/unreachable的Toleration,那么系统会自动为其加入tolerationSeconds=300的node.alpha.kubernetes.io/unreachable类型的Toleration。

这些系统自动设置的toleration在Node发现问题时,能够为Pod确保驱逐前再运行5min。这两个默认的Toleration由Admission Controller“DefaultTolerationSeconds”自动加入。

9.6、Pod Priority Preemption:Pod优先级调度

对于运行各种负载(如Service、Job)的中等规模或者大规模的集群来说,出于各种原因,我们需要尽可能提高集群的资源利用率。而提高资源利用率的常规做法是采用优先级方案,即不同类型的负载对应不同的优先级,同时允许集群中的所有负载所需的资源总量超过集群可提供的资源,在这种情况下,当发生资源不足的情况时,系统可以选择释放一些不重要的负载(优先级最低的)​,保障最重要的负载能够获取足够的资源稳定运行。

在Kubernetes 1.8版本之前,当集群的可用资源不足时,在用户提交新的Pod创建请求后,该Pod会一直处于Pending状态,即使这个Pod是一个很重要(很有身份)的Pod,也只能被动等待其他Pod被删除并释放资源,才能有机会被调度成功。Kubernetes 1.8版本引入了基于Pod优先级抢占(Pod Priority Preemption)的调度策略,此时Kubernetes会尝试释放目标节点上低优先级的Pod,以腾出空间(资源)安置高优先级的Pod,这种调度方式被称为“抢占式调度”​。在Kubernetes 1.11版本中,该特性升级为Beta版本,默认开启,在后继的Kubernetes 1.14版本中正式Release。如何声明一个负载相对其他负载“更重要”​?我们可以通过以下几个维度来定义:

  • Priority,优先级;
  • QoS,服务质量等级;
  • 系统定义的其他度量指标。

优先级抢占调度策略的核心行为分别是驱逐(Eviction)与抢占(Preemption)​,这两种行为的使用场景不同,效果相同。

  • Eviction是kubelet进程的行为,即当一个Node发生资源不足(under resource pressure)的情况时,该节点上的kubelet进程会执行驱逐动作,此时Kubelet会综合考虑Pod的优先级、资源申请量与实际使用量等信息来计算哪些Pod需要被驱逐;当同样优先级的Pod需要被驱逐时,实际使用的资源量超过申请量最大倍数的高耗能Pod会被首先驱逐。对于QoS等级为“BestEffort”的Pod来说,由于没有定义资源申请(CPU/Memory Request)​,所以它们实际使用的资源可能非常大。
  • Preemption则是Scheduler执行的行为,当一个新的Pod因为资源无法满足而不能被调度时,Scheduler可能(有权决定)选择驱逐部分低优先级的 Pod实例来满足此Pod的调度目标,这就是Preemption机制。

需要注意的是,Scheduler可能会驱逐Node A上的一个Pod以满足Node B上的一个新Pod的调度任务。比如下面的这个例子:

一个低优先级的Pod A在Node A(属于机架R)上运行,此时有一个高优先级的Pod B等待调度,目标节点是同属机架R的Node B,他们中的一个或全部都定义了anti-affinity规则,不允许在同一个机架上运行,此时Scheduler只好“丢车保帅”​,驱逐低优先级的Pod A以满足高优先级的Pod B的调度。

Pod优先级调度示例如下。

首先,由集群管理员创建PriorityClasses,PriorityClass不属于任何命名空间:

apiVersion:scheduling.k8s.io/v1kind:PriorityClass# 资源类型:优先级类metadata:name:high-priority# PriorityClass 的名称,Pod 可以通过 spec.priorityClassName 引用它value:1000000# 优先级数值,值越大优先级越高(通常系统组件使用数十亿的值,业务最高建议设置在百万级别)globalDefault:false# 是否设为集群的默认优先级。false 表示不会自动应用到没有指定优先级的 Pod 上description:"This priority class should be used for XYZ service pods only."# 对该优先级类的描述说明

上述YAML文件定义了一个名为high-priority的优先级类别,优先级为100000,数字越大,优先级越高,超过一亿的数字被系统保留,用于指派给系统组件。

我们可以在任意Pod中引用上述Pod优先级类别:

apiVersion:v1kind:Podmetadata:name:nginx# Pod 的名称labels:env:test# 为 Pod 打上的标签(环境为测试环境)spec:containers:-name:nginx# 容器名称image:nginx# 使用的镜像名称imagePullPolicy:IfNotPresent# 镜像拉取策略:如果本地存在该镜像则优先使用本地镜像,否则才去镜像仓库拉取priorityClassName:high-priority# 引用前面定义的高优先级类,让该 Pod 在节点资源紧张时具备优先调度或抢占资源的资格

如果发生了需要抢占的调度,高优先级Pod就可能抢占节点N,并将其低优先级Pod驱逐出节点N,高优先级Pod的status信息中的nominatedNodeName字段会记录目标节点N的名称。需要注意,高优先级Pod仍然无法保证最终被调度到节点N上,在节点N上低优先级Pod被驱逐的过程中,如果有新的节点满足高优先级Pod的需求,就会把它调度到新的Node上。而如果在等待低优先级的Pod退出的过程中,又出现了优先级更高的Pod,调度器将会调度这个更高优先级的Pod到节点N上,并重新调度之前等待的高优先级Pod。

优先级抢占的调度方式可能会导致调度陷入“死循环”状态。当Kubernetes集群配置了多个调度器(Scheduler)时,这一行为可能就会发生,比如下面这个例子:

Scheduler A为了调度一个(批)Pod,特地驱逐了一些Pod,因此在集群中有了空余的空间可以用来调度,此时Scheduler B恰好抢在Scheduler A之前调度了一个新的Pod,消耗了相应的资源,因此,当Scheduler A清理完资源后正式发起Pod的调度时,却发现资源不足,被目标节点的kubelet进程拒绝了调度请求!这种情况的确无解,因此最好的做法是让多个Scheduler相互协作来共同实现一个目标。

最后要指出一点:使用优先级抢占的调度策略可能会导致某些Pod永远无法被成功调度。因此优先级调度不但增加了系统的复杂性,还可能带来额外不稳定的因素。因此,一旦发生资源紧张的局面,首先要考虑的是集群扩容,如果无法扩容,则再考虑有监管的优先级调度特性,比如结合基于Namespace的资源配额限制来约束任意优先级抢占行为。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 10:40:25

大模型开发入门指南:小白也能学会,高薪就业全解析(收藏版)

本文详细介绍了大模型开发的工作内容、学习路径、就业前景及薪资水平。大模型开发工程师负责优化通用大模型以满足企业需求,应用场景广泛,就业选择多样。学习核心技能包括大模型基础原理、提示词工程、模型微调与应用部署、行业业务场景落地能力。入行条…

作者头像 李华
网站建设 2026/11/3 10:36:26

使用Linux系统部署.Net程序

与Windows系统部署.Net程序作对比: 部署环节WindowsLinux发布程序Visual Studio 发布 / dotnet publish相同上传文件远程桌面复制SCP / WinSCP安装运行环境.NET Hosting BundleASP.NET Core Runtime,或使用自包含发布WebApi 运行IIS ASP.NET Core Modu…

作者头像 李华
网站建设 2026/11/3 10:36:07

海外版外卖系统:对账表下载之后为什么和后台对不上

做海外版外卖系统,财务把对账表下载下来,和后台屏幕上的合计对不上,先不要改金额。多数是两边用的条件不一样:一座城还是全部城、含不含试单、含不含未付款、截止到哪一天。条件不同,数字就不会相同。一、对不上时先对…

作者头像 李华
网站建设 2026/11/3 10:29:07

智能助手总览

企业智能助手 来源地址:https://gitee.com/zhu_xin/ai-serve-desk 架构总览 一、项目定位 一个面向企业内部的 LLM 智能中台: 能力说明知识问答基于知识库的 RAG 检索,回答 WiFi、VPN、规章制度等问题文档同步接收飞书/钉钉文档变更 Web…

作者头像 李华