- 运维
- 云原生
- SRE
- AI Agent
- 人工智能
【免费下载链接】chaosblade
An easy to use and powerful chaos engineering experiment toolkit.(阿里巴巴开源的一款简单易用、功能强大的混沌实验注入工具)
导读
当 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异常.md | CSI 驱动异常 / 云盘与节点可用区不匹配 | FailedMount/FailedAttachVolume/ CSI 超时 |
| Pod_ContainerCreating_云盘挂载超时或冲突.md | 云盘(RWO)被其他节点/Pod 占用 | Multi-Attach error/AttachVolume.Attach failed |
| Pod_ContainerCreating_容器运行时异常.md | containerd/docker 进程异常或 hang | container 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 故障现象清单
演练前需要能准确识别目标故障,官方用例给出的现象为:
- Pod 长时间停留在
ContainerCreating状态; - Pod Events 中显示
Multi-Attach error或AttachVolume.Attach failed; - 云盘被其他节点占用,无法 attach 到当前节点。
其中 Events 证据是判定故障生效的关键——kubectl describe pod中的Multi-Attach error是 attach-detach controller(或 CSI attach 逻辑)在检测到卷已挂载到其他节点时产生的典型报错,与「云盘真实损坏」「CSI 驱动超时」等现象可明确区分。
三、演练前置条件与资源准备
执行本用例前需确认两项资源准备,缺一不可:
- 应用 A 已正常运行,且使用了云盘类型的 PVC(
accessMode为ReadWriteOnce); - 集群中有多个节点(这是 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 恢复步骤
- 删除临时抢占 Pod:
kubectl delete pod chaos-volume-holder --force --grace-period=0
--force --grace-period=0用于跳过优雅终止期强制删除。由于该 Pod 持有云盘挂载,kubelet 卸载卷与 API Server 删除 Pod 之间存在时序,强制删除可加快 detach 流程,避免等待挂起。
- 等待云盘从原节点 detach(attach-detach controller / CSI 插件完成卸载,通常数十秒);
- 等待应用 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不可用,必须使用脚本)。从源码看,该脚本的核心逻辑是:
- 查询节点
allocatable.pods(pod capacity)、annotationk8s.aliyun.com/max-available-ip(IP pool 大小)以及当前非终态 Pod 数; - 计算副本数
min(ip_remaining, pod_slots_remaining - 2)——填满 IP pool 但预留 2 个 pod slot给目标应用重建,精确触发 CNI 分配失败而非OutOfpods; - 先
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 用例选择:动态发现
ls references/catalogue/列出所有分类目录,按故障现象匹配目录(如Pod_ContainerCreating);ls references/catalogue/<匹配的目录>/列出该目录下所有用例文件,按根因匹配文件名;- 无匹配文件时明确告知「当前不支持该场景」并停止,严禁自行构造用例外的故障注入。
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.(阿里巴巴开源的一款简单易用、功能强大的混沌实验注入工具)
相关推荐
ChaosBlade K8s 故障演练用例深度解析:Volume 挂载超时与 CSI 可用区异常导致 Pod ContainerCreating
ChaosBlade K8s 故障演练用例深度解析:Volume 挂载超时与 CSI 可用区异常导致 Pod ContainerCreating 导读 本文基于
运维云原生SREAI Agent人工智能ChaosBlade K8s 故障演练实战:pod-disk fill 注入模拟"云盘空间打满(日志未清理)"
ChaosBlade K8s 故障演练实战:pod disk fill 注入模拟"云盘空间打满(日志未清理)" 本文以 ChaosBlade 开源混沌工程工具为
运维云原生SREAI Agent人工智能ChaosBlade 入门实战指南:从 CPU 满载到 Dubbo 故障注入的完整演练
ChaosBlade 入门实战指南:从 CPU 满载到 Dubbo 故障注入的完整演练 ChaosBlade(GitHub 加速计划 / ch / chaosb
运维云原生SREAI Agent人工智能
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考