从执行 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验证用户身份,并检查其是否有权限执行此操作。 - 准入控制: 请求通过一系列准入控制器(如
ResourceQuota、PodSecurity)进行修改或验证。 - 持久化存储: 所有验证通过后,
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。
- 比较期望的 Pod 数量和当前实际的 Pod 数量,如果数量不足,则根据 Pod 模板通过
如果是直接
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成功(或未配置)后,livenessProbe和readinessProbe开始定期运行。- 在
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