Kubernetes 入门教程之二

大纲

Kubernetes 核心技术

Pod

Pod 的基础概念

Pod 的概述

Pod 是 Kubernetes 中可以创建和管理的最小资源单元,是用户在资源对象模型中创建或部署的基本单位,也是 Kubernetes 上运行容器化应用的直接载体。Kubernetes 并不会直接管理容器,而是通过管理 Pod 来间接管理容器。一个 Pod 通常由一个或多个容器组成,这些容器共享网络、存储等资源,并作为一个整体被调度和管理。在 Kubernetes 中,其他资源对象主要用于支撑或扩展 Pod 的功能,例如:Controller 资源用于管理和控制 Pod 的生命周期;Service 或 Ingress 资源用于暴露和访问 Pod;而 PersistentVolume (PV) 等存储资源用于为 Pod 提供持久化存储支持。此外,每个 Pod 都包含一个特殊的系统容器,称为 Pause 容器,它作为 Pod 的 “根容器” 存在,用于占据 Pod 的网络命名空间等资源。除了 Pause 容器,Pod 中还包含一个或多个紧密相关的用户业务容器,所有业务容器都在同一个 Namespace 里面,可以实现网络共享;这些容器协同工作,共同完成某项具体的业务功能。

Pod 的特性
  • 资源共享

    • 一个 Pod 里的多个容器可以共享存储和网络,可以看作一个逻辑的主机(服务器),共享 Namespace(命名空间)、Cgroups(控制组)或者其他的隔离资源。
    • 同一个 Pod 中的多个容器共享同一个 Network Namespace,因此它们共享同一个 IP 地址和端口空间。也就是说,Pod 内的容器可以通过 localhost 进行通信。需要注意的是,多个容器在同一个 Pod 中运行时,应避免端口冲突。不同的 Pod 之间具有各自独立的 IP 地址,默认情况下,不同 Pod 中的容器之间不能通过 IPC 机制通信(除非做了特殊配置),通常使用 Pod 的 IP 地址进行网络通信。
    • 一个 Pod 中的多个容器可以共享同一个存储卷,该存储卷作为 Pod 的一部分被定义,并可以挂载到该 Pod 内所有容器的文件系统中,从而实现数据共享和持久化存储。
  • 生命周期短暂

    • Pod 是生命周期相对短暂的组件,例如当 Pod 所在的节点发生故障时,该节点上的 Pod 会被重新调度到其他节点上运行。但需要注意的是,重新调度后创建的是一个全新的 Pod,与原来的 Pod 没有任何关联,原有的状态、数据和标识都会丢失,二者之间没有任何直接关系。
  • 平坦的网络

    • Kubernetes 集群中的所有 Pod 都处于同一个共享的网络地址空间中,这意味着每个 Pod 都可以通过其他 Pod 的 IP 地址直接进行访问和通信,无需进行额外的网络配置。

Docker 容器与宿主机进程的关系

  • Docker 容器里的进程没有独立 Linux 内核,使用的是宿主机内核,它本质就是宿主机进程。
  • Docker 容器只是由 Linux 内核提供的隔离(Namespace) + 资源限制(Cgroups)环境。
  • 当宿主机关掉 Docker 容器主进程,容器就会退出运行(容器生命周期依赖主进程)。换言之,Docker 容器主进程如果挂掉,容器就会停止运行。
  • Docker 容器的 Linux 内核版本永远等于宿主机的内核版本,更换镜像也换不掉内核。比如,当宿主机内核版本低(例如 3.3),容器里即使是最新版本的 Ubuntu,也无法使用高版本内核才有的特性(比如一些新 Cgroup 特性、eBPF)。
Pod 的分类

Pod 有两种类型:

  • 普通 Pod

    • 普通 Pod 被创建后会被存储到 Etcd 中,随后由 Kubernetes Master 调度到某个特定的 Node(工作节点)上并与之绑定。该 Node(工作节点)上的 kubelet 进程会负责将 Pod 实例化为一组相关的容器(如 Docker 容器)并启动它们。默认情况下,如果 Pod 中的某个容器停止运行,Kubernetes 会自动检测并重启该 Pod 内的所有容器。如果 Pod 所在的 Node(工作节点)发生宕机,Kubernetes 会将该 Node(工作节点)上的所有 Pod 重新调度到其他可用节点上。
  • 静态 Pod

    • 静态 Pod 是由 kubelet 直接管理的特殊 Pod,仅存在于特定的 Node(工作节点)上。它们不受 API Server 管理,也无法与 Replication Controller、Deployment 或 DaemonSet 等控制器关联。此外,kubelet 对静态 Pod 的健康检查能力有限,通常仅能监控其运行状态,而不会像普通 Pod 那样提供完整的健康检查机制。
Pod 的定义

定义 Pod 的 YAML 配置示例如下(<string> 是占位符,需要根据实际情况填写):

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
35
36
37
38
39
40
41
42
43
apiVersion: v1
kind: Pod
# 元数据
metadata:
name: <string>
namespace: <string>
labels:
name: <string>
annotations:
name: <string>
# 时间配置
spec:
periodSeconds: 0 # 检查间隔时间
successThreshold: 0
failureThreshold: 0
# 安全配置
securityContext:
privileged: false
restartPolicy: Always # 重启策略,可选值: Always、Never、OnFailure,默认 Always
nodeSelector: # 节点选择,将 Pod 调度到包含这些 Label 的 Node(工作节点)上
key: value # 以 key:value 格式指定
imagePullSecrets:
- name: <string>
hostNetwork: false # 是否使用主机网络模式,默认 false(不使用)
# 共享存储卷列表
volumes:
- name: <string>
emptyDir: {}
- name: host-volume
hostPath:
path: /path/on/host
- name: secret-volume
secret:
secretName: <string>
items:
- key: <string>
path: <string>
- name: configmap-volume
configMap:
name: <string>
items:
- key: <string>
path: <string>
Pod 的运行方式

在 Kubernetes 中,运行的容器要求其主程序必须始终在前台运行,而不能以后台方式执行。如果应用默认是以后台运行的方式启动,就需要进行修改,使其在前台运行。否则,当 kubelet 创建包含该容器的 Pod 并执行启动命令后,会因为容器立即退出而认为该 Pod 已经结束,从而立刻销毁该 Pod。如果该 Pod 是由控制器(如 Replication Controller)管理的,那么就会不断尝试重新创建和销毁 Pod,陷入无限循环。需要注意的是,一个 Pod 可以由一个或多个容器组成。

  • 下面的 YAML 配置内容定义了一个包含单个容器的 Pod,容器使用的是官方 Tomcat 镜像,并包含基本的端口和挂载配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Pod
metadata:
name: mytomcat
labels:
app: tomcat
spec:
containers:
- name: tomcat-container
image: tomcat:9.0
ports:
- containerPort: 8080
volumeMounts:
- name: tomcat-data
mountPath: /usr/local/tomcat/webapps
volumes:
- name: tomcat-data
emptyDir: {}
  • YAML 配置内容的详细说明
配置项说明
metadata.namePod 的名称,必须唯一
metadata.labels标签,用于标识和选择 Pod
spec.containers容器列表,一个 Pod 可包含一个或多个容器
spec.containers[].name容器的名称,在 Pod 内部唯一
spec.containers[].image容器使用的镜像,这里是 tomcat:9.0
spec.containers[].ports容器开放的端口列表
spec.containers[].ports[].containerPort容器内部监听的端口号(如 Tomcat 默认 8080)
spec.containers[].volumeMounts容器内挂载的卷配置
spec.containers[].volumeMounts[].name要挂载的卷名称,对应 spec.volumes 中定义的名称
spec.containers[].volumeMounts[].mountPath挂载点路径,如 /usr/local/tomcat/webapps
spec.volumes定义 Pod 中使用的卷
spec.volumes[].name卷的名称,与 volumeMounts 中的名称对应
spec.volumes[].emptyDir使用一个空目录卷,Pod 删除时数据也会被清除
Pod 的生命周期

Pod 的生命周期状态有以下几种:

生命周期状态说明
PendingAPI Server 已创建该 Pod,但 Pod 中的一个或多个容器的镜像尚未创建(包括镜像下载过程)。
RunningPod 内所有容器已创建,且至少有一个容器处于运行状态(包括正在启动或重启的状态)。
CompletedPod 内所有容器均已成功执行并退出,且不会再重启。
FailedPod 内所有容器均已退出,但至少有一个容器退出失败。
Unknown 由于某些原因(如网络通信不畅)无法获取 Pod 的状态。
Pod 的状态条件

Pod 的状态条件(Conditions)有以下几种:

状态条件触发时机正常状态说明
PodScheduled当 Scheduler 为 Pod 分配了目标 Node(工作节点)后True表示 Pod 已被调度到某个 Node(工作节点)上。如果为 False,可能是集群资源不足或调度约束冲突。
Initialized当所有 Init 容器(如果有)成功执行完成后True仅对包含 Init 容器的 Pod 有意义。若 Init 容器失败,此条件会显示 False 并记录原因。
ContainersReady当 Pod 内所有主容器(非 Init 容器)的状态均为 RunningTrue仅表示容器已启动,但不保证容器内应用已就绪(需结合 Readiness Probe(就绪探针)判断)。
Ready当 Pod 满足以下条件时:
1. 所有主容器 Running
2. 通过 Readiness Probe(就绪探针)检测(如果配置了)。
True表示 Pod 可正常接收流量。若为 False,该 Pod 会被从 Service 的 Endpoints 中移除。

Pod 状态条件的附加说明

  • (1) 状态值:
    • 每个 Condition 的状态可能是 TrueFalseUnknown
  • (2) 依赖关系:
    • PodScheduledInitializedContainersReadyReady(存在先后顺序)。
  • (3) 常见问题:
    • PodScheduled=False,需检查节点资源或亲和性规则。
    • Initialized=False,需排查 Init 容器的日志。
    • Ready=FalseContainersReady=True,通常是 Readiness Probe(就绪探针)配置问题。
  • (4) 查看命令:
    1
    2
    3
    4
    5
    # 以结构化格式提取 Pod 状态条件(Conditions)的详细信息
    kubectl get pod <pod-name> -o jsonpath='{.status.conditions}'

    # 或使用 describe 查看 Pod 的详细状态
    kubectl describe pod <pod-name>
Pod 的重启策略

Pod 的重启策略包括 Always、OnFailure 和 Never,默认值是 Always。

重启策略说明
Always 默认值,当容器退出时,总是由 kubelet 自动重启该容器(适用于长期运行的 Pod,如 Web 服务)。
OnFailure 仅在容器异常退出(非 0 状态码)时,由 kubelet 自动重启该容器(适合批处理任务)。
Never 无论容器如何退出,kubelet 都不会重启该容器(适合一次性任务)。

Pode 重启策略的配置示例如下:

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 的重启策略
Pod 的状态转换

Pod 生命周期状态的转换表(基于容器事件和重启策略)如下:

Pod 包含的容器数 Pod 当前的运行状态发生的事件 Pod 的结果状态(RestartPolicy = Always)Pod 的结果状态(RestartPolicy = OnFailure)Pod 的结果状态(RestartPolicy = Never)
1 个容器 Running 容器成功退出 RunningSucceededSucceeded
1 个容器 Running 容器失败退出 RunningRunningFailed
2 个容器 Running 其中 1 个容器失败退出 RunningRunningRunning
2 个容器 Running2 个容器被 OOM 终止 RunningRunningFailed
  • 关键说明:
    • OOM:表示容器因内存不足(Out Of Memory)被系统终止
    • 状态转换规则:
      • Always:任何容器终止都会触发重启(保持 Running 状态)
      • OnFailure:仅当容器异常退出(非 0 状态码 / OOM)时重启
      • Never:容器终止后直接反映最终状态(Succeeded/Failed)
    • 多容器 Pod 的状态由所有容器的综合状态决定
Pod 的健康检查

Kubernetes 提供以下三种探针(Probe)来监控容器的运行状态:

  • 存活探针(livenessProbe

    • 作用:检测容器是否正常运行。如果检测不通过,Kubernetes 会杀死容器并根据 restartPolicy(重启策略) 重启容器。
    • 适用场景:用于修复死锁、无响应的应用(如数据库卡死)。
    • 配置示例:
      1
      2
      3
      4
      5
      6
      livenessProbe:
      exec:
      command: ["cat", "/tmp/healthy"] # 执行命令检查文件是否存在
      initialDelaySeconds: 5 # 容器启动后等待5秒开始检查
      periodSeconds: 5 # 每5秒检查一次
      failureThreshold: 3 # 连续失败3次后判定为不健康
  • 就绪探针(readinessProbe

    • 作用:检测容器是否准备好接收流量。如果检测不通过,Kubernetes 会将 Pod 从 Service 的 Endpoints 中剔除,并且 Pod 会被标记为 NotReady,但不会被重启。
    • 适用场景:用于控制流量进入(如应用启动时需要加载大量数据,导致容器启动后无法立刻对外提供服务
    • 配置示例:
      1
      2
      3
      4
      5
      6
      7
      readinessProbe:
      httpGet:
      path: /healthz # 发送 HTTP 请求进行检测
      port: 8080
      initialDelaySeconds: 10 # 容器启动后等待10秒开始检查
      periodSeconds: 3 # 每3秒检查一次
      successThreshold: 1 # 成功1次即标记为就绪
  • 启动探针(startupProbe

    • 作用:从 Kubernetes 1.16+ 版本开始引入,专门检测慢启动应用是否完成初始化。在启动探针成功之前,其他探针不会生效。可以避免因应用启动过慢,导致被存活 / 就绪探针误杀。
    • 适用场景:启动时间较长的应用(如 Java/SpringBoot 应用、需要加载大数据量的服务)。
    • 配置示例:
      1
      2
      3
      4
      5
      6
      startupProbe:
      httpGet:
      path: /actuator/health # Spring Boot 健康检查端点
      port: 8080
      failureThreshold: 30 # 允许的最大失败次数
      periodSeconds: 10 # 每10秒检查一次

探针(Probe)支持以下三种检测方法(三种类型的探针都支持):

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

探针(Probe)的三种探测结果状态:

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

探针(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

基于存活探针检测容器的健康状态

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
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
# 启动探针(给予充足启动时间)
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
Pod 的资源限制

每个 Pod 都可以对其可使用的 Node(工作节点)计算资源设置限额。Kubernetes 支持对以下两种计算资源进行配额限制:

  • 资源类型

    • CPU 资源:以绝对值的 CPU 数量为单位(比如 500m 表示 0.5 个 CPU 核心)。
    • Memory 资源:内存大小以字节数为单位(比如 512Mi 表示 512 MiB 内存)。
  • 配额参数

    • 每种资源需要定义两个关键参数:
    • Requests
      • 表示该资源的最小申请量。
      • Kubernetes 调度器会确保 Node(工作节点)剩余资源大于等于 Requests 值,否则 Pod 无法被调度。
    • Limits
      • 表示该资源的最大允许使用量。若容器尝试使用超过 Limits 的资源:
        • 对于 CPU 资源,容器会被限制(Throttled)。
        • 对于 Memory 资源,容器可能被 Kubernetes 终止(OOM Kill)并重启。

Pod 资源限制的配置示例如下,表示 MySQL 容器申请最少 0.25 个 CPU 以及 64MiB 内存,在运行过程中容器所能使用的最大资源配额为 0.5 个 CPU 以及 128MiB 内存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Pod
metadata:
name: mysql-pod
spec:
containers:
- name: db
image: mysql
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"

CPU 资源限制的单位

  • (1) 在 Kubernetes 的资源限制配置中,cpu: "500m" 表示 500 毫核(millicores)。
  • (2) 1m = 0.001 个 CPU 核心,而 500m 等价于 0.5 个 CPU 核心(即 50% 的单核算力)。
  • (3) Kubernetes 常见的 CPU 单位如下表所示:
CPU 单位含义配置示例
11 个完整的 CPU 核心cpu: "1"
1000m1 个完整的 CPU 核心cpu: "1000m"
500m0.5 核(即 50% 的单核算力)cpu: "500m"
250m0.25 核(即 25% 的单核算力)cpu: "250m"
Pod 的镜像拉取策略

Pod 有以下几种镜像拉取策略:

策略名称描述
IfNotPresent默认值,只有当镜像在宿主机上不存在时才会拉取
Always每次创建 Pod 时都会重新拉取一次镜像(即使宿主机上已存在)
NeverPod 永远不会主动拉取镜像,仅使用宿主机上已有的镜像(若宿主机上不存在,则报错)

Pode 镜像拉取策略的配置示例如下:

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Pod
metadata:
name: mynginx
spec:
containers:
- name: nginx
image: nginx:1.14
imagePullPolicy: Always # Pod 的镜像拉取策略

Pod 的调度策略

提示

更多关于 Kubernetes 调度器的介绍请看 这里

Pod 的创建流程

  • (1) 用户提交 Pod 创建请求

    • 用户通过 kubectl 命令行工具或其他客户端工具提交 Pod 创建请求
    • 请求会发送到 Master 节点的 API Server
  • (2) API Server 处理

    • API Server 接收并验证请求
    • 将 Pod 配置信息写入 Etcd 进行持久化存储
  • (3) Scheduler 调度

    • Scheduler 组件监控 API Server,发现有未调度的新 Pod
    • Scheduler 通过调度算法(考虑资源需求、节点亲和性等)选择最适合的 Node(工作节点)
    • Scheduler 将调度决策(绑定信息)通过 API Server 更新到 Etcd
  • (4) Node(工作节点)执行

    • 目标 Node(工作节点)上的 kubelet 组件会定期查询 API Server
    • kubelet 发现分配给本节点的 Pod 信息(从 Etcd 读取)
    • kubelet 根据 Pod 描述文件:
      • 通过容器运行时(如 Docker、Containerd)创建容器
      • 配置容器网络、存储等资源
      • 启动容器
  • (5) Pod 状态更新

    • kubelet 监控容器状态,并将容器最新状态报告给 API Server
    • API Server 将 Pod 状态信息写入 Etcd
    • 用户可以通过 kubectl 命令行工具查看 Pod 的运行状态
影响 Pod 调度的因素

在 Kubernetes 中,影响 Pod 调度的主要因素有以下几种。

Pod 资源限制
  • Pod 资源限制(Resource Requests)
    • 核心机制:
      • Pod 通过 resources.requests 声明所需的最小资源量
      • 调度器(Scheduler)根据这些请求寻找有足够资源的节点
    • 配置示例:
      1
      2
      3
      4
      5
      6
      7
      8
      spec:
      containers:
      - name: db
      image: mysql
      resources:
      requests:
      memory: "64Mi"
      cpu: "250m"
    • 调度行为:
      • 调度器会排除所有可用资源(Allocatable)小于请求值的节点
      • 资源包括 CPU、内存、GPU 等
      • 实际调度基于节点的剩余资源(Allocatable - Requested)
节点选择器
  • 节点选择器(Node Selector)
    • 核心机制:
      • 通过 nodeSelector 字段指定 Pod 必须运行在具有特定标签的节点上
      • 这是简单的节点选择约束方式
    • 配置示例:
      1
      2
      3
      4
      5
      6
      spec:
      nodeSelector:
      env_role: dev
      containers:
      - name: nginx
      image: nginx:1.15
    • 节点的标签操作:
      • 给节点打上标签:
        1
        kubectl label nodes <node-name> env_role=prod
      • 查看节点上的标签:
        1
        kubectl get nodes --show-labels
节点亲和性
  • 节点亲和性(Node Affinity)
    • 概述:
      • K8s 节点亲和性(Node Affinity)规则有两种:硬亲和性(required)、软亲和性(preferred
    • 作用:
      • 节点亲和性调度使得 Pod 对象被吸引运行到一类特定的节点上。
    • 特性:
      • nodeSelector 字段更灵活的规则
      • 支持硬亲和性(约束条件必须满足)和软亲和性(尝试满足约束条件,但不保证满足)
      • 支持常用操作:InNotInExistsGtLtDoesNotExist
    • 配置示例:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      spec:
      affinity:
      nodeAffinity:
      # 节点硬亲和性
      requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
      - key: env_role
      operator: In
      values:
      - dev
      - test
      # 节点软亲和性
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
      preference:
      matchExpressions:
      - key: group
      operator: In
      values:
      - otherprod
污点和容忍

污点(Taints)

  • 污点的概述:
    • 节点可以设置污点(Taints)来拒绝普通 Pod 的调度
  • 污点的定义:
    • 定义在节点(Node)上的键值型属性数据
    • 字段 spec.taints,语法是 key=value:effect
  • 污点的类型:
    • NoSchedule
      • 作用:
        • 默认值,新 Pod 无法调度到该节点(除非明确容忍此污点)
        • 已运行的 Pod 若不容忍此污点,不会被驱逐(Evict)
      • 场景:保留节点给特定用途(如 GPU 节点、生产环境专用节点)
    • PreferNoSchedule
      • 作用:
        • 调度器尽量避免将 Pod 分配到该节点,但若无其他可用节点仍会调度,不驱逐已运行的 Pod
        • 已运行的 Pod 若不容忍此污点,不会被驱逐(Evict)
      • 场景:软性隔离(如临时维护节点,但不强制拒绝调度)
    • NoExecute
      • 作用:
        • 新 Pod 无法调度到该节点(同 NoSchedule
        • 已运行的 Pod 若不容忍此污点,会被驱逐(Evict)
      • 场景:节点故障维护或紧急隔离(如节点磁盘故障需立即迁移所有 Pod)
  • 污点的适用场景:
    • 专用节点隔离:保留节点给特定 Pod(如 GPU 节点只运行 AI 任务)
    • 节点维护:标记节点为不可调度(如 NoSchedule),避免新 Pod 被分配到正在维护的节点
    • 特殊硬件限制:防止普通 Pod 调度到带特殊硬件(如 FPGA)的节点
  • 节点的污点操作示例:
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 不会因为该污点被驱逐。
  • 容忍的类型
    • NoSchedule
      • 作用:允许 Pod 调度到带有 NoSchedule 污点的节点
      • 场景:让关键 Pod(如存储服务)无视节点的硬性隔离规则
    • PreferNoSchedule
      • 作用:允许 Pod 调度到带有 PreferNoSchedule 污点的节点(但调度器仍可能优先选择其他节点)
      • 场景:非关键 Pod 在资源不足时仍可使用软隔离节点
    • NoExecute
      • 作用:
        • 允许 Pod 调度到带有 NoExecute 污点的节点
        • 豁免驱逐:即使节点新增 NoExecute 污点,Pod 也不会被驱逐
      • 场景:守护进程(如日志收集器)需长期运行,无视节点维护状态
    • 空值(不指定 effect 字段)
      • 作用:容忍所有污点类型(包括未来可能新增的类型)
      • 场景:超级特权 Pod(如集群管理组件)需在任何节点运行
  • 容忍的适用场景:
    • 特权 Pod 调度:允许关键 Pod(如日志收集组件)无视污点,调度到任意节点
    • 故障恢复:容忍 NoExecute 污点,使 Pod 在节点故障时不被驱逐(如数据库 Pod)
    • 共享特殊节点:让普通 Pod 通过容忍临时使用专用节点(如容忍 GPU 节点污点)
  • 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"
Pod 亲和性和反亲和性
  • Pod 亲和性
    • 控制 Pod 倾向于与指定 Pod 调度到同一拓扑域(共存关系)。
    • 适用于需要紧密协作或低延迟通信的场景,以降低网络延迟、提升性能。
    • 配置示例:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      spec:
      affinity:
      # Pod 亲和性
      podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
      matchExpressions:
      - key: app
      operator: In
      values: ["cache"]
      topologyKey: "kubernetes.io/hostname"
    • 配置说明:
      • Kubernetes 调度器会强制保证,Pod 调度到与匹配 labelSelector 条件的 Pod 所在的同一 zone 中。
      • 如果集群中所有 zone 都没有匹配的 Pod,则新 Pod 会一直处于 Pending 状态。
  • Pod 反亲和性
    • 控制 Pod 不与指定 Pod 调度到同一拓扑域(互斥关系)。
    • 适用于高可用场景,比如:将 Pod 副本分布到不同机架(Rack)或可用区(Zone) 中,避免单点故障。
    • 配置示例:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      spec:
      affinity:
      # Pod 反亲和性
      podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
      matchExpressions:
      - key: app
      operator: In
      values:
      - cache
      topologyKey: zone
    • 配置说明:
      • Kubernetes 调度器会强制保证,同一 zone 下,不会与匹配 labelSelector 条件的 Pod 同时调度运行。
      • 如果所有 zone 都有匹配的 Pod,则新 Pod 会一直处于 Pending 状态。

提示

Pod 亲和性和反亲和性的更详细介绍,可以看这里

Pod 优先级与抢占式调度

在 Pod 上定义容忍(Tolerations)时,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 调度成功。

Pod 的调度决策流程
  • (1) 预选阶段:排除不满足条件的节点(资源不足、标签不匹配等)。
  • (2) 优选阶段:对剩余节点打分 (考虑资源平衡、亲和性等因素)。
  • (3) 绑定阶段:选择最高分节点,将绑定信息写入 API Server。
  • (4) 执行阶段:目标 Node(工作节点)的 Kubelet 拉起 Pod。

提示

Kubernetes 调度器的详细工作流程,可以看这里

Label

Label 的概念

Label 是 Kubernetes 中的核心概念之一,用于为集群中的各种资源对象打上自定义的标记。

  • Label 的核心概念:

    • 一个 Label 是一个 key=value 形式的键值对,其中 keyvalue 由用户自定义。
    • Label 可以附加到各种 Kubernetes 资源对象上,例如 Node、Pod、Service、Replication Controller(RC)等。
    • 一个资源对象可以拥有任意数量的 Label,同一个 Label 也可以被应用到任意数量的资源对象上。
    • Label 通常在资源对象创建时通过 metadata.labels 字段定义,也可以在对象创建后动态添加或删除。
  • Label 的核心作用

    • Label 附加到 Kubernetes 资源对象上的主要目的是对这些对象进行分组管理。
    • Kubernetes 分组管理的核心机制是 Label Selector(标签选择器):
      • Label Selector 根据指定的匹配规则筛选出符合条件的资源对象,实现分组控制和管理。
      • Label 和 Label Selector 都不能单独存在,必须附加在某些资源对象的定义文件中,才能发挥作用。
      • 在实际使用中,Label 通常附加在 Pod 上,而 Label Selector 则常用于 Replication Controller(RC)、Replica Set(RS) 或 Service 等资源定义文件中,通过匹配特定 Label 来选择和管理 Pod。
  • Label 的常见用途

    • 通过在对象的定义中添加 metadata.labels,为对象打上标签。
    • 其他资源(如 Service、Deployment)可以通过 spec.selector 来选择和关联具有特定 Label 的对象,实现分组管理和调度。
  • Label 的注意事项

    • Label 和 Label Selector 都不能单独存在,必须附加在某些资源对象的定义文件中,常见组合是:
      • Pod + Label
      • Replication Controller(RC) / Replica Set(RS) / Service + Label Selector

Label 的使用

  • 配置示例
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
apiVersion: v1
kind: Replication Controller
metadata:
name: nginx
spec:
replicas: 3
selector:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80

---

apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: NodePort
ports:
- port: 80
nodePort: 3333
selector:
app: nginx
  • 配置说明:
    • Replication Controller(RC):
      • 通过 selector 选择并管理所有带有 app=nginx 标签的 Pod。
      • 确保 Pod 的副本数量维持在 3 个,由 RC 创建的 Pod 会包含 app=nginx 标签。
    • Service:
      • 通过 selector 匹配同样带有 app=nginx 标签的 Pod,并将流量分发给这些 Pod。
      • 通过 nodePort: 3333 在集群外部暴露服务。

Node(工作节点)的标签操作

  • 给 Node(工作节点)打上标签:kubectl label nodes <node-name> env_role=prod
  • 查看 Node(工作节点)上的标签:kubectl get nodes --show-labels