☰
深入解析 Pod_ContainerCreating 云盘挂载超时或冲突:基于 chaosblade 技能库的 K8s 故障演练实战指南
2026/10/9 5:22:24 网站建设 项目流程
  • 运维
  • 云原生
  • SRE
  • AI Agent
  • 人工智能

【免费下载链接】chaosblade

An easy to use and powerful chaos engineering experiment toolkit.(阿里巴巴开源的一款简单易用、功能强大的混沌实验注入工具)

项目地址:https://gitcode.com/gh_mirrors/ch/chaosblade
点击查看免费下载

导读

当 Kubernetes Pod 长时间卡在ContainerCreating状态时,最常见的根因之一是云盘(块存储卷)挂载超时或 Multi-Attach 冲突——特别是使用ReadWriteOnce(RWO)模式的云盘被其他节点/Pod 占用时。本文以 chaosblade 仓库中 k8s-chaos-skills 技能库收录的 云盘挂载超时或冲突用例 为骨架,完整还原其故障现象、资源准备、演练步骤、注入验证与恢复流程,并结合仓库内同族用例、Chaosblade K8s 命令速查表 及脚本源码进行纵深讲解。读者将掌握:如何在不修改业务代码的前提下,仅通过原生 kubectl 操作精准复现 Multi-Attach 冲突类故障,如何依据 Events 证据判定注入是否生效,以及如何安全、可回滚地完成恢复并输出标准演练报告。

一、Pod_ContainerCreating 故障分类与用例目录结构

在 k8s-chaos-skills 技能库中,所有故障用例遵循「故障分类目录 + 根因文件」的命名规约存放在references/catalogue/下,目录名对应故障层级_故障现象,文件名对应分类_具体根因。以Pod_ContainerCreating分类为例,当前仓库收录了 4 个不同根因的用例:

用例文件(相对路径)根因关键 Events 证据
Pod_ContainerCreating_CNI分配失败.md节点 IP 池耗尽 / ENI 数量达上限failed to allocate for ENI/no available IP in subnet
Pod_ContainerCreating_Volume挂载超时CSI异常.mdCSI 驱动异常 / 云盘与节点可用区不匹配FailedMount/FailedAttachVolume/ CSI 超时
Pod_ContainerCreating_云盘挂载超时或冲突.md云盘(RWO)被其他节点/Pod 占用Multi-Attach error/AttachVolume.Attach failed
Pod_ContainerCreating_容器运行时异常.mdcontainerd/docker 进程异常或 hangcontainer runtime is not ready/rpc error

从源码结构看,这种「目录即分类、文件名即根因」的设计使得 Agent 可以通过 list_scenarios.py 脚本动态发现全部场景,无需维护静态索引。该脚本会遍历references/catalogue/下每个分类目录,解析目录名得到level(故障层级)与symptom(故障现象),解析文件名得到root_cause,最终输出 JSON 结构化清单(含total、category_count、categories等字段),方便快速总览或对接外部系统。

二、云盘挂载超时或冲突:故障机理与基准事实

2.1 根因分析

云盘类型的 PersistentVolume 通常以accessModes: ["ReadWriteOnce"]创建,这意味着同一时刻仅允许一个节点挂载该卷。当集群中存在多节点,且同一 PVC 被调度到不同节点上的多个 Pod 引用时,后到的节点无法执行 Attach 操作,volume mount 阶段会一直阻塞,Pod 便长期停留在ContainerCreating。

该用例在「基准事实」一节给出了明确界定:

  • 根因:云盘(ReadWriteOnce)被其他节点/Pod 占用,新 Pod 无法 attach 该云盘,导致 volume mount 阶段阻塞;
  • 必现现象:Pod ContainerCreating;Events 显示Multi-Attach error或AttachVolume失败;PV 被其他节点占用。

注意:这里的「多 Pod 引用同一 PVC」并非持久卷的合法使用方式——RWO 模式下 Kubernetes 本身就禁止多节点同时挂载。该演练的本质是人为构造非法调度,使 PV 的 attach 状态与调度结果发生冲突,从而暴露调度器、attach-detach 控制器、CSI 插件的处理行为。

2.2 故障现象清单

演练前需要能准确识别目标故障,官方用例给出的现象为:

  1. Pod 长时间停留在ContainerCreating状态;
  2. Pod Events 中显示Multi-Attach error或AttachVolume.Attach failed;
  3. 云盘被其他节点占用,无法 attach 到当前节点。

其中 Events 证据是判定故障生效的关键——kubectl describe pod中的Multi-Attach error是 attach-detach controller(或 CSI attach 逻辑)在检测到卷已挂载到其他节点时产生的典型报错,与「云盘真实损坏」「CSI 驱动超时」等现象可明确区分。

三、演练前置条件与资源准备

执行本用例前需确认两项资源准备,缺一不可:

  1. 应用 A 已正常运行,且使用了云盘类型的 PVC(accessMode为ReadWriteOnce);
  2. 集群中有多个节点(这是 Multi-Attach 冲突成立的前提——冲突需要「另一个节点」来抢占卷)。

建议同时遵循 SKILL.md 中声明的安全红线:

  • 隔离:在隔离命名空间或测试集群演练,严禁在生产核心链路注入;
  • 最小影响:用精确标签选择器定位目标,范围尽可能小;
  • 可回滚:注入前明确回滚方案,确保 30 秒内可恢复;
  • 有监控:无监控不演练;
  • 仅限已有用例:只能执行references/catalogue/中已有的故障注入用例,严禁自行编造、拼凑或即兴发挥用例中未涉及的故障注入操作。无法匹配时必须明确告知用户「当前不支持该场景」并停止;
  • 禁止:业务高峰期演练 / 对 etcd、kube-apiserver 等控制平面注入 / 无备份对 StatefulSet 做破坏性实验。

四、演练步骤:用原生 kubectl 构造 Multi-Attach 冲突

本用例不需要注入 blade 实验,而是通过创建「抢占 Pod」的方式,在另一个节点上强制挂载应用 A 的 PVC,从而制造真实的 Multi-Attach 冲突。整个流程分为四步。

4.1 定位应用 A 的 PVC 与 PV

先确认应用 A 使用的 PVC 名称及其绑定的 PV,后续步骤需要这两个资源作为参照:

# 查看应用 A 的 PVC(注意 accessModes 应为 ReadWriteOnce) kubectl get pvc -n <namespace> # 查看 PVC 绑定到的 PV 名称 kubectl get pvc <app-a-pvc> -n <namespace> -o jsonpath='{.spec.volumeName}' # 查看 PV 详情(可观测其 nodeAffinity / volumeHandle) kubectl describe pv <pv-name>

4.2 在另一节点创建抢占 Pod

在另一个节点上创建一个临时 Pod(命名chaos-volume-holder),直接引用应用 A 的 PVC。通过nodeName将 Pod 硬绑定到指定节点,确保卷被「另一个节点」抢占:

apiVersion: v1 kind: Pod metadata: name: chaos-volume-holder namespace: <namespace> spec: nodeName: <另一节点> containers: - name: holder image: busybox command: ["sleep", "3600"] volumeMounts: - name: data mountPath: /data volumes: - name: data persistentVolumeClaim: claimName: <应用A的PVC名称>

执行创建:

kubectl apply -f chaos-volume-holder.yaml

用例原文的 YAML 注释提到「通过直接指定 PV 的 volumeHandle 创建新 PV/PVC 对」来模拟冲突,属于进阶变体:当无法直接引用业务 PVC 时,可基于原 PV 的volumeHandle另建一套 PV/PVC 指向同一块云盘,达到同样的 Multi-Attach 效果。基础路径则直接引用<应用A的PVC名称>,操作更简单、更贴近真实场景。

4.3 删除应用 A 的旧 Pod,触发在其他节点重建

抢占 Pod 成功挂载云盘后,删除应用 A 原来的 Pod,使 ReplicaSet/Deployment 控制器在其他节点上重建副本:

kubectl delete pod <app-a-old-pod> -n <namespace>

由于云盘已被chaos-volume-holder所在节点独占(RWO),新副本所在节点无法执行 Attach,Pod 创建流程将阻塞在 volume 阶段。

4.4 观察新 Pod 的 ContainerCreating 状态

等待数十秒后执行kubectl get pods -o wide,预期应用 A 的新 Pod 长期停留在ContainerCreating,且调度节点与原 Pod 不同。

五、注入验证:以 Events 证据确认故障生效

注入是否成功的判定不能只依赖 Pod 状态,必须核对 Events 中的关键证据:

# 1. 确认应用 A 的新 Pod 状态为 ContainerCreating kubectl get pods -n <namespace> # 2. 确认 Events 显示 Multi-Attach error 或 volume attach 失败 kubectl describe pod <pod-name> -n <namespace> # 3. 确认 PV 仍 attach 在占用它的节点上 kubectl describe pv <pv-name>

判定要点:

  • Pod Phase 必须为ContainerCreating(而不是 Pending 或其他状态);
  • Events 中必须出现Multi-Attach error、AttachVolume.Attach failed或等价的 volume attach 失败信息;
  • PV 的 attach 状态应停留在抢占节点(chaos-volume-holder所在节点),而不是应用 A 的新节点。

只有当上述三点全部满足时,才能判定故障注入成功(verified)。若新 Pod 恰好调度回原节点(云盘仍可复用),或 Events 显示的是镜像拉取等其他错误,则说明故障未按预期生效,需要重新排查节点选择逻辑。

六、注入恢复与恢复验证

6.1 恢复步骤

  1. 删除临时抢占 Pod:
kubectl delete pod chaos-volume-holder --force --grace-period=0

--force --grace-period=0用于跳过优雅终止期强制删除。由于该 Pod 持有云盘挂载,kubelet 卸载卷与 API Server 删除 Pod 之间存在时序,强制删除可加快 detach 流程,避免等待挂起。

  1. 等待云盘从原节点 detach(attach-detach controller / CSI 插件完成卸载,通常数十秒);
  2. 等待应用 A 的 Pod 自动完成 volume attach——新节点此时获得卷的挂载权,Pod 应自动进入 Running。

6.2 恢复验证

# 1. 确认应用 A 的 Pod 状态恢复为 Running kubectl get pods -n <namespace> # 2. 确认 volume 成功 attach 并 mount kubectl describe pod <pod-name> -n <namespace> kubectl describe pv <pv-name> # 3. 确认应用 A 数据读写正常(进入容器执行读写检查) kubectl exec -it <pod-name> -n <namespace> -- ls -l /data

恢复验证通过的标准:Pod 恢复Running、volume 状态为 Attached/Mounted、业务数据可正常读写。

七、同族故障对比:ContainerCreating 的其他三个根因

同一故障现象(Pod ContainerCreating)可由完全不同的底层原因触发,演练时需按根因区分。以下三个用例与「云盘挂载冲突」互为对照,便于读者建立完整的故障识别矩阵。

7.1 Volume 挂载超时 / CSI 可用区不匹配

见 Pod_ContainerCreating_Volume挂载超时CSI异常.md。其核心思路是构造跨可用区的 PV/PVC:通过nodeAffinity强制 PV 绑定到其他可用区,使云盘与 Pod 调度节点不在同一可用区,CSI attach/mount 必然超时。

该用例特别强调了滚动更新死锁规避:注入前必须记录 Deployment 的maxUnavailable并将临时值设为100%,否则默认策略下 K8s 不会终止旧 Pod,导致滚动更新死锁、故障无法完整覆盖所有副本:

kubectl get deployment <deployment-name> -n <namespace> \ -o jsonpath='{.spec.strategy.rollingUpdate.maxUnavailable}' kubectl patch deployment <deployment-name> -n <namespace> --type='json' \ -p='[{"op":"replace","path":"/spec/strategy/rollingUpdate/maxUnavailable","value":"100%"}]'

用例强调:maxUnavailable只是使滚动更新完成的手段,不是故障本身,滚动更新完成后应立即还原为原始值,不应泄漏到恢复阶段。

跨可用区 PV 使用 CSI 驱动diskplugin.csi.alibabacloud.com(阿里云云盘 CSI),通过nodeAffinity约束topology.kubernetes.io/zone;PVC 通过volumeName显式绑定该 PV。恢复时需同时移除注入时添加的volumes和volumeMounts(只移除其中一个会导致 Deployment 配置错误),并清理测试 PV/PVC。

7.2 CNI 分配失败(IP/ENI 耗尽)

见 Pod_ContainerCreating_CNI分配失败.md。该用例针对使用 ENI/vSwitch 分配 Pod IP 的 CNI 插件(如 Terway),通过批量创建 Pod 精确耗尽目标节点的 IP/ENI 资源。

其关键技巧在于防止调度器规避耗尽节点:先用kubectl label node给目标节点打标签,再给应用 A 的 Deployment 添加nodeSelector约束,确保新 Pod 只能调度到已耗尽的节点。

批量创建 Pod 必须使用仓库配套脚本 inject_cni_exhaust.py(用例明确标注kubectl create/apply不可用,必须使用脚本)。从源码看,该脚本的核心逻辑是:

  1. 查询节点allocatable.pods(pod capacity)、annotationk8s.aliyun.com/max-available-ip(IP pool 大小)以及当前非终态 Pod 数;
  2. 计算副本数min(ip_remaining, pod_slots_remaining - 2)——填满 IP pool 但预留 2 个 pod slot给目标应用重建,精确触发 CNI 分配失败而非OutOfpods;
  3. 先create deployment(--replicas=0),再通过 patch 同时设置replicas与spec.template.spec.nodeName,确保所有 Pod 直接绑定到目标节点,避免临时调度到其他节点。

脚本输出 JSON 化的node_info(pod_capacity / ip_pool / current_pods)与replicas计算结果,方便 Agent 和演练者核对注入精度。

7.3 容器运行时异常

见 Pod_ContainerCreating_容器运行时异常.md。该用例通过 chaosblade 挂起节点上的 containerd 进程,模拟容器运行时 hang:

blade create k8s node-process stop \ --names <节点名> \ --process containerd \ --timeout 120 \ --kubeconfig <路径>

依据 Chaosblade K8s 命令速查表,node-process的 action 有kill与stop两种:kill杀掉进程,stop以 SIGSTOP 挂起进程——本例正是利用stop模拟「进程 hang 但未退出」的状态。--timeout 120表示实验 120 秒后自动恢复,属于内置的自愈兜底;若超时未恢复,可通过blade destroy <UID>强制恢复。

该用例的资源准备强调「目标节点上有多个应用副本(避免单点影响)」与「监控系统可观测节点和容器运行时状态」,因为节点运行时 hang 会影响该节点上所有 Pod,属于爆炸半径较大的场景。

八、演练执行方法论:意图识别 → 用例选择 → 用例执行

以上所有用例(含云盘挂载冲突)都遵循 SKILL.md 定义的三段式决策树流程:

意图识别 ──→ 用例选择 ──→ 用例执行 (提取四维度) (决策树匹配) (读取文件并按步骤执行)

8.1 意图识别:提取四个维度

从用户输入中提取故障层级、故障现象、故障原因、目标应用四个维度,外加 kubeconfig 集群凭证路径。识别关键词映射(如「挂载、磁盘空间、磁盘IO」→ Pod 层级),信息不全时通过提问引导确认。

8.2 用例选择:动态发现

  1. ls references/catalogue/列出所有分类目录,按故障现象匹配目录(如Pod_ContainerCreating);
  2. ls references/catalogue/<匹配的目录>/列出该目录下所有用例文件,按根因匹配文件名;
  3. 无匹配文件时明确告知「当前不支持该场景」并停止,严禁自行构造用例外的故障注入。

8.3 用例执行:严格按四阶段推进

读取用例文件 → 将占位符(应用 A、<namespace>)替换为实际参数 →所有 blade 和 kubectl 命令必须显式指定--kubeconfig <路径>(禁止依赖默认值)→ 涉及 blade 命令时查阅 chaosblade-commands.md 获取完整参数 → 严格按「演练步骤 → 注入验证 → 注入恢复 → 恢复验证」顺序执行 → 输出演练报告。

对于「云盘挂载超时或冲突」这类纯 kubectl 用例,还应遵循速查表中的一般性原则:注入前务必确认 scope-target-action 组合在 Action 对照表中存在(例如node-disk只有fill/burn没有fullload,pod-mem的 action 是load),避免因 action 不存在导致注入失败;网络类drop默认全量丢包,必须用端口/IP 过滤缩小爆炸半径。

九、演练报告与后续改进

完成恢复验证后,按 SKILL.md 规定的格式输出演练报告:

演练报告 - 用例:[决策树路径,如 Pod > ContainerCreating > 云盘挂载超时或冲突] - 目标:[namespace/app-name] - 注入结果:[成功/失败] + 观察到的现象 - 恢复结果:[成功/失败] + 是否符合基准事实 - 发现的问题与改进建议

对于本用例,报告中至少应记录:新 Pod 的 ContainerCreating 持续时长、Events 中的 Multi-Attach 报错原文、PV attach 的节点归属变化、detach 等待耗时、业务数据读写是否受影响等观测项。这些记录可用于验证调度器、attach-detach 控制器与 CSI 插件在该异常场景下的行为是否符合预期,进而改进集群的存储调度策略(如为关键应用配置多副本跨节点容灾、避免 RWO 卷的非法多挂载、为 CSI 挂载增加超时告警等)。

十、小结

Pod_ContainerCreating是 Kubernetes 排障中最常见的故障现象之一,而「云盘挂载超时或冲突」是该分类下最易被误判的根因——它由 RWO 云盘的 Multi-Attach 约束引发,Events 证据(Multi-Attach error/AttachVolume.Attach failed)是与 CNI 分配失败、CSI 可用区不匹配、容器运行时异常相区分的关键。本文基于 chaosblade 技能库的 原始用例 完整还原了「资源准备 → 演练步骤 → 注入验证 → 注入恢复 → 恢复验证 → 演练报告」的标准流程,并对照同族三个根因用例与配套脚本源码,给出了可复制、可验证、可回滚的实战方案。读者在隔离环境中按此流程执行,即可在不触碰生产、不改动业务代码的前提下,系统验证自家集群在存储卷抢占场景下的韧性表现。

  • 运维
  • 云原生
  • SRE
  • AI Agent
  • 人工智能

【免费下载链接】chaosblade

An easy to use and powerful chaos engineering experiment toolkit.(阿里巴巴开源的一款简单易用、功能强大的混沌实验注入工具)

项目地址:https://gitcode.com/gh_mirrors/ch/chaosblade
点击查看免费下载

相关推荐

上一篇:mimalloc 通用内存分配器完全指南:设计原理、构建集成、malloc 覆盖与运行期调优
下一篇:用 fairseq 微调 RoBERTa 完成自定义分类任务:以 IMDB 情感分类为例的完整实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询