06 自动化工程
概述#
SRE 把 50% 以上的工作时间投入"工程"——不是写业务代码,而是构建让运维工作自动化的软件系统。本章讲清楚自动化工程的演进路径、核心原则,以及如何避免"自动化本身变成新的 toil"。
自动化工程的本质是把 SRE 的时间从"做操作"转向"写做操作的代码"。这不是"偷懒",是把人力从重复劳动中解放出来,投入到只有人能做的创造性工作——架构设计、根因分析、可靠性工程。
一、自动化演进阶梯#
自动化不是"要么有要么无",而是几个渐进的层次:
Level 0 手动操作 ← 纯人工,依赖经验和记忆力
Level 1 文档化操作 ← 有 Runbook,但操作还是人手做
Level 2 脚本化 ← 有一次性脚本,但参数硬编码
Level 3 自动化工具 ← 可复用工具,参数化、可审计
Level 4 自愈系统 ← 系统检测到异常自动修复,无需人工介入每一层的特征#
| Level | 操作者 | 可重复性 | 审计 | 典型形态 | 出错概率 |
|---|---|---|---|---|---|
| L0 手动 | 人 | 每次不同 | 无 | SSH 上去 kubectl delete pod | 高(凭记忆) |
| L1 文档化 | 人(按 runbook) | 基本一致 | 无 | Wiki 里的操作手册 | 中(可能漏步骤) |
| L2 脚本化 | 人触发脚本 | 一致 | 有限 | bash 脚本 restart-service.sh | 低(脚本是固定的) |
| L3 自动化 | 系统/人触发 | 一致 | 完整 | CI/CD 流水线、GitOps | 极低(有 review) |
| L4 自愈 | 系统自动 | 一致 | 完整 | HPA 自动扩缩、Pod 自动重建 | 极低(但需监控) |
目标不是让所有人都到 L4——L4 只在合适的场景下做。但至少要让重复频率高的操作达到 L3。
每一层的过渡难点#
L0 → L1:需要把"默会知识"显性化。老员工的"直觉"必须变成可写的步骤。难点在于有经验的人没时间写文档。
L1 → L2:需要把文档变成代码。难点是脚本维护——环境变了脚本就坏了,没人修就废了。
L2 → L3:需要从"个人脚本"变成"团队工具"。难点是规范化:参数化、错误处理、日志、审计。很多脚本卡在 L2 是因为"只有作者能跑"。
L3 → L4:需要从"人触发"变成"系统触发"。难点是判断逻辑——什么时候该自动执行、什么时候该升级到人。这是最难的一步,需要大量数据积累和调优。
哪些应该到 L4(自愈)#
- 服务进程 crash → K8s 自动重启(liveness probe + restartPolicy)
- 流量突增 → HPA / KEDA 自动扩容
- 节点不可用 → Cluster Autoscaler / Karpenter 自动替换
- 证书过期 → cert-manager 自动续签
- 磁盘满 → 自动清理日志或扩容 PVC
- 数据库主库故障 → 自动 failover(如 Orchestrator、Patroni)
哪些 L3 就够了#
- 服务发布 → CI/CD 流水线触发,有人确认
- 配置变更 → GitOps PR + approve + sync
- 数据库迁移 → 自动化执行但有审批关卡
- 紧急回滚 → 一键脚本但需要人决策
哪些应该留在 L1/L2#
- 季度容量规划 review → 需要人判断
- 跨团队协调的迁移 → 复杂决策
- 新服务的架构设计 → 创造性工作
- Postmortem 复盘 → 需要人分析
二、自动化工程的核心原则#
1. Automation over Operation#
Google SRE 的核心理念:宁可花 10 小时写自动化工具,也不花 5 分钟手做第 10 次同样的操作。
判断标准:一个操作如果预计未来一年要做超过 10 次,自动化就值得。公式:
自动化 ROI = (单次手动耗时 × 预计操作次数) / 开发时间
如果 ROI > 3,优先级高
如果 ROI > 10,立刻做
如果 ROI < 1,不做(手动更划算)举例:每次手动扩容 15 分钟,预计一年要做 50 次,写自动化脚本要 4 小时。
ROI = (15min × 50) / (4h × 60min) = 750 / 240 ≈ 3.1ROI > 3,应该做。但还要考虑隐性收益:自动化后误操作概率降低、可以夜间执行、可以并行多服务。
2. 自动化是软件工程,不是写脚本#
自动化代码需要:
- Code Review:和业务代码一样的审查流程
- 测试:不只是在测试环境跑一次,要有回归测试
- 版本管理:进 Git,可回滚
- 文档:为什么这样设计、边界条件是什么
- 告警:自动化工具自己挂了要知道
- SLO:自动化工具也是服务,有自己的可靠性目标
很多团队的自动化脚本"能跑就行",没有 review 没有测试。结果是脚本越积越多,每个都有 bug,没人敢动——自动化变成了新的 tech debt。
3. 工具化思维#
不要为每个任务写独立脚本,要构建可复用的工具平台。比如:
- ❌ 为 A 服务写扩容脚本,为 B 服务又写一个类似的
- ✅ 构建一个扩容框架,A 和 B 通过参数配置接入
工具化的核心是关注点分离:
通用框架(处理流程、错误、日志、审计)
+
具体配置(每个服务的参数)
=
可复用工具4. 渐进式自动化#
不要试图一次性自动化所有事情。按优先级队列:
1. 最频繁的 toil(每天多次)→ 立刻自动化
2. 高风险的人为误操作(生产误删除)→ 加安全护栏 + 自动化
3. 复杂但稳定(发布流程)→ 逐步自动化
4. 低频简单操作(季度清理)→ 有个 Runbook 就好,不用自动化5. 自动化优先于流程#
很多团队遇到"频繁出错"的反应是"加审批流程"——增加 review 节点、加审批人、加 sign-off。这是错误的方向。
频繁出错 → 加流程 → 操作变慢 → toil 增加 → 没时间做自动化 → 继续出错正确方向:
频繁出错 → 自动化 → 操作标准化 → 出错概率下降 → 释放时间做更多自动化流程不能消除错误,自动化才能。流程只让错误"更慢地发生"。
三、自愈系统设计模式#
模式 1:观测-决策-执行闭环#
Sensor(传感器) → Analyzer(分析器) → Actuator(执行器)
↑ |
└──────────── 反馈验证 ──────────────────┘- Sensor:Prometheus 指标、日志异常检测
- Analyzer:告警规则、SLO burn rate 条件
- Actuator:K8s operator、自动化脚本
关键:执行器动作后,Sensor 必须验证效果。如果执行了没效果,要降级到人工介入。
举例:HPA 自动扩容流程
Sensor: CPU 使用率 > 70%
↓
Analyzer: HPA 判断需要扩容
↓
Actuator: 创建新 Pod
↓
Sensor: 5 分钟后 CPU 是否下降?
↓ 是 → 扩容成功,记录
↓ 否 → 继续扩容 + 告警人工介入模式 2:渐进式自治#
Step 1: 检测 + 建议("检测到问题,建议执行 X")
Step 2: 检测 + 自动执行(但保留人工撤销能力)
Step 3: 检测 + 自动执行 + 自动验证(全自动)不要一步跳到全自动。先在非生产环境跑 Step 1 至少一个月,确认建议都是正确的,再逐步放开。
Google SRE Book 推荐的"自动化成熟度"演进:
- 第 1 个月:系统检测到问题,发通知给人,人处理
- 第 2-3 个月:系统检测到问题,给出建议操作,人确认后系统执行
- 第 4-6 个月:系统自动执行,但每次都通知人
- 第 7 个月+:系统自动执行,只在异常时通知人
模式 3:安全护栏#
任何自动执行操作必须满足:
- 爆炸半径限制:一次只影响最小范围(如 HPA 一次最多扩 N 个 pod)
- 回滚能力:自动化操作可撤销
- 熔断机制:连续失败 N 次自动停止
- 审计日志:谁/什么/何时/做了什么操作
- 速率限制:单位时间内操作次数上限(避免雪崩)
- 干运行模式:可以先 dry-run 看会做什么,不真执行
模式 4:分层自治#
不同层级的故障用不同层级的自愈:
应用层(业务 bug) → 重启 pod / 回滚版本
基础设施层(节点故障) → 重新调度 pod / 替换节点
网络层(连接异常) → 重试 / 切换备用
数据层(DB 慢) → 限流 / 降级 / 读副本
依赖层(下游挂) → 熔断 / 降级每层自治能力独立设计,避免"一个层级的故障触发其他层级的错误自愈"。
四、自动化工具的工程实践#
自动化工具的代码结构#
一个合格的自动化工具应该有:
# 伪代码示例
def autoscale_service(service_name, target_replicas):
# 1. 前置检查
if not validate_service_exists(service_name):
raise ServiceNotFoundError(service_name)
current = get_current_replicas(service_name)
# 2. 安全护栏
if target_replicas > MAX_REPLICAS:
raise SafetyViolationError(f"超过最大副本数 {MAX_REPLICAS}")
if target_replicas > current * MAX_SCALE_UP_RATIO:
logger.warning(f"扩容比例过大,需要人工确认")
notify_human_for_approval(service_name, target_replicas)
return
# 3. 执行
try:
scale_service(service_name, target_replicas)
except Exception as e:
# 4. 失败处理
logger.error(f"扩容失败: {e}")
emit_alert(f"autoscale_failed: {service_name}")
return
# 5. 验证
wait_for_ready(service_name, target_replicas, timeout=300)
# 6. 审计
audit_log(
action="autoscale",
service=service_name,
from_replicas=current,
to_replicas=target_replicas,
timestamp=now(),
trigger="automatic"
)自动化工具的测试#
自动化工具必须有测试,否则就是"用 bug 修 bug":
- 单元测试:每个函数的行为
- 集成测试:和真实系统的交互(在测试环境)
- 混沌测试:故意注入故障,看工具是否正确处理
- 回归测试:每次改动后跑全量测试
测试覆盖率建议:核心逻辑 > 80%,辅助代码 > 50%。
自动化工具的监控#
自动化工具自己也是服务,需要:
- 健康检查(liveness/readiness)
- 执行成功率监控
- 执行时长监控
- 失败告警
- 自身的 SLO(如"扩容成功率 > 99%")
一个挂了的自动化工具比没有自动化更危险——它会让你以为问题被处理了,实际没有。
五、常见陷阱#
陷阱 1:自动化过度#
自动化了"每月操作一次、每次 5 分钟"的任务,但维护这个自动化每月要花 2 小时。投入产出倒挂。
判断标准:自动化 ROI = 节省的 toil 时间 / (开发时间 + 维护时间 × 12)。如果 ROI < 1,不要自动化。
陷阱 2:自动化没有告警#
自动化工具自己挂了没人知道。任何自动化组件都需要监控——和业务服务一样配健康检查和告警。
更糟糕的情况:自动化工具"半挂"——没完全死但行为异常。这种问题最难发现。需要监控的不仅是"工具是否运行",还有"工具的输出是否正常"。
陷阱 3:自动化 = 自愈的错觉#
"我配了 HPA"不等于"容量问题是自愈的"。HPA 扩容需要时间(pod 启动、JIT 预热),在扩容窗口内流量仍然可能打挂服务。真正的自愈需要预热机制、连接池预热、限流兜底。
陷阱 4:把流程变成了自动化#
手动审批流程 + 自动执行 ≠ 自动化。正确做法是:如果这个操作足够安全,把审批去掉;如果不安全,先加安全护栏再加自动化。
陷阱 5:自动化脚本变成"只有作者能跑"#
很多团队的自动化脚本卡在 L2,原因是脚本没有规范化:
- 参数硬编码
- 依赖特定环境变量
- 没有错误处理
- 没有日志
- 没有文档
作者离职后脚本就废了。规范化要求:所有自动化脚本必须满足团队级的代码标准,进 Git,有 README,有测试。
陷阱 6:自动化加剧了单点故障#
"自动化了 = 这个人不用做了"——但如果只有这个人懂自动化工具的工作原理,工具本身就是单点。需要让多人理解工具,文档完整,能接手维护。
陷阱 7:自动化绕过了变更管理#
自动化执行的操作如果不在变更管理系统里记录,等于"看不见的变更"。所有自动化操作必须写审计日志,并接入变更管理流程。
六、自动化的组织维度#
谁来写自动化#
三种模式:
- SRE 自己写:SRE 团队既做运维也做自动化工程。优点:贴近实际需求;缺点:人少时优先级被运维挤掉。
- 工具团队写:有专门的工具/平台团队,SRE 提需求。优点:工程能力强;缺点:离实际运维远,需求理解偏差。
- 混合模式:通用工具由工具团队做,业务特定的自动化由 SRE 写。这是 Google 的模式,也是大多数成熟团队的模式。
自动化的接受度#
写了自动化工具,但团队不用——这是常见问题。原因:
- 工具不好用(UI 差、文档烂)
- 团队习惯了手动操作("老方法更可靠")
- 工具出过 bug,失去信任
- 没有强制使用的规定
解决:
- 让团队参与工具设计(不是 SRE 自己拍)
- 工具先在 SRE 内部用,稳定后推给开发
- 出 bug 要快速修复,重建信任
- 把"使用自动化工具"写进团队规范
实战要点#
- 统计 Toil 频率是自动化规划的前提。不知道哪些操作最频繁,就无法排优先级。每月做一次 toil 来源分析。
- 写自动化代码的生产标准 = 写业务代码的标准。Code Review、测试、文档一个不能少。
- 自愈系统从建议模式开始。先让系统"告诉你该做什么",确认无误再让它"帮你做"。
- 自动化工具也是服务,需要监控、告警、SLO。自动化工具挂了的风险等同于业务服务挂了。
- 渐进式上 Level。不要直接从 L1 跳到 L4——每跳一级都要充分验证。
- 每个自动化操作都要有审计日志。谁/什么/何时/做了什么,必须可追溯。
- 自动化优先于流程。流程不能减少错误,只能让错误更慢发生。自动化才能从根本上减少错误。
- ROI 低于 1 的不要自动化。低频简单操作有 Runbook 就好,过度自动化是浪费。
- 保留人工介入路径。任何自动化都必须有"我需要人来看"的升级机制——不能让自动化"自己一路走到黑"。
小结#
自动化工程的本质是把 SRE 的时间从"做操作"转向"写做操作的代码"。演进阶梯(手动→文档→脚本→自动化→自愈)是规划蓝图。
记住核心等式:自动化 ROI = 节省的 Toil 时间 / 开发时间。ROI 高的优先做,ROI 低的留 Runbook。
判断一个团队的自动化成熟度,看三件事:高频操作是否都到 L3+、自动化工具是否被监控、自愈系统是否从建议模式演进到执行模式。三件事都做到是成熟团队;只做到一两件是在路上;一件都没做,那 50% toil 上限就是空话。
下一章进入可观测性——有了工程时间,怎么用指标和告警做可靠性决策。