当你执行 kubectl apply -f deployment.yaml 时,Kubernetes 并不是”一次性”创建出所有 Pod。它启动了一个多阶段的控制循环:kubectl 将 YAML 提交给 API Server,API Server 经过认证、鉴权、准入控制后写入 etcd;Deployment Controller 监听到新对象,创建 ReplicaSet;ReplicaSet Controller 再创建 Pod;Scheduler 为 Pod 选择节点;kubelet 在节点上启动容器。
理解这个流程,就理解了 Kubernetes 声明式 API 与控制器模式的核心机制。
一、全局视角:创建 Deployment 的完整流程
二、第一阶段:kubectl → API Server
2.1 kubectl 的处理
kubectl apply 并不是简单地发送 YAML 文本。它做了以下工作:
- 读取 YAML 文件:解析为 Kubernetes API 对象
- 计算变更:对比当前集群中的对象和 YAML 中的对象,生成增量补丁(如果对象已存在)
- 发送请求:通过 HTTP POST(新对象)或 PATCH(更新对象)发送到 API Server
# 查看 kubectl 实际发送的请求kubectl apply -f deployment.yaml --v=8
# 输出(简化):# I0513 POST https://api-server:6443/apis/apps/v1/namespaces/default/deployments# Request Body: {"kind":"Deployment","metadata":{"name":"nginx"},...}2.2 API Server 认证
API Server 首先验证请求者的身份:
| 认证方式 | 说明 | 适用场景 |
|---|---|---|
| X509 证书 | kubectl 使用 kubeconfig 中的客户端证书 | 管理员操作 |
| ServiceAccount Token | Pod 内自动挂载的 JWT Token | Pod 内访问 API |
| OIDC Token | 外部身份提供商(如 LDAP、GitHub) | 企业统一认证 |
2.3 API Server 鉴权(RBAC)
认证通过后,API Server 检查请求者是否有权限执行该操作:
用户: admin操作: POST /apis/apps/v1/namespaces/default/deploymentsRBAC 检查: ClusterRoleBinding admin → ClusterRole cluster-admin → 允许RBAC 的检查逻辑:遍历所有与用户关联的 RoleBinding/ClusterRoleBinding,检查对应的 Role/ClusterRole 是否包含匹配的规则。
2.4 准入控制链
鉴权通过后,请求进入准入控制链(Admission Chain)。准入控制器可以修改(Mutating)或验证(Validating)请求对象:
常见的准入控制器:
| 控制器 | 类型 | 作用 |
|---|---|---|
| NamespaceLifecycle | Validating | 防止在终止中的 Namespace 创建对象 |
| LimitRanger | Mutating | 为未设置资源限制的 Pod 注入默认值 |
| ServiceAccount | Mutating | 为 Pod 注入 ServiceAccount 和 Token Volume |
| PodSecurity | Validating | 检查 Pod 是否符合安全标准 |
| ResourceQuota | Validating | 检查是否超出 Namespace 配额 |
| DefaultTolerationSeconds | Mutating | 为 Pod 注入默认容忍时间 |
| MutatingAdmissionWebhook | Mutating | 调用自定义 Webhook 修改对象 |
| ValidatingAdmissionWebhook | Validating | 调用自定义 Webhook 验证对象 |
Mutating 阶段先执行,Validating 阶段后执行。Mutating 阶段可以修改对象(如注入 sidecar、设置默认值),Validating 阶段只能接受或拒绝。Webhook 准入控制器是扩展 Kubernetes 的核心机制——详见 Kubernetes 扩展机制。
三、第二阶段:etcd 持久化
准入控制通过后,API Server 将对象序列化为 JSON 并写入 etcd:
{ "kind": "Deployment", "apiVersion": "apps/v1", "metadata": { "name": "nginx", "namespace": "default", "uid": "a1b2c3d4-...", "creationTimestamp": "2026-05-13T10:00:00Z", "resourceVersion": "12345" }, "spec": { "replicas": 3, "selector": {...}, "template": {...} }, "status": { "replicas": 0, "updatedReplicas": 0, "conditions": [...] } }etcd 的关键特性:
- 强一致性:使用 Raft 协议,确保所有节点数据一致
- Watch 支持:客户端可以监听键的变化,实时获取通知
- 版本管理:每个对象有
resourceVersion,用于乐观并发控制
etcd 是集群的核心——如果 etcd 不可用,整个集群无法创建/更新/删除任何对象。生产环境必须部署 3-5 个 etcd 节点,确保高可用。
四、第三阶段:Deployment Controller
4.1 Informer 机制
Controller 不直接轮询 API Server,而是使用 Informer 机制:
Informer 的工作流程:
- List:首次启动时,从 API Server 获取所有 Deployment 对象,建立本地缓存
- Watch:之后监听 API Server 的变更事件,实时更新本地缓存
- 回调:缓存更新后触发 OnAdd/OnUpdate/OnDelete 回调,Controller 在回调中执行业务逻辑
Informer 的优势:减少 API Server 压力(不需要反复 List),响应速度快(Watch 事件实时推送)。
4.2 Deployment Controller 的处理
当 Deployment Controller 收到新 Deployment 的 OnAdd 回调时:
- 检查是否已有匹配的 ReplicaSet
- 如果没有,创建新的 ReplicaSet(初始版本
revision=1) - 设置 ReplicaSet 的
replicas为 Deployment 的replicas值 - 更新 Deployment 的
status字段
# Deployment Controller 创建的 ReplicaSetapiVersion: apps/v1kind: ReplicaSetmetadata: name: nginx-7d6f5c4b2d # 自动生成的名称(包含 Pod 模板哈希) labels: app: nginx pod-template-hash: 7d6f5c4b2d # Deployment 自动添加的标签 ownerReferences: # 声明 ReplicaSet 属于 Deployment - apiVersion: apps/v1 kind: Deployment name: nginx uid: a1b2c3d4-... controller: truespec: replicas: 3 selector: matchLabels: app: nginx pod-template-hash: 7d6f5c4b2d template: ... # 与 Deployment 的 Pod 模板一致ownerReferences 是 Kubernetes 的垃圾回收机制——当 Deployment 被删除时,所有引用它的 ReplicaSet 和 Pod 都会被自动回收。
五、第四阶段:ReplicaSet Controller
ReplicaSet Controller 监听新 ReplicaSet 的创建:
- 计算当前匹配
selector的 Pod 数量 - 当前数量 <
replicas(0 < 3):需要创建 3 个 Pod - 按 ReplicaSet 的
template创建 Pod,每个 Pod 的ownerReferences指向 ReplicaSet
# ReplicaSet Controller 创建的 PodapiVersion: v1kind: Podmetadata: name: nginx-7d6f5c4b2d-abc12 # 自动生成 labels: app: nginx pod-template-hash: 7d6f5c4b2d ownerReferences: - apiVersion: apps/v1 kind: ReplicaSet name: nginx-7d6f5c4b2d controller: truespec: nodeName: "" # 未指定节点,等待调度 containers: - name: nginx image: nginx:1.25注意 Pod 的 nodeName 为空——这意味着 Pod 还没有被调度,Scheduler 将负责选择目标节点。
六、第五阶段:Scheduler 调度
Scheduler 监听 nodeName="" 的 Pod,为它们选择最合适的 Node。
6.1 调度算法
**预选(Filter)**阶段排除不满足硬性条件的 Node:
| 预选条件 | 说明 |
|---|---|
| PodFitsResources | Node 的可分配资源是否满足 Pod 的 requests |
| PodFitsHostPorts | Node 的 HostPort 是否已被占用 |
| PodMatchNodeSelector | Pod 的 nodeSelector/nodeAffinity 是否匹配 |
| NoDiskConflict | Pod 的 Volume 是否与 Node 上已有 Volume 冲突 |
| PodToleratesNodeTaints | Pod 的 tolerations 是否能容忍 Node 的 taints |
**优选(Score)**阶段为满足条件的 Node 打分:
| 优选策略 | 说明 |
|---|---|
| LeastRequestedPriority | 优先选择资源使用率最低的 Node(Spread 策略) |
| MostRequestedPriority | 优先选择资源使用率最高的 Node(Bin-Packing 策略) |
| BalancedResourceAllocation | CPU 和内存使用率尽量均衡 |
| NodeAffinityPriority | 优先满足 Node 亲和性 |
| ImageLocalityPriority | 优先选择已拉取所需镜像的 Node |
6.2 绑定
Scheduler 选择 Node 后,向 API Server 发送 Bind 请求:
apiVersion: v1kind: Bindingmetadata: name: nginx-7d6f5c4b2d-abc12target: apiVersion: v1 kind: Node name: node-2API Server 更新 Pod 的 nodeName 字段为 node-2。
七、第六阶段:kubelet 启动容器
kubelet 在每个 Node 上运行,通过 Watch 监听分配到本节点的 Pod。
7.1 kubelet 的 Pod 处理流程
7.2 CRI:容器创建
kubelet 通过 CRI(Container Runtime Interface)与容器运行时通信:
kubelet → containerd(通过 gRPC) CreateContainer(podConfig) → 返回 containerID StartContainer(containerID) → 容器进程启动CRI 的关键步骤:
- 拉取镜像(
image: nginx:1.25) - 创建 Pause 容器(持有 Pod Network Namespace)
- 创建应用容器(加入 Pause 的 Network Namespace)
- 启动容器进程
7.3 CNI:网络配置
kubelet 调用 CNI 插件为 Pod 配置网络:
kubelet → CNI 插件(如 Calico/Cilium) ADD: 创建 veth pair、配置 IP、设置路由CNI 插件的工作:
- 创建 veth pair(一端在 Pod Network Namespace,一端在宿主机)
- 为 Pod 分配 IP(从 Pod CIDR 中分配)
- 配置 Pod 内的路由和 DNS
- 配置宿主机的路由(将 Pod IP 路由到 veth 对)
- 如果是跨节点通信,配置节点间的路由或封装规则
7.4 CSI:存储挂载
如果 Pod 引用了 PVC,kubelet 调用 CSI 插件挂载存储:
kubelet → CSI 插件 NodeStageVolume → 将存储挂载到临时目录 NodePublishVolume → 将临时目录 bind-mount 到 Pod 目录7.5 状态上报
容器启动后,kubelet 定期向 API Server 上报 Pod 状态:
status: phase: Running conditions: - type: Ready status: "True" containerStatuses: - name: nginx ready: true restartCount: 0 state: running: startedAt: "2026-05-13T10:01:30Z"八、滚动更新的完整流程
当更新 Deployment 的镜像版本时(nginx:1.25 → nginx:1.26),触发滚动更新:
滚动更新的关键控制参数:
spec: strategy: rollingUpdate: maxSurge: 1 # 最多多创建 1 个 Pod maxUnavailable: 0 # 最多允许 0 个 Pod 不可用 minReadySeconds: 30 # Pod Ready 后等待 30 秒才继续 progressDeadlineSeconds: 600 # 10 分钟内未完成则标记为 Progressing=FalseDeployment Controller 的更新逻辑:
- 创建新 ReplicaSet(
revision=2),初始replicas=0 - 按策略逐步扩容新 ReplicaSet、缩容旧 ReplicaSet
- 每次扩容前等待新 Pod 的 Readiness Probe 通过
- 如果
progressDeadlineSeconds内未完成,标记 Deployment 为失败 - 旧 ReplicaSet 保留(
replicas=0),用于回滚
九、回滚机制
kubectl rollout undo deployment/nginx回滚时,Deployment Controller:
- 找到上一个 ReplicaSet(
revision=1) - 将旧 ReplicaSet 的
replicas扩容到 3 - 将当前 ReplicaSet(
revision=2)的replicas缩容到 0 - 更新 Deployment 的
image回退到nginx:1.25
整个过程与滚动更新的逻辑相同——只是方向相反。
总结
| 阶段 | 组件 | 关键机制 |
|---|---|---|
| kubectl → API Server | kubectl, API Server | 认证/鉴权/准入控制链 |
| etcd 持久化 | API Server, etcd | Raft 强一致性、Watch 机制 |
| Deployment → ReplicaSet | Deployment Controller | Informer + 控制循环 |
| ReplicaSet → Pod | ReplicaSet Controller | Pod 模板 + ownerReferences |
| Pod 调度 | Scheduler | 预选 Filter + 优选 Score |
| 容器启动 | kubelet | CRI 创建容器 + CNI 配置网络 + CSI 挂载存储 |
| 滚动更新 | Deployment Controller | 新 RS 扩容 + 旧 RS 缩容 |
| 回滚 | Deployment Controller | 旧 RS 扩容 + 新 RS 缩容 |
整个流程的核心是声明式 API + 控制器模式——kubectl 只描述期望状态,多个控制器各自负责一部分收敛工作,通过 Watch 机制实时响应变更,通过 ownerReferences 管理对象间的依赖关系。
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
部分信息可能已经过时






