Kubernetes 入门教程之六

大纲

Kubernetes 核心技术

Probe

为了监控容器的运行状态,Kubernetes 提供了探针(Probe)。

Probe 的类型

Kubernetes 提供了三种类型的探针:Liveness Probe(存活探针)、Readiness Probe(就绪探针)、Startup Probe(启动探针)。

Liveness Probe

Liveness Probe(存活探针)用于判断容器是否处于健康状态,即 Pod 是否真正处于 Running 状态。如果 Liveness Probe 探测到容器不健康,kubelet 会将该容器 Kill 掉,并根据 Pod 的重启策略决定是否重启它。Liveness Probe 可用于修复死锁、无响应的应用(如数据库卡死)。如果容器未配置 Liveness Probe,kubelet 会默认认为其探测结果始终为成功。在实际场景中,应用程序可能由于某些原因(例如后端服务故障)暂时无法对外提供服务,但进程本身仍在运行。这种情况下,Kubernetes 无法识别并隔离这个有故障的 Pod,调用方仍可能访问到该 Pod,导致业务不稳定。为解决这一问题,Kubernetes 提供了 Liveness Probe 来检测应用程序的运行健康状况,并在检测到异常时执行相应的补救措施,例如重启容器,以保证系统的整体稳定性。Liveness Probe 的配置示例如下:

1
2
3
4
5
6
livenessProbe:
exec:
command: ["cat", "/tmp/healthy"] # 执行命令检查文件是否存在
initialDelaySeconds: 5 # 容器启动后等待5秒开始检查
periodSeconds: 5 # 每5秒检查一次
failureThreshold: 3 # 连续失败3次后判定为不健康
Readiness Probe

Readiness Probe(就绪探针)用于判断容器是否已经启动完成并能够对外提供服务,即容器的 Ready 状态是否为 true如果 Readiness Probe 探测失败,容器的 Ready 状态会被置为 False,Kubernetes 控制器会将该 Pod 的 Endpoint 从对应 Service 的 Endpoint 列表中移除,从而停止将任何请求调度到该 Pod,直到下一次探测成功为止。Readiness Probe 可用于控制流量进入(如应用启动时需要加载大量数据,导致容器启动后无法立刻对外提供服务)。通过 Readiness Probe,Kubernetes 可以在应用完全就绪之前,阻止流量被路由到尚未准备好的 Pod 副本,确保服务稳定性。例如,对于基于 Tomcat 的应用来说,Tomcat 进程启动成功并不代表应用可以立即对外提供服务,可能还需要等待 Spring 容器初始化、数据库连接建立等操作完成。在 Spring Boot 应用中,可以使用 Actuator 提供的 /health 接口作为 Readiness Probe 的检测目标,用于判断应用是否已经准备好对外提供服务。Readiness Probe 的配置示例如下:

1
2
3
4
5
6
7
readinessProbe:
httpGet:
path: /healthz # 发送 HTTP 请求进行检测
port: 8080
initialDelaySeconds: 10 # 容器启动后等待10秒开始检查
periodSeconds: 3 # 每3秒检查一次
successThreshold: 1 # 成功1次即标记为就绪
Startup Probe

Startup Probe(启动探针)是在 Kubernetes 1.16+ 版本中引入的,主要用于检测慢启动应用是否完成初始化。在 Startup Probe 检测成功之前,Liveness Probe 和 Readiness Probe 都不会生效;从而避免因应用启动过慢,被存活探针或就绪探针误判为异常并提前终止容器。Startup Probe 非常适合启动时间较长的应用,例如 Java / SpringBoot 应用、需要加载大量数据或复杂初始化逻辑的服务。通过配置合适的 Startup Probe,可以为应用提供足够的启动缓冲时间,确保在应用真正完成初始化之前,Kubernetes 不会对其进行健康检查或流量调度,从而保证系统的稳定性。Startup Probe 的配置示例如下:

1
2
3
4
5
6
startupProbe:
httpGet:
path: /actuator/health # Spring Boot 健康检查端点
port: 8080
failureThreshold: 30 # 允许的最大失败次数
periodSeconds: 10 # 每10秒检查一次

Probe 的核心参数

  • 探针(Probe)可配置的核心参数(用于精确控制探针的行为)
参数作用默认值最小值适用探针类型
initialDelaySeconds容器启动后,等待多少秒才开始第一次执行探测,避免容器未完成启动就被误判为失败。0 秒 0 秒 liveness、readiness、startup
periodSeconds探测的执行频率,即两次探测之间的间隔时间。10 秒 1 秒 liveness、readiness
timeoutSeconds单次探测的超时时间,超过该时间未响应则判定为探测失败。1 秒 1 秒 liveness、readiness
failureThreshold探测成功后,连续失败多少次才会被认定为容器不健康。31liveness、readiness、startup
successThreshold对于已标记为不健康的容器,需要连续成功多少次才会重新标记为健康。对于 Liveness Probe,该值必须为 111liveness、readiness

Probe 的检测方法

  • Kubernetes 的三类探针都支持以下三种检测方法
检测方法说明配置示例
exec- 在容器内执行命令,返回状态码为 0 表示检测成功。
- 适用于复杂检测逻辑或没有 HTTP 接口的服务。
command: ["cat", "/tmp/healthy"]
httpGet- 通过发送 HTTP 请求检查服务是否正常。
- 返回状态码 200 ~ 399 表示检测成功。
httpGet: { path: /health, port: 80 }
tcpSocket- 通过容器 IP + 端口建立 TCP 连接,
- 连接成功,即表示容器健康。
tcpSocket: { port: 3306 }

Probe 的检测结果

  • 探针(Probe)的三种检测结果状态
检测结果状态说明
Success容器通过检查,状态正常。
Failure容器未通过检查,状态异常。
Unknown无法执行检查,因此不采取任何措施。

Pod 的重启策略有以下三种(如果 Liveness Probe 探测到容器不健康,kubelet 会将该容器 Kill 掉,并根据 Pod 的重启策略决定是否重启它)

重启策略说明
Always默认值,当容器退出时,总是由 kubelet 自动重启该容器(适用于长期运行的 Pod,如 Web 服务)。
OnFailure仅在容器异常退出(非 0 状态码)时,由 kubelet 自动重启该容器(适合批处理任务)。
Never无论容器如何退出,kubelet 都不会重启该容器(适合一次性任务)。
1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
name: mynginx
spec:
containers:
- name: nginx
image: nginx:1.14
imagePullPolicy: Always
restartPolicy: OnFailure # Pod 的重启策略

Probe 的使用示例

  • 基于 Liveness Probe(存活探针)检测容器健康
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy
# 存活检查
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
  • 存活探针、就绪探针二者配合使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: k8s.gcr.io/goproxy:0.1
ports:
- containerPort: 8080 # 容器内应用(比如 Goproxy)监听的端口
# 存活检查
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
# 就绪检查
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
  • 启动探针、存活探针和就绪探针三者配合使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
apiVersion: v1
kind: Pod
metadata:
name: springboot-app
spec:
containers:
- name: app
image: my-springboot-app:latest
ports:
- containerPort: 8080 # 容器内应用(比如 Tomcat)监听的端口
# 启动探针(给予充足启动时间)
startupProbe:
httpGet:
path: /actuator/health
port: 8080
failureThreshold: 30
periodSeconds: 10
# 存活检查(启动探针成功后生效)
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
periodSeconds: 10
timeoutSeconds: 3
# 就绪检查(启动探针成功后生效)
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 5
periodSeconds: 5

调度器

调度器的概述

一个容器平台的核心功能是为容器分配运行所需的计算、存储和网络资源。其中,容器调度系统负责在最合适的主机上启动容器,并将相关容器进行关联。它必须能够自动处理容器故障,并在应用访问量增加时,自动在更多主机上启动容器以应对扩展需求。目前,主流的三大容器平台 Swarm、Mesos 和 Kubernetes 各自拥有不同的调度系统:

  • Swarm:直接调度 Docker 容器,并提供与标准 Docker API 一致的接口,使用起来较为简单。
  • Mesos:采用多框架并行的调度模型,不同运行框架拥有相对独立的调度系统。其中,Marathon 框架对 Docker 容器提供了原生支持。
  • Kubernetes:引入 Pod 和 Label 的概念,将一组有依赖关系的容器组合成一个逻辑单元 Pod,并以 Pod 为基本单位进行部署和调度。同时,多个 Pod 可以通过 Service 形成一个完整的服务。

Kubernetes 通过这种抽象,简化了集群范围内相关容器的共同调度和管理复杂度。从另一个角度看,这种设计使得 Kubernetes 更容易实现功能更强大、逻辑更复杂的容器调度算法,这也是其与 Swarm 和 Mesos 的主要区别所在。

K8s 的资源分类

Kubernetes 调度器作为整个集群的 “大脑”,在提升集群资源利用率和保障服务稳定运行方面起着至关重要的作用,其重要性也会随着集群规模和复杂度的提升而不断增加。在 Kubernetes 中,资源可分为两类:

  • 可压缩资源(Compressible Resources)

    • 这类资源可以被限制或回收,例如 CPU 周期、磁盘 I/O 带宽等。
    • 当 Pod 资源不足时,Kubernetes 可以通过降低资源分配的方式来限制 Pod 对这些资源的使用,而无需直接杀掉 Pod。
  • 不可压缩资源(Incompressible Resources)

    • 这类资源一旦被 Pod 占用,除非终止 Pod,否则无法回收,例如内存、硬盘空间等。
    • 当 Pod 占用不可压缩资源过多且无法满足需求时,Kubernetes 只能通过驱逐(Eviction)或杀掉 Pod 来释放资源。

未来,Kubernetes 还将支持更多类型的资源,如网络带宽、存储 IOPS 等,使得调度和资源管理更加精细化和智能化。

K8s 调度器的概述

kube-scheduler 是 Kubernetes 系统的核心组件之一,主要负责整个集群的资源调度工作。它通过特定的调度算法和调度策略,将 Pod 调度到最合适的 Node(工作节点) 上,从而更高效、更合理地利用集群资源。这也是企业选择 Kubernetes 的一个重要原因:如果一项新技术不能帮助企业节约成本、提升效率,那么它将很难被真正落地和推广。

K8s 调度器的工作流程

K8s 调度器的简介

kube-scheduler 是一个独立的二进制程序,启动后会持续监听 API Server,获取所有 PodSpec.NodeName 为空的 Pod,并为其执行调度。每个成功调度的 Pod,调度器都会生成一个 Binding 对象 并存入 Etcd,随后目标节点上的 Kubelet 会根据调度结果创建 Pod。在默认情况下,kube-scheduler 内置的默认调度器已经能够满足大多数场景的需求。例如,默认策略可以保证 Pod 被分配到资源充足的节点上运行。但在实际生产环境中,企业往往对业务需求和应用特性有更深入的了解,因此需要更灵活、可控的调度策略,例如:

  • 限制某些 Pod 只能运行在特定节点上;
  • 某些节点只允许运行特定类型的应用;
  • 针对资源隔离、安全性或性能优化进行特殊调度。

Pod 的创建流程

更多关于 Pod 的创建流程的介绍,可以看 这里

K8s 调度器的工作流程

K8s 调度器的工作流程主要分为以下四个阶段(点击查看流程图):

  • (1) 预选阶段(Predicates)— 节点过滤

    • 在该阶段,K8s 调度器会根据一系列规则过滤掉不符合要求的节点,形成候选节点列表。
    • 例如,当 Pod 设置了资源 requests,如果某节点的可用资源不足,则该节点会被过滤掉。
    • 常见的 Predicates 过滤算法:
      算法名称说明
      PodFitsResources节点剩余资源是否满足 Pod 的资源请求(CPU / 内存等)。
      PodFitsHost如果 Pod 指定了 NodeName,检查节点名称是否匹配。
      PodFitsHostPorts节点上已使用的端口是否与 Pod 申请的端口冲突。
      PodSelectorMatches节点的标签是否与 Pod 指定的 labelSelector 匹配。
      NoDiskConflict检查 Pod 所需的 Volume 是否与节点上已挂载的 Volume 冲突(只读 Volume 除外)。
      CheckNodeDiskPressure节点磁盘压力是否过大,是否满足调度要求。
      CheckNodeMemoryPressure节点内存压力是否过大,是否满足调度要求。
  • (2) 优选阶段(Priorities)— 节点打分

    • 在该阶段,K8s 调度器会对通过预选阶段的节点进行打分,分数越高,表示该节点越适合部署该 Pod。
    • 打分规则是由一组键值对组成的:
      • 键:优先级策略的名称
      • 值:该策略的权重
    • 常见的 Priorities 优先级策略:
      优先级策略说明
      LeastRequestedPriority根据 CPU 和内存使用率计算权重,使用率越低,权重越高,从而优先选择负载较低的节点。
      SelectorSpreadPriority为了实现高可用,将同一个 Deployment / Replica Set 下的多个 Pod 尽量分散到不同节点上。运行该类型 Pod 数量较少的节点权重更高。
      ImageLocalityPriority如果某节点已经存在 Pod 需要的镜像,且镜像总大小越大,则该节点权重越高,从而减少镜像拉取时间。
      NodeAffinityPriority根据 Node Affinity(节点亲和性)规则计算权重,优先调度到符合亲和性条件的节点上。
  • (3) 绑定阶段(Binding)

    • K8s 调度器会从打分结果中选择分数最高的节点,将该 Pod 与该 Node(工作节点)进行绑定(Binding)。
    • 绑定结果会被写入 Etcd,供集群其他组件使用。
  • (4) Kubelet 执行

    • 最终被选定的 Node(工作节点)对应的 Kubelet 会接收到绑定信息,随后拉取容器镜像并创建 Pod。

K8s 调度器的工作流程图

总结

K8s 的调度过程分为两个阶段:首先是预选阶段(Predicates),用于过滤掉不满足条件的节点;然后是优选阶段(Priorities),对通过预选的节点按优先级进行排序。最后,从中选择优先级最高的节点进行调度。如果在任意阶段出现错误,调度器会直接返回错误。在预选阶段(Predicates),调度器会遍历所有节点,过滤掉不满足条件的节点。该阶段属于强制性规则,输出的所有符合要求的节点将作为第二阶段(优选阶段)的输入。如果所有节点都不满足条件,Pod 将一直处于 Pending 状态,直到出现满足条件的节点。期间,调度器会不断重试。因此,在部署应用时,如果发现 Pod 长时间处于 Pending 状态,说明没有符合调度条件的节点,可以检查节点资源是否可用。在优选阶段(Priorities),如果有多个节点都通过了预选条件,系统会根据节点的优先级对这些节点进行排序,最终选择优先级最高的节点来部署 Pod。K8s 调度器除了有上面介绍的 Predicates 过滤算法之外,还有一些其他的算法,更多更详细的过滤算法可以查看源码文件:k8s.io/kubernetes/pkg/scheduler/algorithm/predicates/predicates.go

K8s 调度器的核心特性

提示

更多关于影响 Pod 调度的因素可以看这里

节点亲和性调度
  • 概述:

    • K8s 节点亲和性(Node Affinity)调度规则有两种:硬亲和性(required)、软亲和性(preferred)。
  • 作用:

    • 节点亲和性调度使得 Pod 对象被吸引运行到一类特定的节点上。
  • 特性:

    • nodeSelector 字段更灵活的规则。
    • 支持硬亲和性(约束条件必须满足)和软亲和性(尝试满足约束条件,但不保证满足)。
    • 支持常用操作:InNotInExistsGtLtDoesNotExist
  • 定义字段:

    • 节点硬亲和性:requiredDuringSchedulingIgnoredDuringExecution
    • 节点软亲和性:preferredDuringSchedulingIgnoredDuringExecution
    • 权重 weight:用于定义优先级,范围是 1 ~ 100,值越大优先级越高
  • 定义方式:

    • 定义方式一:Pod 使用 spec.nodeSelector(基于等值关系)
    • 定义方式二:Pod 使用 spec.affinity.nodeAffinity 支持 matchExpressions 属性(基于复杂标签选择机制)

  • 节点硬亲和性的配置示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
affinity:
nodeAffinity:
# 节点硬亲和性:Pod 只能调度到满足条件的节点
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: env_role
operator: In
values:
- dev
- test
containers:
- name: myapp
image: ikubernetes/myapp:v1
  • 节点软亲和性的配置示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
name: myapp-pod
labels:
app: myapp
spec:
affinity:
nodeAffinity:
# 节点软亲和性:Pod 优先调度到符合条件的节点,但不是强制要求
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 60
preference:
matchExpressions:
- key: zone
operator: In
values:
- foo
- weight: 30
preference:
matchExpressions:
- key: ssd
operator: Exists
containers:
- name: myapp
image: ikubernetes/myapp:v1
Pod 亲和性调度

K8s 的 Pod 亲和性(Pod Affinity)调度用于控制 Pod 倾向于与指定 Pod 调度到同一拓扑域,常用于需要紧密协作或低延迟通信的场景。

  • Pod 亲和性(Pod Affinity)调度规则有两种:

    • 硬亲和性(约束条件必须满足):requiredDuringSchedulingIgnoredDuringExecution
    • 软亲和性(尝试满足约束条件,但不保证满足):preferredDuringSchedulingIgnoredDuringExecution
  • 可用于将相互依赖的 Pod 部署在同一机架(Rack)或同一可用区(Zone),以降低网络延迟、提升性能,比如:

    • topologyKey: kubernetes.io/hostname:倾向于将 Pod 调度到同一 Node(工作节点)。
    • topologyKey: zone:倾向于将 Pod 调度到同一可用区。

  • Pod 硬亲和性调度的配置示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
apiVersion: apps/v1
kind: Deployment
metadata:
name: busybox-deployment
spec:
replicas: 2
selector:
matchLabels:
app: busybox
template:
metadata:
labels:
app: busybox
spec:
affinity:
# Pod 硬亲和性调度
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp
topologyKey: zone
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "sleep 3600"]
  • 配置说明:
    • Kubernetes 调度器会强制保证,Pod 调度到与匹配 labelSelector 条件的 Pod 所在的同一 zone 中。
    • 如果集群中所有 zone 都没有匹配的 Pod,则新 Pod 会一直处于 Pending 状态。
      字段作用
      requiredDuringSchedulingIgnoredDuringExecution硬亲和性约束:必须满足条件,否则 Pod 无法被调度。
      labelSelector.matchExpressions指定匹配条件,比如匹配拥有 app=myapp 标签的 Pod。
      topologyKey定义拓扑域的维度,如 zonekubernetes.io/hostname 等。
Pod 反亲和性调度

K8s 的 Pod 反亲和性(Pod AntiAffinity)调度用于控制 Pod 不与指定 Pod 调度到同一拓扑域,常用于高可用场景。

  • 可用于将 Pod 副本分布到不同机架(Rack)或可用区(Zone) 中,避免单点故障,比如:
    • topologyKey: kubernetes.io/hostname:避免 Pod 调度到同一 Node(工作节点)。
    • topologyKey: zone:避免 Pod 调度到同一可用区。

Pod 反亲和性调度的配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
apiVersion: apps/v1
kind: Deployment
metadata:
name: busybox-deployment
spec:
replicas: 2
selector:
matchLabels:
app: busybox
template:
metadata:
labels:
app: busybox
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "sleep 3600"]
affinity:
# Pod 反亲和性调度
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp
topologyKey: zone
  • 配置说明:
    • Kubernetes 调度器会强制保证,同一 zone 下,不会与匹配 labelSelector 条件的 Pod 同时调度运行。
    • 如果所有 zone 都有匹配的 Pod,则新 Pod 会一直处于 Pending 状态。
      字段作用
      requiredDuringSchedulingIgnoredDuringExecution硬亲和性约束:必须满足条件,否则 Pod 无法被调度。
      labelSelector.matchExpressions指定匹配条件,比如匹配拥有 app=myapp 标签的 Pod。
      topologyKey定义拓扑域的维度,如 zonekubernetes.io/hostname 等。
污点和容忍度

污点(Taints)

  • 污点的作用:

    • 让节点拒绝调度 Pod 到其上运行,除非 Pod 显式声明可以容忍该污点。
  • 污点的定义:

    • 定义在节点(Node)上的键值型属性数据。
    • 字段 spec.taints,语法是 key=value:effect
  • 污点的适用场景:

    • 专用节点隔离:保留节点给特定 Pod(如 GPU 节点只运行 AI 任务)
    • 节点维护:标记节点为不可调度(如 NoSchedule),避免新 Pod 被分配到正在维护的节点
    • 特殊硬件限制:防止普通 Pod 调度到带特殊硬件(如 FPGA)的节点
  • 污点的类型:

    污点类型(Effect)作用对已运行 Pod 的影响典型场景
    NoSchedule 新的 Pod 无法调度到该节点,除非 Pod 明确声明容忍该污点不容忍此污点的 Pod 不会被驱逐保留节点给特定用途(如 GPU 节点、生产环境专用节点)
    PreferNoSchedule 调度器尽量避免将 Pod 调度到该节点,但若无其他节点可选,仍可被调度不容忍此污点的 Pod 不会被驱逐软性隔离,如临时维护节点但不强制拒绝调度
    NoExecute 新的 Pod 无法调度到该节点(与 NoSchedule 相同)不容忍此污点的 Pod 会被驱逐(Evict)节点故障或紧急隔离,如磁盘损坏需立即迁移所有 Pod
  • 节点自动添加的污点

    • 当节点出现特定状态或资源异常时,Kubernetes 会自动为节点添加带有 NoExecute 效果的污点,从而驱逐不具备相应容忍度的 Pod。
    • K8s 核心组件通常会自动容忍下面这些系统级别的污点,以确保系统服务的持续运行。
      污点键(Taint Key)触发条件 / 含义说明
      node.kubernetes.io/not-ready节点进入 NotReady 状态表示节点不可调度且无法响应心跳
      node.alpha.kubernetes.io/unreachable节点进入 NotReachable 状态旧版本中使用,表示节点网络不可达(已被废弃,改为下一个键)
      node.kubernetes.io/unreachable节点网络不可达替代 alpha 版本的键,节点与控制平面失联时自动添加
      node.kubernetes.io/out-of-disk节点磁盘空间不足节点磁盘空间耗尽时自动添加
      node.kubernetes.io/memory-pressure节点内存资源紧张表示节点内存使用率过高
      node.kubernetes.io/disk-pressure节点磁盘面临压力表示节点磁盘可用空间或 I/O 受限
      node.kubernetes.io/network-unavailable节点网络不可用节点网络尚未就绪或中断
      node.cloudprovider.kubernetes.io/uninitialized节点由云提供商组件初始化中当 kubelet 由云环境程序启动时自动添加,待控制器初始化节点后自动移除
  • 节点的污点操作示例:

1
2
3
4
5
# 给节点添加污点
kubectl taint nodes <node-name> <key>=<value>:NoSchedule

# 举个例子
kubectl taint node kube-node1 node-type=production:NoShedule
1
2
3
4
5
# 查看节点的污点
kubectl describe node <node-name> | grep Taint

# 或者
kubectl get nodes <node-name> -o go-template={{.spec.taints}}
1
2
3
4
5
6
7
8
# 删除节点的单个污点(末尾的 "-" 符号表示删除)
kubectl taint nodes <node-name> <key>:NoSchedule-

# 删除节点的指定键的所有污点(末尾的 "-" 符号表示删除)
kubectl taint nodes <node-name> <key>-

# 删除节点的所有污点
kubectl patch nodes <node-name> -p '{"spec":{"taints":[]}}'

容忍度(Tolerations)

  • 容忍度的概述:

    • 节点设置污点后,Pod 必须声明可以容忍哪些污点,才允许其被调度到具有这些污点的节点上。
  • 容忍度的定义:

    • 定义在 Pod 上的键值型属性数据。
    • 字段 spec.tolerations,语法是 key=value:effect
    • 字段 tolerationSeconds 用于定义延迟驱逐 Pod 的时间
      • tolerationSeconds 仅在 effect: NoExecute 的容忍规则中生效;
      • 超过设定时间后,若节点上的污点仍存在,则 Pod 会被驱逐;
      • 如果未设置 tolerationSeconds,则表示 Pod 将无限期地容忍该污点,即 Pod 不会因为该污点被驱逐。
  • 容忍度的调度规则:

    • Pod 优先调度到没有污点的节点。
    • 如果目标节点有污点,则 Pod 必须显式声明容忍该污点,否则无法被调度过去。
  • 容忍度的适用场景:

    • 特权 Pod 调度:允许关键 Pod(如日志收集组件)无视污点,调度到任意节点
    • 故障恢复:容忍 NoExecute 污点,使 Pod 在节点故障时不被驱逐(如数据库 Pod)
    • 共享特殊节点:让普通 Pod 通过容忍临时使用专用节点(如容忍 GPU 节点污点)
  • 容忍度的类型:

容忍度类型(Effect)作用典型场景
NoSchedule 允许 Pod 调度到带有 NoSchedule 污点的节点,无视节点的硬性隔离规则关键 Pod,如存储服务、核心系统组件
PreferNoSchedule 允许 Pod 调度到带有 PreferNoSchedule 污点的节点,但调度器仍会优先选择其他节点非关键 Pod 在资源不足时,仍可使用软隔离节点
NoExecute1. 允许 Pod 调度到带有 NoExecute 污点的节点
2. 豁免驱逐:即使节点新增 NoExecute 污点,Pod 也不会被驱逐
守护进程(如日志收集器、监控代理)需长期运行,无视节点维护状态
空值(未指定 Effect)容忍所有类型的污点,包括未来新增的类型超级特权 Pod,如集群管理组件、CNI/CSI 插件等需在所有节点运行
  • Pod 的容忍度配置示例:
1
2
3
4
5
6
7
spec:
tolerations:
- key: "key1"
operator: "Equal" # 等值判断,判断条件为 Equal
value: "value1"
effect: "NoExecute"
tolerationSeconds: 600 # 延迟 600 秒后驱逐 Pod(可选)
1
2
3
4
5
6
spec:
tolerations:
- key: "key1"
operator: "Exists" # 存在性判断,只要污点键(Key)存在即可匹配
effect: "NoExecute"
tolerationSeconds: 600 # 延迟 600 秒后驱逐 Pod(可选)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spec:
tolerations:
# 容忍 NoSchedule 污点
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"

# 容忍 NoExecute 污点
- key: "unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 600 # 延迟 600 秒后驱逐 Pod(可选)

# 容忍所有污点(危险!慎用!)
- operator: "Exists"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
apiVersion: apps/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
# 容忍 NoExecute 污点
tolerations:
- key: "node-type"
operator: "Equal"
value: "production"
effect: "NoExecute"
tolerationSeconds: 600 # 延迟 600 秒后驱逐 Pod(可选)

特别注意

  • 一个节点可以配置多个污点,一个 Pod 也可以有多个容忍度。
  • 污点提供了让节点(Node)排斥运行特定 Pod 对象的能力。
  • 节点亲和性(Node Affinity)调度使得 Pod 对象被吸引运行到一类特定的节点上。
Pod 优先级与抢占式调度

在 Pod 上定义容忍度时,Pod 的优先级与抢占式调度机制如下:

  • 优先级(Pod Priority)

    • 表示 Pod 对象的重要程度。
    • 作用:
      • 影响调度顺序:高优先级 Pod 会优先被调度。
      • 影响驱逐次序:节点资源不足时,低优先级 Pod 会先被驱逐。
  • 抢占机制(Preemption)

    • 当一个 Pod 无法被调度时,调度器会尝试驱逐节点上优先级更低的 Pod,为当前高优先级 Pod 腾出资源。
    • 适合关键业务 Pod 需要资源保障的场景。
  • 启用方法

    • Pod 优先级与抢占式调度机制默认处于禁用状态,需要手动启用。
    • 启用方式:在以下组件的启动参数中增加 --feature-gates=PodPriority=true
      • kube-apiserver
      • kube-scheduler
      • kubelet
  • 使用步骤

    • (1) 创建优先级类别(PriorityClass

      • 定义不同的优先级,如关键业务、高优先级、低优先级等。
      • 配置示例:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        apiVersion: scheduling.k8s.io/v1
        kind: PriorityClass
        metadata:
        name: high-priority # 优先级类别名称
        value: 1000 # 优先级值,数值越大优先级越高
        globalDefault: false # 是否为默认优先级类别
        description: "用于关键业务 Pod,例如存储、网络组件" # 优先级的描述信息

        ---

        apiVersion: scheduling.k8s.io/v1
        kind: PriorityClass
        metadata:
        name: low-priority # 优先级类别名称
        value: 100 # 优先级值,数值越大优先级越高
        globalDefault: false # 是否为默认优先级类别
        description: "用于低优先级 Pod,例如测试或批处理任务" # 优先级的描述信息
    • (2) 在 Pod 中指定优先级

      • 创建 Pod 时,通过 priorityClassName 属性绑定到对应的优先级类别。
      • 配置示例:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        apiVersion: v1
        kind: Pod
        metadata:
        name: critical-app
        spec:
        priorityClassName: high-priority # Pod 绑定高优先级类别
        containers:
        - name: critical-container
        image: nginx

Pod 的优先级与抢占式调度总结

高优先级 Pod 无法被调度 → 调度器检查目标节点 → 驱逐低优先级 Pod → 为高优先级 Pod 腾出资源 → 高优先级 Pod 调度成功。