跳过正文
  1. 所有文章/

kubectl apply 到 Pod Running 的链路

·1922 字·4 分钟
目录

从执行 kubectl apply 命令到一个 Pod 进入 Running 状态,整个链路涉及 Kubernetes 系统多个组件的协同工作。以下是详细的步骤分解:

阶段一:用户提交 (kubectl apply)
#

操作: 用户执行 kubectl apply -f pod.yaml

过程:

  • kubectl 读取 YAML/JSON 文件,将其转换为一个 API 对象(如 Pod、Deployment)。
  • kubectl 将 API 对象的声明式配置发送给 Kubernetes 集群的入口——kube-apiserver

阶段二:API 服务器处理与持久化 (kube-apiserver)
#

  • 认证与鉴权: kube-apiserver 验证用户身份,并检查其是否有权限执行此操作。
  • 准入控制: 请求通过一系列准入控制器(如 ResourceQuotaPodSecurity)进行修改或验证。
  • 持久化存储: 所有验证通过后,kube-apiserver 将 API 对象作为"期望状态"保存到集群的持久化存储 etcd 中。此时,Pod 资源已经被创建,但其状态为 Pending

阶段三:控制循环驱动资源创建 (Controller Manager)
#

这是实现"期望状态"与"实际状态"一致的核心。kube-controller-manager 中的各种控制器通过 Informer(List-Watch)机制监听 kube-apiserver 的资源变更事件(而非直接访问 etcd)。

以 Deployment 为例:

  • Deployment 控制器 监听到新的 Deployment 对象创建事件。
    • 根据 spec.replicas 等字段,计算并通过 kube-apiserver 创建对应的 ReplicaSet 对象,写入 etcd
  • ReplicaSet 控制器 监听到新的 ReplicaSet 对象创建事件。
    • 比较期望的 Pod 数量和当前实际的 Pod 数量,如果数量不足,则根据 Pod 模板通过 kube-apiserver 创建 Pod 对象,写入 etcd

如果是直接 kubectl apply 一个裸 Pod 的 YAML,则此阶段不涉及控制器,Pod 对象已在阶段二被直接创建。

阶段四:调度决策 (kube-scheduler)
#

  • 监听: kube-scheduler 通过 Informer 监听 kube-apiserver,寻找 nodeName 为空的 Pod(即未调度的 Pod)。
  • 调度周期:
    • 过滤: 根据资源请求、节点选择器、污点容忍等规则,过滤出所有可调度节点。
    • 评分: 对过滤后的节点进行打分(如资源均衡、亲和性等),选出最优节点。
    • 绑定: 调度器向 kube-apiserver 提交一个 Binding 对象,由 apiserver 将调度结果(nodeName)写回 etcd 中该 Pod 对象的定义里。此时,Pod 状态仍为 Pending,但已绑定到了目标节点。

阶段五:节点执行 (kubelet)
#

Pod 最终在目标工作节点上被创建和运行。

  • 监听: 目标节点上的 kubelet 通过 Informer 监听 kube-apiserver,发现有一个 Pod 被调度到了自己负责的节点上。
  • 创建 Pod 沙箱: kubelet 通过 CRI 调用容器运行时,为 Pod 创建"沙箱"环境(即 pause 容器,负责持有 Pod 的 Network Namespace 和 IPC Namespace)。
  • 配置网络: kubelet 调用 CNI 插件,为 Pod 沙箱配置网络,分配 Pod IP 地址。
  • 挂载存储: 如果 Pod 定义了 Volume,kubelet 通过 CSI 完成存储卷的挂载(Attach/Mount)。
  • 拉取镜像: 通过 CRI 通知容器运行时,按 Pod 定义中的镜像列表从镜像仓库拉取镜像。
  • 创建容器: 通过 CRI 调用容器运行时,在 Pod 沙箱内创建并启动应用容器。
  • 执行生命周期钩子: 如果定义了 postStart 钩子,此时执行。
  • 运行探针:
    • startupProbe(如果配置):首先运行,成功前其他探针不启动。防止慢启动容器被误杀。
    • startupProbe 成功(或未配置)后,livenessProbereadinessProbe 开始定期运行。
    • readinessProbe 首次成功之前,容器不会进入"就绪"状态,不会接收流量。

阶段六:状态上报与完成
#

  • 状态更新: 在容器启动和运行过程中,kubelet 持续收集 Pod 和容器的状态,通过 kube-apiserver 更新回 etcd
  • Running 状态: 当 Pod 中所有容器都已成功创建,且至少有一个容器正在运行时,Pod 的 phase 字段变为 Running。此时 kubectl get pods 显示状态为 Running
  • 就绪:readinessProbe 成功通过后,Pod 的"就绪"条件变为 True,kube-proxy 等组件才会将该 Pod 加入 Service 的 Endpoints,开始接收流量。

时序图
#

sequenceDiagram
    actor User
    participant kubectl
    participant apiserver as kube-apiserver
    participant etcd
    participant cm as controller-manager
    participant scheduler as kube-scheduler
    participant kubelet
    participant runtime as 容器运行时(CRI)
    participant cni as CNI 插件
    participant registry as 镜像仓库

    User->>kubectl: kubectl apply -f pod.yaml
    kubectl->>apiserver: POST /apis/.../deployments(声明式配置)

    Note over apiserver: 认证 → 鉴权 → 准入控制
    apiserver->>etcd: 写入 Deployment/Pod 对象(Pending)
    apiserver-->>kubectl: 200 OK

    Note over cm: Informer 监听 apiserver
    cm->>apiserver: 感知到 Deployment 创建事件
    cm->>apiserver: 创建 ReplicaSet
    apiserver->>etcd: 写入 ReplicaSet
    cm->>apiserver: 感知到 ReplicaSet 创建事件
    cm->>apiserver: 创建 Pod 对象(nodeName 为空)
    apiserver->>etcd: 写入 Pod(Pending,未调度)

    Note over scheduler: Informer 监听 apiserver
    scheduler->>apiserver: 感知到未调度的 Pod
    Note over scheduler: 过滤 → 评分 → 选出最优节点
    scheduler->>apiserver: 提交 Binding 对象(nodeName=node-1)
    apiserver->>etcd: 更新 Pod.spec.nodeName=node-1

    Note over kubelet: Informer 监听 apiserver(node-1)
    kubelet->>apiserver: 感知到 Pod 调度到本节点
    kubelet->>runtime: 创建 Pod 沙箱(pause 容器)
    runtime-->>kubelet: 沙箱创建成功
    kubelet->>cni: 配置网络,分配 Pod IP
    cni-->>kubelet: IP 分配成功
    kubelet->>runtime: 拉取应用镜像
    runtime->>registry: 拉取镜像
    registry-->>runtime: 镜像拉取完成
    kubelet->>runtime: 创建并启动应用容器
    runtime-->>kubelet: 容器启动成功
    kubelet->>kubelet: 执行 postStart 钩子(如有)
    kubelet->>kubelet: 运行 startupProbe(如有)
    kubelet->>kubelet: startupProbe 成功后运行 livenessProbe / readinessProbe

    kubelet->>apiserver: 上报 Pod 状态(phase=Running)
    apiserver->>etcd: 更新 Pod 状态
    kubelet->>apiserver: readinessProbe 成功,上报 Ready=True
    apiserver->>etcd: 更新 Pod Ready 条件
    apiserver-->>User: kubectl get pods → Running / Ready