TT Lab
价格 开始
学习 学习路径 课程

由我来搞坏 — 先写假设的混沌实验室

破坏实验室 — 破坏五次,修好一次

在 TT Lab 中继续学习

目标

在临时 VM 内真正的 k3s 上进行五次混沌实验。先测出正常基线,在破坏之前一次性写下五个实验的假设,接着杀掉 Pod、限制 CPU、耗尽内存,然后把所学反映到设计中,再次承受同样的攻击。这是一个 65 分钟的实验,面向了解 kubectl 基本查询和 Deployment 结构的中级学习者。

为什么重要

注入故障本身只是一行命令。难的是让这个实验产出下周仍然留得下来的东西。所以本实验的产出不是故障,而是笔记。假设在实验之前写,测量在实验窗口内进行,结论则写成两者对照的结果。预期落空并不是失败——被证伪的假设恰恰是这个实验能带来的最昂贵的信息,把它记为 refuted 才是正确答案。

判定表(结论中要用的名称)

为了避免每个人对同一个数字有不同的解读,先约定好命名规则。

测量工具

python3 /opt/fixtures/chaos_lab.py 只做三件事。它既不替你制造故障,也不替你修复。

安全范围

只使用临时 VM 内的 API https://127.0.0.1:6443 和 labhub-chaos 命名空间。绝对不要在生产集群或他人的环境中运行。为了只保留一个原因,所提供的应用使用 Recreate 策略——这并不是“不中断运维”的推荐值。应用镜像已按摘要(digest)固定。

本实验安排为 65 分钟,比默认会话(60 分钟)更长。开始时先延长会话时间。会话结束后,VM 和记录文件都会消失,无法恢复。记录文件是可以编辑的实验笔记,而不是无法伪造的证据。

步骤

  1. 应用 /opt/fixtures/chaos-lab-app.json,等待滚动更新完成,然后在不触碰任何东西的状态下施加 20 秒负载,记录基线。用 python3 /opt/fixtures/chaos_lab.py load 20 /root/chaos-lab/raw-01.json 测量,并用 python3 /opt/fixtures/chaos_lab.py record steady /root/chaos-lab/raw-01.json /root/chaos-lab/01-steady.json 保存。
  2. 从基线文件中读取成功率和 p95,在 steady_state 中写下稳态,并在 /root/chaos-lab/hypothesis.json 中写下五个实验(kill-one、kill-ha、cpu-squeeze、mem-squeeze、hardened)的假设。每个实验需要四项:availability、latency、为什么这样预期(why)、何时停止(abort_if)。availability_ratio_min 取不低于 0.95 且不高于基线测量值,p95_ms_max 取不低于基线 p95 且不超过其 3 倍。
  3. 在副本数为 1 的状态下,让负载在后台运行,并在测量窗口内删除那唯一的 Pod。窗口关闭后用 python3 /opt/fixtures/chaos_lab.py record kill-one /root/chaos-lab/raw-03.json /root/chaos-lab/03-kill-one.json 保存。资源限制和 preStop 保持基线状态不变。
  4. 把副本增加到 3,等三个都变为 Ready 之后,用同样的方式在负载窗口内只删除一个 Pod。用 python3 /opt/fixtures/chaos_lab.py record kill-ha /root/chaos-lab/raw-04.json /root/chaos-lab/04-kill-ha.json 保存。除了副本数,其他什么都不要改。
  5. 只把 shop 容器的 cpu 限制降到 100m(memory 保持 96Mi,副本数仍为 3)。在滚动更新结束、三个都变为 Ready 之后,施加 20 秒负载,并用 python3 /opt/fixtures/chaos_lab.py record cpu-squeeze /root/chaos-lab/raw-05.json /root/chaos-lab/05-cpu-squeeze.json 保存。
  6. 把 cpu 限制恢复为 500m,同时把 memory 限制降到 40Mi。应用启动时会一次性占用 48MiB,因此容器会因 OOM 被杀死。捕捉到重启后,施加 20 秒负载,并用 python3 /opt/fixtures/chaos_lab.py record mem-squeeze /root/chaos-lab/raw-06.json /root/chaos-lab/06-mem-squeeze.json 保存。
  7. 把资源限制恢复为正常值(cpu 500m、memory 96Mi),这次再加上终止处理。用 preStop 钩子争取至少 3 秒,并把 terminationGracePeriodSeconds 提高到 10 以上。滚动更新结束后,再次发起与第 3 步、第 4 步相同的攻击,并用 python3 /opt/fixtures/chaos_lab.py record hardened /root/chaos-lab/raw-07.json /root/chaos-lab/07-hardened.json 保存。
  8. 按照说明中的判定表给五份记录中的数字命名,写入 /root/chaos-lab/conclusion.json。每个实验需要 observed_availability、observed_latency、与假设对照得出的 verdict(confirmed 或 refuted),以及据此要改变什么(action)。最后的评分会一并查看之前的记录和当前的集群——改进后的设计必须处于运行状态。

参考

在破坏之前,把“正常”记成数字

应用 /opt/fixtures/chaos-lab-app.json,等待滚动更新完成,然后在不触碰任何东西的状态下施加 20 秒负载,记录基线。用 python3 /opt/fixtures/chaos_lab.py load 20 /root/chaos-lab/raw-01.json 测量,并用 python3 /opt/fixtures/chaos_lab.py record steady /root/chaos-lab/raw-01.json /root/chaos-lab/01-steady.json 保存。

Running、Ready 与实际请求成功是不同的事实。等到 Ready 的端点变为 1 个之后再测量。如果测量窗口内出现了新的 Pod,就不会被认定为基线。

先写下五个假设

从基线文件中读取成功率和 p95,在 steady_state 中写下稳态,并在 /root/chaos-lab/hypothesis.json 中写下五个实验(kill-one、kill-ha、cpu-squeeze、mem-squeeze、hardened)的假设。每个实验需要四项:availability、latency、为什么这样预期(why)、何时停止(abort_if)。availability_ratio_min 取不低于 0.95 且不高于基线测量值,p95_ms_max 取不低于基线 p95 且不超过其 3 倍。

预期不必一定正确。把错误的预期事后记为 refuted,正是本实验的正确答案。标签的含义见说明中的判定表。从这里开始不要再修改这个文件——最后的评分会检查它是否先于第一份实验记录写成。

杀掉只有一个副本的服务

在副本数为 1 的状态下,让负载在后台运行,并在测量窗口内删除那唯一的 Pod。窗口关闭后用 python3 /opt/fixtures/chaos_lab.py record kill-one /root/chaos-lab/raw-03.json /root/chaos-lab/03-kill-one.json 保存。资源限制和 preStop 保持基线状态不变。

要先启动负载,过几秒再杀掉 Pod,影响才会落在窗口之内。如果杀掉之后才开始测量,测到的就是替代 Pod 已经就绪之后的数字。窗口关闭时 Pod 必须重新变为 Ready,才会被记录。

把副本增加到三个,重复同样的攻击

把副本增加到 3,等三个都变为 Ready 之后,用同样的方式在负载窗口内只删除一个 Pod。用 python3 /opt/fixtures/chaos_lab.py record kill-ha /root/chaos-lab/raw-04.json /root/chaos-lab/04-kill-ha.json 保存。除了副本数,其他什么都不要改。

每次只改变一个变量,才能解释结果。确认三个全部 Ready 之后再测量。即使成功率没有恢复到基线水平,也照实记录即可——那就是这个实验的结果。

限制 CPU——不会被杀死,而是变慢的故障

只把 shop 容器的 cpu 限制降到 100m(memory 保持 96Mi,副本数仍为 3)。在滚动更新结束、三个都变为 Ready 之后,施加 20 秒负载,并用 python3 /opt/fixtures/chaos_lab.py record cpu-squeeze /root/chaos-lab/raw-05.json /root/chaos-lab/05-cpu-squeeze.json 保存。

资源限制在 Pod 模板中,所以修改后会启动新的 Pod。如果在滚动更新途中测量,部署的影响和限制的影响会混在一起。也要记住,限制不能小于请求量。

耗尽内存——这次会被杀死

把 cpu 限制恢复为 500m,同时把 memory 限制降到 40Mi。应用启动时会一次性占用 48MiB,因此容器会因 OOM 被杀死。捕捉到重启后,施加 20 秒负载,并用 python3 /opt/fixtures/chaos_lab.py record mem-squeeze /root/chaos-lab/raw-06.json /root/chaos-lab/06-mem-squeeze.json 保存。

这次滚动更新不会结束。不要等待 rollout status,而要查看重启次数或终止原因。退出码和原因与 CPU 那次有何不同,正是这个实验的关键。

把所学反映到设计中,再次承受同样的攻击

把资源限制恢复为正常值(cpu 500m、memory 96Mi),这次再加上终止处理。用 preStop 钩子争取至少 3 秒,并把 terminationGracePeriodSeconds 提高到 10 以上。滚动更新结束后,再次发起与第 3 步、第 4 步相同的攻击,并用 python3 /opt/fixtures/chaos_lab.py record hardened /root/chaos-lab/raw-07.json /root/chaos-lab/07-hardened.json 保存。

preStop 先于 TERM 信号执行,钩子结束后信号才会发出。在此期间,端点移除得以传播开。宽限期的倒计时在钩子之前就已开始,所以宽限期必须比钩子时间更宽裕。删除探针,或者再增加副本来让数字变好看,都是在规避这个实验的约定。

对照假设与测量,合上实验笔记

按照说明中的判定表给五份记录中的数字命名,写入 /root/chaos-lab/conclusion.json。每个实验需要 observed_availability、observed_latency、与假设对照得出的 verdict(confirmed 或 refuted),以及据此要改变什么(action)。最后的评分会一并查看之前的记录和当前的集群——改进后的设计必须处于运行状态。

被证伪的假设不是失败。与预期不同时,记为 refuted 才是正确的答案。如果只把数字写得像模像样,名称却随便乱写,评分器会按同样的规则重新计算并将其筛掉。五个 action 必须各不相同。