K8s 中创建一个 Deployment 的完整流程
流程分为 两大阶段 :提交阶段 和 控制循环实现阶段。下图直观地展示了整个流程及其核心组件的交互:
节点工作平面 控制平面内部流程 写入状态 通知 通知 创建ReplicaSet Manifest 创建Pod Manifest 通知 筛选与绑定 调用容器运行时 上报状态 Scheduler Kubelet 创建Pod容器 API Server kubectl 转换并发送
Deployment Manifest 至 API Server etcd Deployment Controller ReplicaSet Controller 用户执行 kubectl apply -f deployment.yaml
第一阶段:提交与接收 (You → API Server)
-
用户提交 Manifest :
你使用
kubectl apply -f deployment.yaml命令。kubectl会读取你的 YAML 文件,将其转换为 JSON 格式,并通过一个 HTTPS POST 请求发送给 Kubernetes API Server。 -
API Server 处理:
- 认证(Authentication): API Server 首先检查你的身份(例如,检查证书、Token 或用户名/密码),确认你有权限执行此操作。
- 授权(Authorization): 认证通过后,API Server 会检查你的权限是否允许在指定的命名空间(Namespace)里创建 Deployment 资源(例如,通过 RBAC 机制)。
- 准入控制(Admission Control) : 请求随后会经过一系列准入控制器(Admission Controllers)的拦截和修改。例如,
ResourceQuota控制器会检查你的命名空间资源配额是否已满,DefaultStorageClass控制器可能会为 PVC 设置默认存储类。 - 验证(Validation): API Server 会校验你提交的 Deployment Manifest 的语法和结构是否合法。
-
持久化存储 :
在所有检查都通过后,API Server 会将你提交的这个 Deployment 对象的新期望状态(Desired State) 作为一个新的条目(Entry)写入到分布式键值存储数据库 etcd 中。
至此,你的指令已经被集群接收并记录。接下来的所有事情,都是由 K8s 的各个控制器自动完成的。
第二阶段:控制循环实现状态 (Controller Loop)
-
Deployment Controller 监控:
- 在 Controller Manager 中运行着的 Deployment Controller 一直在通过 API Server 监听(Watch)着 etcd 中与 Deployment 相关的变更。
- 它发现了一个新的 Deployment 对象被创建了(或者旧的被更新了)。
-
Deployment Controller 创建 ReplicaSet:
- Deployment Controller 读取到 Deployment 的期望状态(例如,需要 3 个副本
replicas: 3)。 - 它会根据 Pod 模板(
template)生成一个对应的 ReplicaSet 对象(Manifest),并通过 API Server 将其写入 etcd。 - 注意:Deployment 本身并不直接管理 Pod,它是通过管理 ReplicaSet 来间接管理 Pod 的。这是为了实现滚动更新和版本回滚。
- Deployment Controller 读取到 Deployment 的期望状态(例如,需要 3 个副本
-
ReplicaSet Controller 监控:
- 同样在 Controller Manager 中的 ReplicaSet Controller 监听到了这个新创建的 ReplicaSet 对象。
-
ReplicaSet Controller 创建 Pod:
- ReplicaSet Controller 比较当前状态 (当前存在的 Pod 数量)和期望状态(Deployment 中定义的副本数)。
- 它发现当前 Pod 数量(0个)少于期望数量(3个)。
- 于是,它会根据 Pod 模板,通过 API Server 创建 3 个 Pod 对象 (Manifest)并写入 etcd。注意,此时只是创建了 Pod 的元数据信息 ,Pod 还没有被调度到任何节点上运行。
-
Scheduler 调度 Pod:
- Scheduler 一直在监听 API Server,它发现了有新的、且
nodeName为空的 Pod 对象(即未被调度的 Pod)。 - Scheduler 作为一个非常智能的调度器,会执行一系列复杂的筛选和评分步骤来为每个 Pod 选择一个最合适的 Node:
- 筛选(Filtering) : 排除所有不满足条件的节点(例如,资源不足、不满足节点选择器
nodeSelector、端口冲突、不满足亲和性规则等)。 - 评分(Scoring): 对通过筛选的节点进行打分(例如,考虑资源平衡、跨可用区部署等),选择得分最高的节点。
- 筛选(Filtering) : 排除所有不满足条件的节点(例如,资源不足、不满足节点选择器
- 做出决定后,Scheduler 会更新 etcd 中 Pod 对象的定义,将其
nodeName字段赋值为选定的节点名称。这个操作称为 "绑定"(Binding)。
- Scheduler 一直在监听 API Server,它发现了有新的、且
-
Kubelet 创建容器:
- 每个 Node 上的 Kubelet 进程也在通过 API Server 监听有哪些 Pod 被分配到了自己所在的节点(即
nodeName是自己的节点名)。 - 它发现了有 Pod 被调度到了自己这里。
- Kubelet 会读取 Pod 的详细定义,然后调用本地的容器运行时(例如 Docker, containerd, CRI-O),指示它从镜像仓库拉取指定镜像并启动容器。
- Kubelet 还会根据 Pod 定义中的要求,设置卷(Volume)、网络(由 CNI 插件负责)等。
- 每个 Node 上的 Kubelet 进程也在通过 API Server 监听有哪些 Pod 被分配到了自己所在的节点(即
-
状态上报与收敛:
- Kubelet 会持续监控它启动的 Pod 和容器的状态(是否是 Running、Healthy)。
- 它通过 API Server 定期上报 Pod 的当前状态(Current State) 到 etcd。
- ReplicaSet Controller 和 Deployment Controller 也会持续监控这些状态变化,确保当前状态始终与期望状态一致。如果某个 Pod 意外终止,ReplicaSet Controller 会检测到数量不一致,并立即创建一个新的 Pod 来替换它,从而实现"自愈"。
总结
这个流程的核心在于 "声明式API" 和 "控制循环":
- 你声明期望状态(在 YAML 文件中定义)。
- 提交给 API Server。
- 一系列控制器 (Deployment, ReplicaSet)监听、比较、驱动,逐步创建所需的下层资源(ReplicaSet -> Pod)。
- 调度器(Scheduler)为 Pod 分配节点。
- 节点代理 (Kubelet)接收指令并真正执行,创建容器。
- 整个系统不断反馈和调整,使当前状态向期望状态收敛。