kubernetes | 调度器

2022年3月17日 · 7210 字 · 15 分钟 · Kubernetes

一、概述

一个容器平台的主要功能就是为容器分配运行时所需要的计算,存储和网络资源。容器调度系统负责选择在最合适的主机上启动容器,并且将它们关联起来。它必须能够自动的处理容器故障并且能够在更多的主机上自动启动更多的容器来应对更多的应用访问。
目前三大主流的容器平台 Swarm, Mesos 和 Kubernetes 具有不同的容器调度系统。

  • Swarm 的特点是直接调度 Docker 容器,并且提供和标准 Docker API 一致的 API。
  • Mesos 针对不同的运行框架采用相对独立的调度系统,其中 Marathon 框架提供了 Docker 容器的原生支持。
  • Kubernetes 则采用了 Pod 和 Label 这样的概念把容器组合成一个个的互相存在依赖关系的逻辑单元。相关容器被组合成 Pod 后被共同部署和调度,形成服务(Service)。

这个是 Kubernetes 和 Swarm,Mesos 的主要区别。
相对来说,Kubernetes 采用这样的方式简化了集群范围内相关容器被共同调度管理的复杂性。换一种角度来看,Kubernetes 采用这种方式能够相对容易的支持更强大,更复杂的容器调度算法。

二、k8s 调度工作方式

Kubernetes 调度器作为集群的大脑,在如何提高集群的资源利用率、保证集群中服务的稳定运行中也会变得越来越重要。
Kubernetes 的资源分为两种属性。

  • 可压缩资源(例如 CPU 循环,Disk I/O 带宽)都是可以被限制和被回收的,对于一个 Pod 来说可以降低这些资源的使用量而不去杀掉 Pod。
  • 不可压缩资源(例如内存、硬盘空间)一般来说不杀掉 Pod 就没法回收。未来 Kubernetes 会加入更多资源,如网络带宽,存储 IOPS 的支持。

三、k8s 调度器

3.1、kube-scheduler

kube-scheduler 是 kubernetes 系统的核心组件之一,主要负责整个集群资源的调度功能,根据特定的调度算法和策略,将 Pod 调度到最优的工作节点上面去,从而更加合理、更加充分的利用集群的资源,这也是选择使用 kubernetes 一个非常重要的理由。

3.2、调度流程

默认情况下,kube-scheduler 提供的默认调度器能够满足我们绝大多数的要求,之前接触的示例也基本上用的 默认的策略,都可以保证我们的 Pod 可以被分配到资源充足的节点上运行。但是在实际的线上项目中,可能我们自己会比 kubernetes 更加了解我们自己的应用,比如我们希望一个 Pod 只能运行在特定的几个节点上,或者这几个节点只能用来运行特定类型的应用,这就需要我们的调度器能够可控。

kube-scheduler 是 kubernetes 的调度器,它的主要作用就是根据特定的调度算法和调度策略将 Pod 调度到合适的 Node 节点上去,是一个独立的二进制程序,启动之后会一直监听 API Server,获取到 PodSpec.NodeName 为空的 Pod,对每个 Pod 都会创建一个 binding。

调度主要分为以下几个部分:

  • 首先是预选过程,过滤掉不满足条件的节点,这个过程称为 Predicates。
  • 然后是优选过程,对通过的节点按照优先级排序,称之为 Priorities。
  • 最后从中选择优先级最高的节点,如果中间任何一步骤有错误,就直接返回错误。

3.2.1、Predicates 阶段

Predicates 阶段 首先遍历全部节点,过滤掉不满足条件的节点,属于强制性规则,这一阶段输出的所有满足要求的 Node 将被记录并作为第二阶段的输入,如果所有的节点都不满足条件,那么 Pod 将会一直处于 Pending 状态,直到有节点满足条件,在这期间调度器会不断的重试。
所以我们在部署应用的时候,如果发现有 Pod 一直处于 Pending 状态,那么就是没有满足调度条件的节点,这个时候可以去检查下节点资源是否可用。

3.2.2、Priorities 阶段

Priorities 阶段 即再次对节点进行筛选,如果有多个节点都满足条件的话,那么系统会按照节点的优先级 (priorites) 大小对节点进行排序,最后选择优先级最高的节点来部署 Pod 应用。
下面是调度过程的简单示意图:


更详细的流程是这样的:
首先,客户端通过 API Server 的 REST API 或者 kubectl 工具创建 Pod 资源。 API Server 收到用户请求后,存储相关数据到 etcd 数据库中。
调度器监听 API Server 查看为调度 (bind) 的 Pod 列表,循环遍历地为每个 Pod 尝试分配节点,这个分配过程就是我们上面提到的两个阶段:

  • 预选阶段 (Predicates),过滤节点,调度器用一组规则过滤掉不符合要求的 Node 节点, 比如 Pod 设置了资源的 request,那么可用资源比 Pod 需要的资源少的主机显然就会被 过滤掉。
  • 优选阶段 (Priorities),为节点的优先级打分,将上一阶段过滤出来的 Node 列表进行打 分,调度器会考虑一些整体的优化策略,比如把 Deployment 控制的多个 Pod 副本分布到 不同的主机上,使用最低负载的主机等等策略。

经过上面的阶段过滤后选择打分最高的 Node 节点和 Pod 进行 binding 操作,然后将结果存储到 etcd 中。 最后被选择出来的 Node 节点对应的 kubelet 去执行创建 Pod 的相关操作。

其中 Predicates 过滤有一系列的算法可以使用,这里简单列举几个:

  • PodFitsResources 节点上剩余的资源是否大于 Pod 请求的资源。
  • PodFitsHost 如果 Pod 指定了 NodeName,检查节点名称是否和 NodeName 匹配。
  • PodFitsHostPorts 节点上已经使用的 port 是否和 Pod 申请的 port 冲突。
  • PodSelectorMatches 过滤掉和 Pod 指定的 label 不匹配的节点。
  • NoDiskConflict 已经 mount 的 volume 和 Pod 指定的 volume 不冲突,除非它们都是只读的。
  • CheckNodeDiskPressure 检查节点磁盘空间是否符合要求。
  • CheckNodeMemoryPressure 检查节点内存是否够用。

除了这些过滤算法之外,还有一些其他的算法,更多更详细的可以查看源码文件 predicates.go。

而 Priorities 优先级是由一系列键值对组成的,键是该优先级的名称,值是它的权重值,同样,我们这里给大家列举几个具有代表性的选项:

  • LeastRequestedPriority 通过计算 CPU 和内存的使用率来决定权重,使用率越低权重越 高,当然正常肯定也是资源是使用率越低权重越高,能给别的 Pod 运行的可能性就越大。
  • SelectorSpreadPriority 为了更好的高可用,对同属于一个 Deployment 或者 RC 下面 的多个 Pod 副本,尽量调度到多个不同的节点上,当一个 Pod 被调度的时候,会先去查 找该 Pod 对应的 controller,然后查看该 controller 下面的已存在的 Pod,运行 Pod 越少的节点权重越高。
  • ImageLocalityPriority 就是如果在某个节点上已经有要使用的镜像节点了,镜像总大小值越大,权重就越高。
  • NodeAffinityPriority 这个就是根据节点的亲和性来计算一个权重值,后面我们会详细讲解亲和性的使用方法。

四、调度器示例

4.1、固定节点调度

指定调度节点: Pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上,会跳过 Scheduler 的调度策略,该匹配规则是强制匹配。

点击查看完整的 scheduler-deploy.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: scheduler-deploy
spec:
  selector:
    matchLabels:
      app: scheduler-deploy
  replicas: 7
  template:
    metadata:
      labels:
        app: scheduler-deploy
    spec:
      nodeName: k8s-node01		# 指定运行的节点名称
      containers:
      - name: scheduler-deploy
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

操作

# 查看创建的 deployment
kubectl get deploy
   
# 查看 pod 是否调度到指定节点上。
kubectl get pod -o wide

4.2、通过 label-selector 机制选择节点

Pod.spec.nodeSelector 通过 kubernetes 的 label-selector 机制选择节点,由调度器调度策略匹配 label,而后调度 Pod 到目标节点,该匹配规则属于强制约束。

# 给 node 添加标签
kubectl label node k8s-node01 app=selector
    
# 查看 node 的标签
kubectl get node --show-labels

点击查看完整的 scheduler-selector-deploy.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: scheduler-selector-deploy
spec:
  selector:
    matchLabels:
      app: scheduler-selector-deploy
  replicas: 20
  template:
    metadata:
      labels:
        app: scheduler-selector-deploy
    spec:
      nodeSelector:
        app: selector		# 匹配标签为 app: selector 的节点
      containers:
      - name: scheduler-selector-pod
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

操作

kubectl create -f scheduler-selector-deploy.yaml
 
kubectl get deploy

# 查看 pod 的调度情况
kubectl get pod -o wide

五、节点调度亲和性

节点亲和性规则:硬亲和性 required 、软亲和性 preferred。
硬亲和性规则不满足时,Pod 会置于 Pending 状态,软亲和性规则不满足时,会选择一个不匹配的节点。当节点标签改变而不再符合此节点亲和性规则时,不会将 Pod 从该节点移出,仅对新建的 Pod 对象生效。

5.1、节点硬亲和性

requiredDuringSchedulingIgnoredDuringExecution
方式一:Pod 使用 spec.nodeSelector (基于等值关系)
方式二:Pod 使用 spec.affinity 支持 matchExpressions 属性 (复杂标签选择机制)
kubectl label nodes kube-node1 zone=foo
调度至 zone = foo 的节点

点击查看完整的 myapp-with-required-nodeaffinity.yml
apiVersion: v1
kind: Pod
metadata:
  name: myapp-with-required-nodeaffinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  # 定义硬亲和性
        nodeSelectorTerms:
          - matchExpressions:  # 集合选择器
              - key: zone
                operator: In
                values: ["foo"]
  containers:
    - name: myapp
      image: ikubernetes/myapp:v1

强制性约束

requiredDuringSchedulingIgnoredDuringExecution,这在 K8s 中被称为“硬亲和性”:

  • 调度阶段(Required):如果集群中没有任何一个节点的标签满足 zone=foo,那么这个 Pod 将永远无法被调度,状态会一直保持为 Pending。
  • 执行阶段(Ignored):如果 Pod 已经运行在某个节点上,而此时该节点的标签被删除了,Pod 不会被驱逐,会继续运行。

为什么不直接用 nodeSelector

虽然 nodeSelector 也能实现同样的功能,但 Node Affinity 具备以下优势:

  • 逻辑组合:支持 In, NotIn, Exists 等复杂逻辑,而 nodeSelector 只能做简单的等值匹配。
  • 软约束支持:除了硬亲和性,它还支持“软亲和性”(Preferred),即“尽量放到 zone=foo,如果没有,放到别的节点也行”。

5.2、节点软亲和性

preferredDuringSchedulingIgnoredDuringExecution
柔性控制逻辑,当条件不满足时,能接受被编排于其他不符合条件的节点之上。
权重 weight 定义优先级,1-100 值越大优先级越高。
如果说“硬亲和性”是必须执行的死命令,那么“软亲和性”就是带有权重的建议。调度器会尽力满足这些条件,但如果实在满足不了(比如没有对应的节点),Pod 依然会被调度到其他节点运行,而不会卡在 Pending 状态。

点击查看完整的 myapp-deploy-with-node-affinity.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy-with-node-affinity
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      name: myapp-pod
      labels:
        app: myapp
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:  # 节点软亲和性
            - weight: 60
              preference:
                matchExpressions:
                  - key: zone
                    operator: In
                    values: ["foo"]
            - weight: 30
              preference:
                matchExpressions:
                  - key: ssd
                    operator: Exists
                    values: []
      containers:
        - name: myapp
          image: ikubernetes/myapp:v1

核心机制

调度器在处理 preferredDuringSchedulingIgnoredDuringExecution 时,会通过一个“打分插件”来决定 Pod 落在哪里:

  • 扫描节点:调度器查看集群中所有通过了基本过滤(如资源充足)的节点。
  • 累加权重:对于每一个节点,如果它满足某个 preference 条件,就加上对应的 weight。
  • 择优录取:最后得分最高的节点将被选中。

六、Pod 资源亲和调度

Pod 对象间亲和性,将一些 Pod 对象组织在相近的位置 (同一节点、机架、区域、地区)。
Pod 对象间反亲和性,将一些 Pod 在运行位置上隔开。

6.1、Pod 硬亲和调度

requiredDuringSchedulingIgnoredDuringExecution
Pod 亲和性描述一个 Pod 与具有某特征的现存 Pod 运行位置的依赖关系;即需要事先存在被依赖的 Pod 对象。
与之前的 Node Affinity(针对节点标签)不同,Pod Affinity 是针对 Pod 标签的调度逻辑。它让你可以告诉 Kubernetes:“把这个新 Pod 放在已经运行了某个特定 Pod 的‘附近’”。
被依赖 Pod:
kubectl run tomcat -l app=tomcat --image tomcat:alpine
查看配置说明:
这会告诉你该字段是必填的。因为没有拓扑域,K8s 就不知道“在一起”的范围到底是同一台电脑、同一个机柜还是同一个国家。
kubectl explain pod.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.topologyKey

点击查看完整的 with-pod-affinity.yml
apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  # 硬亲和调度
        - labelSelector:
            matchExpressions:  # 集合选择器
              - key: app
                operator: In
                values: ["tomcat"]  # 选择被依赖 Pod
                # 上面意思是,当前 pod 要跟标签为 app 值为 tomcat 的 pod 在一起
            topologyKey: kubernetes.io/hostname  # 根据挑选出的 Pod 所有节点的 hostname 作为同一位置的判定
  containers:
    - name: myapp
      image: ikubernetes/myapp:v1

核心逻辑

配置的是 requiredDuringSchedulingIgnoredDuringExecution(硬亲和性):

  • 规则:新 Pod with-pod-affinity 在调度时,必须找到一个满足条件的节点。
  • 条件:该节点所在的“区域”(由 topologyKey 定义)内,必须已经运行了一个带 app=tomcat 标签的 Pod。
  • 后果:如果集群里没有 app=tomcat 的 Pod,或者对应的节点资源满了,这个新 Pod 会一直处于 Pending 状态。

深度理解 topologyKey(拓扑域)

这是 Pod 亲和性中最容易理解偏的概念。topologyKey 定义了什么是“在一起”:

  • kubernetes.io/hostname(当前使用的):
    表示“同一个节点”。调度器会查找 tomcat Pod 在哪个具体的 Node 上,然后把新 Pod 也塞进同一个 Node。
  • topology.kubernetes.io/zone:
    表示“同一个可用区”。如果 tomcat 在机房 A,那么新 Pod 只要落在机房 A 的任何一台机器上都算满足条件。
  • kubernetes.io/os:
    表示“同一种操作系统”。比如 tomcat 在 Linux 节点上,新 Pod 只要也去 Linux 节点就行(这通常范围太广,不常用)。

为什么需要 Pod 亲和性

在复杂的分布式架构中,这通常为了解决网络延迟或数据传输效率:

  • 应用与缓存:将 Web 应用 Pod 调度到 Redis 缓存 Pod 所在的同一台物理机上,通过本地回环或极低延迟的网卡进行通信,提升响应速度。
  • 应用与数据库:将业务逻辑 Pod 尽可能靠近数据库 Pod 部署。
  • 协同组件:主程序与配套的日志收集、监控 sidecar(如果不是以 Sidecar 模式运行的话)。

潜在风险

单点故障:如果你把相关的 Pod 全都通过亲和性挤在同一个节点上,万一这台物理机断电,你的整套服务都会同时挂掉。
调度死锁:如果 A 亲和 B,B 亲和 A,且两者都没运行,那么它们可能永远都跑不起来。

6.2、Pod 软亲和调度

Pod 软亲和性(Preferred Pod Affinity) 的复杂用法,通过权重系统,让调度器在做决策时不仅考虑“能不能跑”,还要考虑“在哪跑性能最好”。

点击查看完整的 myapp-with-preferred-pod-affinity.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-with-preferred-pod-affinity
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      name: myapp
      labels:
        app: myapp
    spec:
      affinity:
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 80
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                    - key: app
                      operator: In
                      values: ["cache"]
                topologyKey: zone
            - weight: 20
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                    - key: app
                      operator: In
                      values: ["db"]
                topologyKey: zone
      containers:
        - name: myapp
          image: ikubernetes/myapp:v1

为什么使用软亲和性而非硬亲和性

在生产环境中,软亲和性更具弹性:

  • 防止 Pending 死锁:如果是硬亲和性,万一 cache Pod 还没启动或所在的 zone 挂了,你的 myapp 将永远无法启动。软亲和性保证了“最佳性能优先,基础可用保底”。
  • 优雅降级:如果高性能区域(靠近缓存的区域)资源耗尽,Pod 可以自动溢出到其他区域,虽然访问缓存变慢了,但业务不会中断。

6.3、Pod 反亲和调度

Pod 反亲和调度用于分散同一类应用,调度至不同的区域、机架或节点等将 spec.affinity.podAffinity 替换为 spec.affinity.podAntiAffinity。
反亲和调度也分为柔性约束和强制约束。
Pod 反亲和性 (Pod Anti-Affinity) 的硬约束用法。这在 Kubernetes 调度中被称为“互斥逻辑”,即告诉调度器:“不要把这个 Pod 放在已经运行了特定标签 Pod 的地方。”

点击查看完整的 anti-affinity.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  labels:
    app: myapp
    tier: fronted
spec:
  containers:
    - name: myapp
      image: ikubernetes/myapp:v1
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  labels:
    app: backend
    tier: db
spec:
  containers:
    - name: busybox
      image: busybox:latest
      imagePullPolicy: IfNotPresent
      command: ["/bin/sh", "-c", "sleep 3600"]
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
              - key: app
                operator: In
                values: ["myapp"]
          topologyKey: zone

为什么需要 Pod 反亲和性

在企业级生产环境中,这通常出于两个目的:

  • 高可用 (High Availability):
    避免“单点故障”。如果你有两个 Nginx 副本,通过反亲和性强迫它们分布在不同节点或不同机房。这样即使一台物理机宕机或一个机房断电,另一个副本依然存活。
  • 资源竞争规避:
    有些应用(如大型数据库或复杂的计算任务)非常消耗 CPU 或内存。你可以设置反亲和性,防止这些“大户”挤在同一台物理机上互相抢资源。

七、污点和容忍度

污点 taints 是定义在节点上的键值型属性数据,用于让节点拒绝将 Pod 调度运行于其上,除非 Pod 有接纳节点污点的容忍度容忍度 tolerations 是定义在 Pod 上的键值属性数据, 用于配置可容忍的污点,且调度器将 Pod 调度至其能容忍该节点污点的节点上或没有污点的节点上
使用 PodToleratesNodeTaints 预选策略和 TaintTolerationPriority 优选函数完成该机制。
节点亲和性使得 Pod 对象被吸引到一类特定的节点 (nodeSelector 和 affinity)。
污点提供让节点排斥特定 Pod 对象的能力。

7.1、定义污点和容忍度

污点定义于 nodes.spec.taints 容忍度定义于 pods.spec.tolerations 语法:key=value:effect

7.2、effect 定义排斥等级

  • NoSchedule 不能容忍,但仅影响调度过程,已调度上去的 pod 不受影响,仅对新增加的 pod 生效。
  • PreferNoSchedule 柔性约束,节点现存 Pod 不受影响,如果实在是没有符合的节点,也可以调度上来。
  • NoExecute 不能容忍,当污点变动时,Pod 对象会被驱逐。

7.3、在 Pod 上定义容忍度时

等值比较容忍度与污点在 key、value、effect 三者完全匹配。
存在性判断 key、effect 完全匹配,value 使用空值。
一个节点可配置多个污点,一个 Pod 也可有多个容忍度。

7.4、管理节点的污点

同一个键值数据,effect 不同,也属于不同的污点。
给节点添加污点:

kubectl taint node <node-name><key>=<value>:<effect>
kubectl taint node node2 node-type=production:NoShedule #举例

查看节点污点:

kubectl get nodes <nodename> -o go-template={{.spec.taints}}

删除节点污点:

kubectl taint node <node-name><key>[:<effect>]
kubectl patch nodes <node-name> -p '{"spec":{"taints":[]}}'
kubectl taint node kube-node1 node-type=production:NoSchedule
kubectl get nodes kube-node1 -o go-template={{.spec.taints}}

删除 key 为 node-type,effect 为 NoSchedule 的污点

kubectl taint node kube-node1 node-type:NoSchedule

删除 key 为 node-type 的所有污点

kubectl taint node kube-node1 node-type

删除所有污点

kubectl patch nodes kube-node1 -p '{"spec":{"taints":[]}}'

给 Pod 对象容忍度

spec.tolerations 字段添加
tolerationSeconds 用于定义延迟驱逐 Pod 的时长

等值判断

tolerations:
  - key: "key1"  # 判断条件为 Equal
    operator: "Equal"
    value: "value1"
    effect: "NoExecute"
    tolerationSeconds: 3600

如果说 Affinity(亲和性) 是 Pod 主动选择去哪个节点,那么 Taints(污点) 和 Tolerations(容忍度) 就是节点选择“拒绝”哪些 Pod。只有拥有对应“许可证”的 Pod,才能被允许部署在带有污点的节点上。

点击查看完整的 myapp-deploy.yml
apiVersion: v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      release: canary
  template:
    metadata:
      labels:
        app: myapp
        release: canary
    spec:
      containers:
        - name: myapp
          image: ikubernetes/myapp:v1
          ports:
            - name: http
              containerPort: 80
      tolerations:
        - key: "key1"
          operator: "Exists"  # 存在性判断,只要污点键存在,就可以匹配
          effect: "NoExecute"
          tolerationSeconds: 3600
        - key: "node-type"
          operator: "Equal"
          value: "production"
          effect: "NoExecute"
          tolerationSeconds: 3600

核心逻辑:突破排斥反应

  • 污点 (Taint):打在节点上。它告诉 Kubernetes:“除非你有特殊的容忍度,否则离我远点。”
  • 容忍度 (Toleration):写在 Pod 上。它告诉 Kubernetes:“我不怕那个污点,我可以住在那。”

配置细节

  • A. 存在性匹配 (operator: “Exists”)
    • 配置:key: “key1”, effect: “NoExecute”
    • 逻辑:只要节点上有一个污点的键是 key1,不管它的值(Value)是什么,这个 Pod 都能容忍它。
    • 作用:非常适合用于处理通用的节点状态,比如节点由于某种原因被标记为 key1 类别。
  • B. 精确值匹配 (operator: “Equal”)
    • 配置:key: “node-type”, value: “production”, effect: “NoExecute”。
    • 逻辑:只有当节点上的污点完全匹配 node-type=production:NoExecute 时,Pod 才能容忍。
    • 作用:常用于专用节点隔离。例如,生产环境节点(Production Nodes)不允许测试流量进入,只有带有该容忍度的生产应用才能部署上去。

问题节点标识

在大型企业生产环境中,这相当于集群的“生物防御系统”。当物理节点出现故障(如硬盘爆满、网络断开)时,控制平面会自动给该节点“贴标签”,防止新的 Pod 掉进火坑,并根据策略驱逐已有的 Pod。
自动为节点添加污点信息,使用 NoExecute 效用标识,会驱逐现有 Pod。
K8s 核心组件通常都容忍此类污点

  • node.kubernetes.io/not-ready 节点进入 NotReady 状态时自动添加。
  • node.alpha.kubernetes.io/unreachable 节点进入 NotReachable 状态时自动添加。
  • node.kubernetes.io/out-of-disk 节点进入 OutOfDisk 状态时自动添加。
  • node.kubernetes.io/memory-pressure 节点内存资源面临压力。
  • node.kubernetes.io/disk-pressure 节点磁盘面临压力。
  • node.kubernetes.io/network-unavailable 节点网络不可用。
  • node.cloudprovider.kubernetes.io/uninitialized kubelet 由外部云环境程序启动时,自动添加,待到去控制器初始化此节点时再将其删除。

Pod 优选级和抢占式调度

优选级,Pod 对象的重要程度。
优选级会影响节点上 Pod 的调度顺序和驱逐次序。
一个 Pod 对象无法被调度时,调度器会尝试抢占 (驱逐) 较低优先级的 Pod 对象,以便可以调度当前 Pod。

Pod 优选级和抢占机制默认处于禁用状态:
启用:同时为 kube-apiserver、kube-scheduler、kubelet 程序的 --feature-gates 添加 PodPriority=true。
使用:事先创建优先级类别,并在创建 Pod 资源时通过 priorityClassName 属性指定所属优选级类别。