3. Runbook 基础:定义、场景与编写规范
Runbook(运行手册)是运维和SRE领域的核心文档化实践,它将可重复的操作流程从“人脑记忆”转化为“标准化可执行程序”。在CI/CD流水线中,Runbook是连接自动化触发与人工干预的桥梁,确保故障恢复和变更执行的一致性与可审计性。
3.1 什么是Runbook
Runbook是一份结构化的操作文档,详细描述了在特定运维场景下(如服务宕机、部署失败、配置变更)需要执行的一系列步骤、检查点、回退方案和预期结果。它不仅仅是操作清单,更是知识沉淀和自动化脚本的入口。
| 维度 | 传统运维笔记 | 标准化Runbook |
|---|---|---|
| 结构 | 自由文本,无固定格式 | 模板化,包含元数据、前置条件、步骤、回退 |
| 可执行性 | 依赖个人经验解读 | 步骤清晰,可被新手或自动化工具直接执行 |
| 版本控制 | 通常无版本管理 | 纳入Git仓库,每次变更可追溯 |
| 与CI/CD联动 | 无 | 可通过Webhook或API被流水线触发 |
| 审计 | 无执行记录 | 每次执行自动记录日志、耗时、操作人 |
核心价值: Runbook将运维操作从“英雄主义”转变为“工程化流程”,降低MTTR(平均修复时间),消除单点故障风险。
3.2 Runbook的典型场景
Runbook在CI/CD流水线中主要服务于两大核心场景:故障恢复和变更执行。下面通过两个独立的结构图来展示其典型流程。
3.2.1 场景一:故障恢复
当监控系统或CI/CD流水线检测到服务异常时,自动触发对应的故障恢复Runbook。该Runbook指导操作员或自动化系统执行诊断、隔离、恢复和验证步骤。
最佳实践: 故障恢复Runbook应包含明确的“决策树”或“条件分支”。例如:“如果步骤3执行失败,则跳转到步骤3.1(回退方案)”,避免操作员在高压下做出错误判断。
3.2.2 场景二:变更执行
变更执行Runbook用于标准化CI/CD流水线中的发布、配置更新、扩缩容等操作。它确保每次变更都遵循相同的审批、执行和验证流程,降低人为失误。
3.3 Runbook的编写规范
高质量的Runbook需要遵循统一的编写规范,以确保可读性、可执行性和可维护性。以下是推荐的Runbook结构模板和编写原则。
3.3.1 标准Runbook模板结构
| 章节 | 内容要求 | 示例 |
|---|---|---|
| 元数据 | 名称、ID、版本、所有者、创建日期、标签 | name: "数据库主从切换" |
| 触发条件 | 明确什么事件会启动此Runbook | “当数据库主库延迟 > 5秒 或 主库宕机” |
| 前置条件 | 执行前必须满足的环境或权限要求 | “操作员需拥有DBA角色权限;已确认从库数据同步正常” |
| 步骤列表 | 有序的操作指令,包含命令、预期输出、检查点 | “步骤1:执行 mysql -e 'STOP SLAVE'” |
| 回退方案 | 当步骤失败时的替代路径或回滚命令 | “若步骤3失败,执行 mysql -e 'START SLAVE' 回退” |
| 验证方法 | 如何确认操作成功完成 | “执行 mysql -e 'SHOW SLAVE STATUS\G' 确认 IO/SQL 线程为 Yes” |
| 通知与升级 | 操作完成后通知谁,失败时升级给谁 | “成功:通知 @oncall;失败:升级至 @sre-lead” |
3.3.2 编写原则
- 原子性: 每个步骤只做一件事,避免“组合拳”式的大步骤。例如,将“停止服务并备份数据库”拆分为“步骤1:停止服务”和“步骤2:执行数据库备份”。
- 可测试性: 每个步骤都应包含明确的“预期输出”或“验证命令”。操作员执行后能立即判断步骤是否成功。
- 幂等性: 尽可能设计为可重复执行而不产生副作用。例如,使用
CREATE TABLE IF NOT EXISTS而非CREATE TABLE。 - 版本化: Runbook必须与代码一样纳入Git版本管理,每次变更都需经过Pull Request审查。
- 自动化优先: 如果某个步骤可以写成脚本,则应在Runbook中直接嵌入脚本或指向自动化Job的链接,减少人工输入。
常见反模式: 避免在Runbook中出现“请联系XX同事获取密码”或“根据经验调整参数”等模糊描述。所有依赖项和参数必须显式声明。
3.3.3 代码示例:Runbook中的步骤定义
以下是一个Runbook步骤的YAML定义示例,展示了如何将步骤、验证和回退结构化。
# runbooks/db-failover.yaml
name: "数据库主从故障切换"
version: "2.1.0"
trigger: "主库健康检查连续3次失败"
steps:
- id: "step-1"
description: "确认从库状态"
command: "mysql -h slave-host -e 'SHOW SLAVE STATUS\G'"
expected_output: "Slave_IO_Running: Yes; Slave_SQL_Running: Yes"
on_failure: "升级至DBA团队,中止Runbook"
- id: "step-2"
description: "将从库提升为新主库"
command: "mysql -h slave-host -e 'STOP SLAVE; RESET SLAVE ALL;'"
expected_output: "Query OK"
on_failure:
rollback_command: "mysql -h slave-host -e 'START SLAVE;'"
rollback_note: "如果提升失败,重新启动从库复制"
- id: "step-3"
description: "验证新主库可写"
command: "mysql -h slave-host -e 'CREATE TABLE test.health (id INT); DROP TABLE test.health;'"
expected_output: "Query OK"
on_failure: "触发回滚Runbook v2.0.0"
rollback:
- id: "rollback-1"
description: "将原主库恢复为从库"
command: "mysql -h original-master -e 'CHANGE MASTER TO ...; START SLAVE;'"