可执行 Runbook
使 runbook 成可执行脚本非仅文档 — 值班跑 runbook 非读它。
为什么
说"跑此 kubectl 命令、再此 SQL 查询、再此 curl"的 runbook 是三复制粘贴步,每步可粘错、跑错集群或静默失败。可执行 runbook 是用正确参数做全部三步、验证每步输出、遇意外中止的脚本。这按人打字和犹豫的时间砍 MTTR,且使 runbook 可测 — 你可在 staging 季度审计时跑并知它工作,而非希望文档对。脚本也自文档化:代码即 runbook,故不能 独立于文档腐。把 top 5 runbook 可执行化的团队报事件响应快 50% 因值班跑一命令而非读和打 10 个。
何时使用
先对触发最多的 top 5 runbook。别全可执行化 — 聚焦跑最频的 runbook。
如何做
1. 按触发频率选 top 5 runbook - 这些是执行速度最要紧的 - 一年触发一次的 runbook 可留文档;每周触发的应是脚本 2. 每步转带验证的脚本函数 - 每步:跑命令、查预期输出、遇意外中止 - 用与运维工具同语言(bash、Python、Go) 3. 使脚本幂等且安全 - 重跑不应坏任何东西(万一首次部分成功) - 毁灭步(删、重启)需 --confirm 标志 - 默认 dry-run 模式:--apply 才执行 4. 审计时在 staging 测脚本 - 跑 --dry-run → 确认它会做对的事 - 跑 --apply → 确认它真解决问题 - 这是 runbook 测试;它现在是代码故像代码测 5. 把脚本接到告警(安全步自动触发) - 告警触发 → 脚本自动跑步 1-2(见 runbook-trigger) - 若自动触发未解则人跑全脚本 - 脚本记一切供复盘
示例
#!/usr/bin/env python3
# runbook/checkout-slo-burn.py — 可执行 runbook
import subprocess, sys, click
@click.command()
@click.option('--apply', is_flag=True, help="执行变更(默认:dry-run)")
def main(apply):
# 步 1:查最近部署
r = subprocess.run(["kubectl", "rollout", "history", "deploy/checkout", "-n", "checkout"],
capture_output=True, text=True)
if "v2.4.1" in r.stdout and "30m" in r.stdout: # 最近部署
print("找到最近部署 v2.4.1 — 可能是因")
if apply:
subprocess.run(["kubectl", "rollout", "undo", "deploy/checkout", "-n", "checkout"], check=True)
print("已回滚。验证中...")
if error_rate() < 0.001: # 验证
print("✅ 错误率 <0.1% — 解决")
else:
print("❌ 错误率仍高 — 升级到 @checkout-sme")
sys.exit(1)
else:
print("[dry-run] 将回滚 deploy/checkout")
else:
print("无最近部署 — 在服务图查下游依赖")
if __name__ == "__main__":
main()
# 值班跑:python3 runbook/checkout-slo-burn.py --apply
# 自动触发(告警 webhook):仅安全步带 --apply 跑常见问题
- ⚠脚本不幂等 — 部分成功后重跑更糟;要求幂等和 dry-run 模式。
- ⚠无 dry-run 模式 — 值班执行前无法安全测脚本,故要么跳要么盲跑希望。
- ⚠脚本独立于文档腐 — runbook.md 说一、.py 做另一;保持为一(代码即 runbook)。
- ⚠全可执行化 — 一年触发一次的 runbook 不值得脚本化;聚焦按频率 top 5。
最佳实践
- ✓按触发频率可执行化 top 5 runbook;年度 runbook 可留文档,周度应是脚本。
- ✓使脚本幂等带 dry-run 默认和 --apply 执行;毁灭步需 --confirm。
- ✓把脚本当 runbook(代码即 文档)使不能独立腐;审计时在 staging 测它。
- ✓安全步接到告警自动触发;仅自动修复未解时人跑全脚本。