基础设施即工作流:超越静态 Terraform
SchemaBridge Team · 2026-01-18 · IaC, DevOps, Cloud Automation
管理 Day 2 云运维:将基础设施视为有状态、长时间运行的业务流程。
“基础设施即代码”的局限:Day 1 与 Day 2
我们热爱 Terraform(IaC)。它解决了“Day 1”的资源置备问题。你描述期望状态(10 台 EC2 实例、1 个 RDS、1 个 VPC),运行 terraform apply,云厂商就会把它变为现实。这对静态资源来说堪称完美。它是声明式的、幂等的,并且纳入版本控制。它是现代 DevOps 的基石。
但云运维的现实是:复杂性存在于 Day 2。Day 1 是婚礼;Day 2 是婚姻。Day 2 关乎的是流程,而不仅仅是资源。它关乎系统随时间变化而不断演进的、鲜活的生命周期。
以一次关键数据库升级的生命周期为例。这不是一个静态事件,而是一个工作流:
1. 准备:为安全起见,将主数据库快照到 S3。
2. 等待:你必须等待快照完成。对于数 TB 的大型数据库,这可能需要 30 到 45 分钟。
3. 置备:使用新的引擎版本,从快照启动一个新的数据库实例。
4. 等待:等待新实例变为“Available”和“Healthy”。
5. 迁移:连接到新实例并运行模式迁移脚本(Flyway 或 Liquibase)。这可能需要 1 小时。
6. 验证:针对新数据库运行一组冒烟测试,以确保数据完整性。
7. 切换:如果成功,更新 DNS CNAME,使其指向新数据库。
8. 回滚:如果任何一步失败,你必须还原 DNS 并销毁出问题的实例。
Terraform 并不适合做这些。它是声明式的,而不是命令式的。虽然有 time_sleep 和 local-exec provisioner 作为“等待 30 分钟”或“运行 SQL 脚本并检查退出码”的变通手段,但 Terraform 没有持久、可恢复、带审批关卡的流程模型。为了处理这些,团队通常会用 Jenkins 流水线、CircleCI 作业或 Python 脚本把 Terraform 包裹起来。我们又回到了本系列前文讨论过的“Glue Code Crisis”,只不过这次是在基础设施领域。这些脚本脆弱、无状态,而且一旦在 4 小时操作的中途失败,几乎无法调试。
将运维视为持久化工作流
在 SchemaBridge,我们认为基础设施运维就是业务工作流。它与支付处理流程有着相同的要求:可靠性、可审计性、状态管理和错误恢复。
将 Day 2 运维迁移到 SchemaBridge,你就为云获得了一个持久化编排器的能力:
- 持久化等待:需要等待 4 小时完成数据仓库导出?工作流会持久化地休眠,不占用任何 Jenkins 执行器或容器。
- 审批关卡:需要资深 SRE 或合规官批准 DNS 切换?工作流会在 Approval 步骤暂停,直到有审批权限的人在 Approvals 页面或通过 API 批准为止。无论耗时 5 分钟还是 5 天,状态都会保留(默认审批超时为 7 天);在它之前放置一个 Slack 步骤,即可发布一条附有待审批链接的消息。
- 显式回滚路径:SchemaBridge 不会替你执行隐藏的补偿逻辑,这是有意为之的特性:回滚是一条由你绘制的路径。把预期结果建模为数据——例如返回
failed的状态检查,或配置为将被拒绝(4xx)的调用转换为invalid_input结果的 Gateway——并将它们路由到恢复旧配置的清理分支。意外的步骤失败会让运行停在原处,这样运维人员可以检查情况并从失败的步骤重试,而不是让一个似懂非懂的回滚自动触发。
“控制平面”模式:与 AWS、K8s 和 Terraform 集成
SchemaBridge 并不取代 Terraform,而是编排它。我们使用控制平面模式来统一静态世界与动态世界。
1. 触发:开发者提交代码,或在你的开发者门户中调用工作流的 webhook URL,触发“Provision Dev Env”工作流。
2. 置备:SchemaBridge 调用 Terraform Cloud API(或你自己的 runner 的 HTTP 端点),启动创建物理资源的运行。SchemaBridge 不会自己通过 shell 调用 terraform:按照设计,工作流脚本运行在 GraalVM 沙箱中,无法访问进程或文件系统。
3. 等待:一个持久化的 Delay 步骤等待,随后一个 Gateway 步骤检查 Terraform 运行的状态。工作流是无环图,因此不能使用无限轮询循环,而是串联有限数量的“等待并检查”步骤,或者让工作流在 Delay 之后重新派生(re-spawn)自身——这与我们自己的渐进式发布系统工作流所使用的递归方式相同。
4. 置备后处理(“逻辑层”):基础设施就绪后,SchemaBridge 调用负责运行数据库迁移、填充测试数据和启动验收测试的端点——可以是你的 CI 系统 API,也可以是你在新集群中掌控的一个小型运维服务。
这种模式让你可以继续用 HCL(HashiCorp Configuration Language)定义资源,同时用可视化图来定义运维逻辑。
临时环境:开发效率的圣杯
每个现代工程团队都希望拥有临时环境——为每个 Pull Request(PR)提供一份完整的生产环境副本。这样可以实现真正的隔离,并在 bug 合并到 main 之前就将其拦截。
传统方案之所以失败,是因为清理很困难。你为 PR-123 启动了资源,但开发者忘了关闭 PR,或者清理脚本失败了。你的云账单随即被“僵尸 RDS 实例”和“孤儿负载均衡器”撑爆。
在 SchemaBridge 中,一个环境就是一个具有明确生命周期的工作流。
1. 启动:通过你的置备 API 启动资源(RDS、缓存、ECS 服务)。
2. 等待:一个持久化的 Delay 步骤在创建时就设定好拆除——例如 24 小时的 TTL。等待期间不占用任何 worker 或容器;唤醒时间会被持久化。
3. 清理:计时器到期后,工作流被唤醒并调用置备 API 销毁环境。如果需要“PR 一合并就拆除”,请将 Git 托管平台的合并 webhook 指向一个独立的拆除工作流,并让拆除操作保持幂等,这样两者都触发也不会造成损害。
由于拆除计时器是在创建环境的同一次运行中设定的,它很难被遗忘。即使整个 SchemaBridge 集群重启,持久化的计时器依然会触发,PR-123 的环境依然会按计划被销毁。这就是“云的垃圾回收”。
示例场景:为延迟敏感型服务实现免干预蓝绿部署
设想一个运营延迟敏感型撮合引擎的团队,需要在不产生哪怕一微秒停机的情况下更新其核心服务。
挑战
如果他们需要在切换流量之前,用实时数据对新版本的准确性验证 10 分钟,那么标准的 Kubernetes 滚动更新就不够安全。他们需要一个复杂的“Shadow Mode”部署。
SchemaBridge 方案
他们可以在 SchemaBridge 中构建一个“Blue/Green Deployment Workflow”:
1. 部署 Green:在旧版本旁边启动新版本的引擎(Green)。
2. 影子流量:配置 API Gateway,将实时流量的一份通用副本发送到 Green(fire-and-forget)。Green 的响应不会返回给用户,而是被记录下来。
3. 验证:在 10 分钟的 Delay 之后,工作流通过 HTTP 获取 Green 已记录响应的样本以及对应的 Blue(线上)响应,并使用 JSONata 进行比较。
4. 决策点:条件边根据比较结果进行路由:
- 如果准确率 < 100%,工作流发布告警,并调用部署 API 销毁
Green。 - 如果准确率 == 100%,工作流继续执行。
5. 切换:工作流更新负载均衡器,将真实用户流量切换到 Green。
6. 清理:再等待一小时(便于回滚),然后销毁 Blue。
结果
这类工作流有望大幅降低部署风险。SRE 团队可以触发部署后便离开,因为他们知道工作流会执行他们设计的验证流程和显式清理路径——把高风险、低频率的发布变成更安全的例行工作。
成本管理:FinOps 的“工作流”
云成本优化(FinOps)往往是一个靠人工不断催促开发者关闭资源的过程。SchemaBridge 让你可以将这种治理自动化。
Night Watchman 模式
你可以部署一个“Night Watchman”工作流,每晚 8:00 运行。
1. 扫描:向你的运维 API(例如一个封装了云 SDK 的小型 Lambda 或内部服务)查询所有带有非生产标签的资源。SchemaBridge 通过 HTTP 与它通信;它没有原生的 AWS 连接器。
2. 检查活跃度:让同一个端点报告过去一小时的 CPU 使用率,只保留低于 5% 的资源。
3. 关停:如果处于空闲状态,调用该端点停止实例(而不是终止)。
4. 通知:向所有者发送一条 Slack 消息:“为节省开支,我们已暂停你的开发机。”
5. 恢复:一个独立的“start my box”工作流由你的运维工具通过其 webhook URL 触发,在早上重新启动实例。
这样一个简单的工作流就能显著减少闲置开发环境的支出,削减那些被遗忘、始终运行的非生产资源的持续成本。
对比:Jenkins/GitLab CI 与 SchemaBridge 运维
| 特性 | CI/CD 流水线(Jenkins) | SchemaBridge 运维 |
| :--- | :--- | :--- |
| 状态 | 绑定在执行器上;长时间等待会占用资源 | 持久化(保存在 PostgreSQL 中;重启后依然存在) |
| 时长 | 分钟/小时 | 小时/天(持久化计时器) |
| 逻辑 | 脚本化(Bash/Groovy) | 可视化(图) |
| 审批 | 流水线中的 input 步骤 | Approval 步骤(UI 或 API),带超时 |
| 恢复 | 从某个 stage 重新开始 | 从失败的步骤重试 |
| 并行度 | 受执行器数量限制 | 扇出(Spawner),配合自动扩缩容的 worker |
运维自动化专家清单
要让你的运维体系现代化,请遵循以下经验法则:
1. 不要在脚本里写等待:如果你在 bash 里写 sleep 60 来等待 ALB,那就做错了。请使用持久化的 Delay 步骤,再接一个状态检查。
2. 先自动化删除:在编写创建逻辑之前先编写清理逻辑。确保每个创建事件都有对应的销毁路径。
3. 使用审批关卡:对于高风险操作,不要害怕让人参与其中。“Pause for Approval”是特性,不是缺陷。
4. 审计操作者:记录是谁触发了环境、为什么触发。让触发方在载荷中传入请求者的 ID,并把它标记到你创建的每个资源上。
5. 将运维视为代码:像管理应用代码一样对运维工作流进行版本控制。将它们导出为 bundle,保存在代码仓库中以便评审,并通过 Deployments 页面(规划、评审、应用)或配置导入进行部署。
结论:云是一台状态机
你的基础设施不是一堆静态的服务器,而是业务中鲜活的组成部分。把它当作状态机来对待,你就能自动化那些目前耗尽 SRE 团队精力的复杂多步运维流程。你可以从“基于工单的运维”迈向“自助式运维”,并内建安全性与持久性。
另请参阅:冷启动迷思:为事件优化 JVM——为什么长时间运行的 worker 胜过按事件冷启动。