演练学习路径:22 个 lab 的难度排序、4 周基础计划与复盘方法

使用方式

这条路径解决“故障页看懂了,真出问题还是不会查”的问题:用 12 个可复现的 lab 把现象、验证命令和修复动作串起来。适合已经读过一条学习路径、需要把知识变成手感的开发、运维和 SRE。

前置知识:会用 Linux 命令行和 Docker;K8s 相关 lab 需要 kind 和 kubectl;数据库与中间件 lab 需要本机有空闲端口和约 2 GB 内存。建议按 4 周完成,每周 3–4 小时,一次只做一个 lab。

所有 lab 都要求在一次性虚拟机、容器或独立 kind 集群里完成。涉及 root、mount、tc、kill 的步骤必须先确认目标环境;实验后清理容器、挂载点和集群,避免端口、磁盘和内存残留。

12 个基础演练总览

演练 练什么 环境 对应排障页 完成后能回答
lab-cpu-100 CPU 满载、热点与节流 Linux 或容器 cpu-100 真计算、等 IO 还是被 cgroup 限流
lab-disk-full 空间耗尽与已删除文件 Linux root + loop no-space-left df 与 du 不一致时先查什么
lab-inode-exhausted inode 耗尽 Linux root + tmpfs inode-exhausted 有空间为什么创建不了文件
lab-pod-pending 调度失败 kind pod-pending Pending 时先看哪类事件
lab-pvc-pending 存储绑定失败 kind k8s-pvc-pending PVC 为什么一直不 Bound
lab-crashloopbackoff 容器反复退出 kind crashloopbackoff 退出码和 previous 日志怎么读
lab-dns-failure 集群 DNS 故障 kind k8s-dns-failed 查 CoreDNS、Service 还是策略
lab-network-latency 延迟注入与测量 Linux Docker + NET_ADMIN packet-loss 延迟、丢包、带宽、DNS 怎么区分
lab-mysql-deadlock InnoDB 死锁 Docker mysql-deadlock 1213 与 1205 的区别
lab-postgres-connection-exhausted 连接耗尽 Docker postgres-connection-exhausted 连接泄漏还是池配置问题
lab-kafka-consumer-lag 消费积压 Docker kafka-consumer-lag 总 lag 如何掩盖分区倾斜
lab-redis-hotkey 热 Key Docker redis-hotkey 热 Key 与大 Key 怎么区分

10 个进阶演练

完成基础 12 个之后,按故障域补做进阶演练。它们更接近真实故障:涉及节点、证书、发布、消息重平衡和 etcd 脑裂,必须严格在一次性环境里做。

演练 练什么 环境 对应排障页
lab-oom-killed 容器内存上限与 OOMKilled Docker / kind oom-killed
lab-imagepullbackoff 镜像 tag、认证与仓库连通性 kind imagepullbackoff
lab-node-notready kubelet 停止、节点压力与驱逐 kind node-notready
lab-certificate-expired 证书过期、链验证与轮换 Docker / 本地 TLS 服务 certificate-expired
lab-nginx-502 上游端口、进程与错误日志 Docker Compose 502 Bad Gateway
lab-helm-failed 模板、资源冲突与 release 状态 kind + Helm Helm
lab-kafka-rebalance 消费者进出与 rebalance Docker Compose Kafka rebalance
lab-es-unassigned 分片分配、磁盘水位与副本 Docker Compose Elasticsearch yellow
lab-etcd-quorum quorum 丢失与恢复顺序 3 节点 kind / etcd etcd quorum
lab-mysql-replication-lag 主从延迟与大事务 Docker Compose MySQL 主从延迟

进阶演练不强制排进四周计划。建议每完成一个基础阶段,就挑一个同故障域的进阶 lab;例如完成 K8s 基础后做 lab-oom-killed 和 lab-node-notready,完成消息与数据阶段后做 lab-kafka-rebalance 和 lab-mysql-replication-lag。

阶段一:单机资源三连

目标:建立“先预测、再注入、后取证”的节奏,分清 CPU、磁盘空间和 inode 三类资源故障。

阅读顺序:

  1. lab-cpu-100 — 风险最低、反馈最快,适合作为第一个实验。
  2. cpu-100 — 对照用户态、内核态和 cgroup 节流的判断。
  3. lab-disk-full — loop 文件系统隔离,安全练习 ENOSPC。
  4. no-space-left — 对照 df、du、lsof 的排查顺序。
  5. lab-inode-exhausted — 同样是 ENOSPC,但根因不同。
  6. inode-exhausted — 对照 df -i 和文件计数的判断。
  7. df — 容量与 inode 两个维度必须一起看。
  8. lsof — 找到已删除但仍被进程持有的文件。

动手任务:在一次性 Linux 虚拟机里连续做 CPU 和 inode 两个实验,注入前先写下预期现象,注入后用两条命令取证并清理。风险是 CPU 实验会吃满一个核、tmpfs 会占内存;必须带 timeout 和容量上限,不要对根分区做填充。

docker run -d --rm --name lab-cpu --cpus=1 alpine:3.20 sh -c 'timeout 120s sh -c "while :; do :; done"'
docker stats --no-stream lab-cpu
mkdir -p /tmp/lab-inode
sudo mount -t tmpfs -o size=64m,nr_inodes=256 tmpfs /tmp/lab-inode
df -i /tmp/lab-inode
sudo umount /tmp/lab-inode

过关标准:

阶段二:K8s 生命周期三连

目标:按 Pod 生命周期定位调度、存储和容器启动失败,不靠重启碰运气。

阅读顺序:

  1. lab-pod-pending — 调度阶段失败,容器还没有创建。
  2. pod-pending — 对照资源、污点、亲和性和 PVC 的判断。
  3. lab-pvc-pending — 存储绑定阶段的失败。
  4. k8s-pvc-pending — 对照 StorageClass、容量和绑定模式。
  5. lab-crashloopbackoff — 容器启动后反复退出。
  6. crashloopbackoff — 对照退出码、lastState 和 previous 日志。
  7. oom-killed — 区分内核 OOM 与普通应用退出。
  8. kubectl-debug — 容器没有 shell 时怎么取证。

动手任务:在独立 kind 集群里依次做 Pending、PVC Pending、CrashLoopBackOff 三个 lab,每次先写判断,再用 Events、describe 和 logs 验证。风险是误删共享集群资源;只能在 kind-lab 集群和 lab 命名空间操作,结束后删除整个集群。

kind create cluster --name lab-k8s
kubectl create namespace lab
kubectl -n lab get events --sort-by=.lastTimestamp
kubectl -n lab describe pod $(kubectl -n lab get pods -o jsonpath='{.items[0].metadata.name}')

过关标准:

阶段三:网络与 DNS 双练

目标:用延迟注入和 DNS 故障验证网络假设,区分延迟、丢包、超时和解析失败。

阅读顺序:

  1. lab-network-latency — 只在容器网卡上注入延迟,练习测量与回滚。
  2. packet-loss — 对照丢包与重传的现象。
  3. connection-timeout — 区分静默丢包和连接被拒绝。
  4. lab-dns-failure — 停掉 CoreDNS 复现集群解析失败。
  5. k8s-dns-failed — 对照 CoreDNS、Service 和 resolv.conf。
  6. dns-resolution-failed — 补全 DNS 解析失败的通用判断。
  7. tcpdump — 用过滤器在正确的网卡和方向上取证。
  8. network-troubleshooting-cheatsheet — 把分层顺序固化成检查表。

动手任务:在 Linux Docker 里做延迟实验,先在客户端容器测基线,再注入 200 ms 延迟和 50 ms 抖动,最后删除 qdisc 恢复。风险是 tc 会影响该容器全部出站流量;只能加 NET_ADMIN 到一次性容器,绝不能对宿主机网卡或生产 Pod 执行。

docker network create lab-net
docker run -d --name lab-server --network lab-net nginx:1.27-alpine
docker run -d --name lab-client --network lab-net --cap-add=NET_ADMIN nicolaka/netshoot:v0.13 sleep 3600
docker exec lab-client ping -c 3 lab-server
docker exec lab-client tc qdisc add dev eth0 root netem delay 200ms 50ms
docker exec lab-client tc -s qdisc show dev eth0
docker exec lab-client tc qdisc del dev eth0 root

过关标准:

阶段四:中间件四连

目标:用单容器复现死锁、连接耗尽、消费积压和热 Key,把现象映射到指标与修复动作。

阅读顺序:

  1. lab-mysql-deadlock — 两个事务制造 1213 死锁。
  2. mysql-deadlock — 对照死锁日志和加锁顺序。
  3. lab-postgres-connection-exhausted — 低 max_connections 复现连接耗尽。
  4. postgres-connection-exhausted — 对照连接状态和保留连接。
  5. lab-kafka-consumer-lag — 3 分区主题制造积压。
  6. kafka-consumer-lag — 对照分区位点、消费速率和 rebalance。
  7. lab-redis-hotkey — 高频访问单个 key。
  8. redis-hotkey — 对照 LFU、MONITOR 和 commandstats。

动手任务:按顺序做四个中间件 lab,每个 lab 只收集一条核心证据并写一句结论;四个容器使用固定端口,做完立即删除。风险是端口冲突和内存占用;端口只绑定回环地址,不要复用共享主机上的现有实例。

docker exec lab-mysql mysql -uroot -plabpass -e 'SHOW ENGINE INNODB STATUS\G' | grep -A20 'LATEST DETECTED DEADLOCK'
docker exec lab-pg psql -U postgres -c 'SELECT state, count(*) FROM pg_stat_activity GROUP BY state;'
docker exec lab-kafka /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group lab-group
docker exec lab-redis redis-cli INFO commandstats | sort -t= -k2 -rn | head

过关标准:

4 周练习顺序与复盘

第 1 周做阶段一,第 2 周做阶段二,第 3 周做阶段三并重做一次 CPU 实验,第 4 周做阶段四并从零复现一个 lab。每次复盘只写五行:现象、假设、验证命令、根因、修复与回滚;周末比较首次定位时间、验证命令数和回滚耗时。

常见误区

读完自测

合上页面,先回答,再展开对照。

  1. 基础 12 个 lab 中,哪一个最适合作为第一次练习?为什么?
  2. 做 lab-disk-full 时,df 和 du 不一致,说明什么?下一步命令是什么?
  3. 四周练习结束后,如何判断自己真的会排障,而不是记住了步骤?
答案
  1. lab-cpu-100:风险最低、反馈最快、清理简单,能先建立“预测现象、注入故障、取证、回滚”的完整节奏,再进入需要 root 或集群的 lab。
  2. 常见原因是文件已删除但仍被进程打开、文件系统保留块、快照或 du 未覆盖对应挂载点;下一步用 lsof +L1 找持有已删除文件的进程,并核对挂载点。
  3. 换一个没做过的 lab,在只看现象的情况下独立完成定位和回滚,并比较首次定位时间、验证命令数和回滚耗时;能解释每一步为什么查、而不是背步骤,才算掌握。

相关条目