3. 发布流水线典型流程:从代码提交到Pod就绪的全链路分解
在K8s平台中,一次标准的发布流水线通常涉及代码仓库、CI系统、镜像仓库、K8s API Server、etcd、Scheduler、Kubelet等多个组件。理解这条链路上的每一个环节,是后续通过etcd日志进行异常定位的基础。本章将全链路分解为8个关键阶段,并标注每个阶段与etcd的交互点。
3.1 全链路阶段总览
下表列出了从开发者提交代码到Pod最终进入Ready状态的完整阶段、核心操作及etcd参与情况:
| 阶段 | 核心操作 | etcd交互点 | 典型耗时 |
|---|---|---|---|
| 1. 代码提交与CI构建 | Git Push → CI触发编译、单元测试、镜像打包 | 无直接交互 | 1~10 min |
| 2. 镜像推送与版本标记 | Docker Push 至镜像仓库,生成唯一镜像摘要 | 无直接交互 | 30 s~3 min |
| 3. 更新Deployment资源 | kubectl set image / 调用API修改Deployment镜像版本 | 写入:Deployment对象更新 | 1~2 s |
| 4. ReplicaSet版本演进 | Deployment Controller创建新RS,期望副本数逐步迁移 | 写入:RS对象创建;读取:监听Deployment变化 | 1~5 s |
| 5. Pod调度决策 | Scheduler为未绑定Pod选择最优Node,写入绑定信息 | 写入:Pod绑定记录;读取:Node资源状态 | 100 ms~5 s |
| 6. Kubelet拉取镜像 | Kubelet根据PodSpec拉取新版本镜像 | 无直接交互(镜像拉取状态通过Pod Status间接写入) | 10 s~2 min |
| 7. 容器启动与健康检查 | CRI创建容器,执行ReadinessProbe/LivenessProbe | 写入:Pod状态更新(Conditions) | 5~30 s |
| 8. Pod就绪与流量接入 | Endpoint Controller更新Service Endpoints,流量引入新Pod | 写入:Endpoints对象更新 | 1~3 s |
关键洞察: 阶段3、4、5、7、8均涉及etcd的写入操作。当发布流水线出现异常时,etcd中对应对象的
resourceVersion跳跃、conditions字段缺失或binding记录异常,往往是根因定位的第一手线索。
3.2 核心阶段详细分解
3.2.1 阶段3:更新Deployment资源
这是流水线从CI/CD工具进入K8s集群的第一个etcd写入点。操作通常通过kubectl set image deployment/xxx image=new-version或直接调用API完成。
- etcd写入内容:Deployment的
spec.template.spec.containers[].image字段被修改,同时metadata.generation自增。 - 异常样本:如果此时etcd写入超时或返回
EtcdError: leader changed,Deployment将停留在旧版本,流水线卡死。
3.2.2 阶段5:Pod调度决策
Scheduler通过Watch机制从etcd获取未调度的Pod(spec.nodeName为空),经过预选、优选后,将Pod与Node的绑定关系写入etcd。
- etcd写入内容:Pod对象的
spec.nodeName字段被赋值,同时status.conditions中新增PodScheduled=True。 - 异常样本:若Scheduler因Node资源不足无法调度,Pod的
status.conditions中会出现Unschedulable状态,etcd中该Pod长时间处于Pending。
3.2.3 阶段7:容器启动与健康检查
Kubelet在节点上启动容器后,会持续执行ReadinessProbe。当探测成功时,Kubelet将Pod的status.conditions中的Ready条件置为True,并写入etcd。
- etcd写入内容:Pod的
status.phase从Running变为Running(不变),但status.conditions[].type=Ready变为True。 - 异常样本:镜像拉取失败或启动命令错误会导致
Ready条件长期为False,etcd中Pod的containerStatuses[].state.waiting.reason字段会记录ImagePullBackOff或CrashLoopBackOff。
3.3 全链路数据流与etcd交互SVG
下图展示了从代码提交到Pod就绪的完整数据流,并重点标注了etcd在其中的读写位置:
3.4 关键时间窗口与etcd版本号变化
在发布过程中,etcd中对象的resourceVersion是追踪变更顺序的核心指标。以下是一个典型发布过程中Deployment及其子对象在etcd中的版本号变化示例:
# 初始状态:Deployment v1,RS v1,Pod v1~v3
/deployments/nginx resourceVersion: 1000
/replicasets/nginx-xxx resourceVersion: 1001
/pods/nginx-xxx-a resourceVersion: 1002
# 阶段3:更新Deployment镜像(etcd写入)
/deployments/nginx resourceVersion: 1050 ← 版本跳跃
# 阶段4:Controller创建新RS(etcd写入)
/replicasets/nginx-yyy resourceVersion: 1051 ← 新RS出现
# 阶段5:Scheduler绑定Pod(etcd写入)
/pods/nginx-yyy-a resourceVersion: 1052 ← nodeName被赋值
# 阶段7:Kubelet更新Pod状态(etcd写入)
/pods/nginx-yyy-a resourceVersion: 1060 ← Ready=True
异常定位要点: 如果发布卡在“Pod启动中”阶段,应重点检查etcd中Pod对象的
resourceVersion是否长时间未变化。若超过30秒无更新,通常意味着Kubelet未成功将状态写回etcd,可能原因包括:镜像拉取阻塞、CNI网络插件异常、或etcd写入性能瓶颈。
3.5 流水线各阶段异常与etcd日志的对应关系
下表总结了发布流水线各阶段常见异常在etcd日志中的典型表现,为后续章节的根因定位提供直接映射:
| 流水线阶段 | 常见异常 | etcd日志/对象特征 |
|---|---|---|
| 3. 更新Deployment | API Server超时、版本冲突 | etcd日志出现 etcdserver: request timed out;Deployment的metadata.generation未递增 |
| 4. RS版本演进 | Controller未创建新RS | etcd中无新的RS对象出现;Deployment的status.observedGeneration落后于generation |
| 5. Pod调度 | 资源不足、节点故障 | Pod的status.conditions包含Unschedulable;etcd中该Pod的spec.nodeName为空 |
| 6. 拉取镜像 | 镜像不存在、仓库认证失败 | Pod的status.containerStatuses[].state.waiting.reason为ImagePullBackOff;etcd中Pod状态频繁更新但Ready始终为False |
| 7. 健康检查 | 启动命令错误、探针配置不当 | Pod的status.conditions[].type=Ready为False且lastTransitionTime长时间未更新;etcd中restartCount持续递增 |
| 8. Pod就绪 | Endpoint未更新、Service选择器不匹配 | etcd中Endpoints对象的subsets[].addresses不包含新Pod IP;Service的status.loadBalancer.ingress为空 |
3.6 全链路时序与etcd写入点SVG
下图以时间轴形式展示发布流水线各阶段与etcd写入事件的对应关系,帮助理解异常发生时etcd日志的时间戳上下文:
3.7 本章小结
发布流水线的全链路分解揭示了以下核心结论:
- etcd是发布流水线的“状态中枢”:8个阶段中有5个阶段直接依赖etcd的写入操作,任何etcd性能问题或写入失败都会导致流水线阻塞。
- resourceVersion是追踪异常的时间线:通过对比Deployment、RS、Pod等对象的版本号变化,可以快速定位异常发生的具体阶段。
- Pod的status.conditions是异常诊断的“第一现场”:
Unschedulable、ImagePullBackOff、CrashLoopBackOff等状态直接反映在etcd存储的Pod对象中。