← 文章 / 云原生与基础设施
freeCodeCamp 1小时前 · 2026-09-25 08:24:01 · 0 阅读

可执行的运营规范:让软件自动化变得可验证

现代软件系统正变得越来越自动化。部署、基础设施变更、扩缩容、故障响应以及数据管道,这些环节都在被自动化。

如今,借助 AI Agent,我们开始将运营决策也纳入自动化范畴。这听起来是进步,但随之而来的问题往往容易被忽视:

我们越来越擅长执行运维操作,却未必更擅长定义这些操作本应达成的目标。

部署流水线可以成功运行,却可能违反了关键的业务约束。

基础设施脚本可以无错误执行完毕,却可能让系统停留在错误状态。

AI Agent 可以完成一系列动作,却可能产生事后无人能验证的结果。

在许多系统中,运营意图依然散落在:

runbooks
tickets
Slack messages
CI/CD configuration
Terraform files
dashboards
monitoring rules
human memory

这些产物固然有用,但它们并不等同于可执行的运营规范。

可执行的运营规范以可评估的方式描述预期行为,以便日后对照实际发生的情况进行验证。

随着执行速度加快、分布更广、自主性增强,这一区分变得越来越重要。

本文将探讨:

  • 为何仅靠自动化并不足够,

  • 执行逻辑与运营意图之间的区别,

  • 可执行的运营规范究竟是什么,

  • 为何单靠可观测性(Observability)无法独立解决此问题,

  • 规范如何让运维行为变得可验证,

  • 该方式如何应用于 CI/CD、基础设施、故障响应及 AI Agent,

  • 一份最小化的规范可能长什么样,

  • 以及这种方法仍然无法解决哪些困境。

核心思想很简单:

如果一个系统能够自动执行某项操作,那么我们就应当能够独立于执行该操作的工具,去描述何为“执行成功”。

先决条件

你应该熟悉以下内容:

  • 软件架构

  • CI/CD

  • 基础设施自动化

  • 可观测性

  • 分布式系统

  • 基础测试概念

  • 自动化工作流

你不需要使用任何特定的云服务商、部署平台或编排工具。

本文介绍的理念刻意做到了与具体工具无关。

目录

自动化解决的是执行,而非意图

设想一条部署流水线,它的流程可能是:

构建应用
运行测试
构建镜像
推送镜像
部署应用
等待就绪
标记流水线成功

如果每一步都顺利完成,流水线就会变绿。但这条流水线究竟证明了什么?

通常,它只证明了类似以下的事实:

配置的步骤已顺利完成

这很有用,但不一定等同于:

预期的运维结果已达成

假设部署在技术上成功了,但实际状况却是:

部署了错误版本的镜像
实际运行的副本数是两个而非三个
错误率上升了
必需的特性开关处于关闭状态
服务本身健康,但无法访问依赖项
滚动更新违反了地域约束

执行者履行了职责,但广义上,这次运维操作失败了。这就是< strong>执行成功与运维合规性之间的差距。

自动化告诉我们的只是:

各步骤已运行。

而我们要知道的往往是:

最终系统是否满足预期条件?

这是两个不同的问题。

运维知识通常是碎片化的

大多数生产系统中其实已经包含了运维知识,问题在于它们分散各处。

例如,一条部署规则可能分散存在于:

GitHub Actions
Terraform
Kubernetes 清单
Grafana 仪表盘
PagerDuty 告警
运维手册
工单
资深工程师的记忆

某份配置定义了副本数量,另一份定义了可接受的错误率,第三份解释了何时需要回滚,第四份则说明了允许的地域范围。

没有任何单一的数据来源能完整表述:

我们要执行的运维操作是什么。

它的约束条件有哪些。

我们需要哪些证据。

以及如何判断它是否成功。

这使得运维操作的逻辑推演变得困难,也让自动化流程显得脆弱。

当规则分散在各类工具中时,执行器往往会成为事实上的规范。

一旦形成这种局面,就难以判断执行器的行为是否正确。

因为执行动作的逻辑与定义成功的逻辑,在本质上被混为一谈了。

执行逻辑与运维意图是两回事

想象这样一个部署脚本:

kubectl set image \
  deployment/orders \
  orders=registry.example.com/orders:2026.09.19

这告诉 Kubernetes 如何执行动作。但它并未完整描述该动作为何可接受。

运维意图更接近于以下描述:

部署 Orders 服务的 2026.09.19 版本。

约束条件:

- 生产环境必须至少保持 3 个可用副本
- 错误率必须保持在 1% 以下
- p95 延迟必须低于 400 毫秒
- 仅允许在 us-east-1 区域部署
- 必须保持 30 分钟内的回滚能力

命令和意图有关联,但二者并非同一产物。

这种区分很重要,因为不同的执行器都可能满足同一意图。

例如:

Kubernetes
Nomad
云部署服务
自定义部署控制器
AI 驱动的平台

如果运维目标是独立表达的,执行器就可以被替换。

如果目标嵌入在执行器专属代码中,更换执行器可能意味着需要重新发掘意图。

什么是可执行的运维规范?

可执行的运维规范是一种机器可读的运维目标描述,可以对照观测证据进行评估。

至少,它应回答如下问题:

我们要达成什么目标?

必须满足哪些约束条件?

应收集哪些证据?

如何判断操作是否符合规范?

例如:

operation: deploy-orders-service

target:
  service: orders
  version: 2026.09.19
  environment: production

constraints:
  minAvailableReplicas: 3
  maxErrorRate: 0.01
  maxP95LatencyMs: 400
  region: us-east-1

evidence:
  - deployedVersion
  - availableReplicas
  - errorRate
  - p95Latency
  - region

这里刻意写得简单。重点不在 YAML 语法本身。

真正关键的是:这份规格对"成功"的定义,与执行部署所用的方式彼此独立。

由此形成一个这样的结构:

运维意图
        ↓
规格
        ↓
执行器
        ↓
执行
        ↓
证据
        ↓
评估

规格成为了一个稳定的参照点。

一个简单的部署示例

假设我们要部署 Orders 服务的 2026.09.19 版本。

只有满足以下条件,这次操作才算成功:

正确版本正在运行
至少三个副本可用
错误率保持在 1% 以下
p95 延迟保持在 400 ms 以下

可以用代码表示为:

type DeploymentSpec = {
  service: string;
  version: string;
  minAvailableReplicas: number;
  maxErrorRate: number;
  maxP95LatencyMs: number;
};

例如:

const spec: DeploymentSpec = {
  service: "orders",
  version: "2026.09.19",
  minAvailableReplicas: 3,
  maxErrorRate: 0.01,
  maxP95LatencyMs: 400,
};

现在假设执行过程产生了如下证据:

type DeploymentEvidence = {
  deployedVersion: string;
  availableReplicas: number;
  errorRate: number;
  p95LatencyMs: number;
};

例如:

const evidence: DeploymentEvidence = {
  deployedVersion: "2026.09.19",
  availableReplicas: 3,
  errorRate: 0.004,
  p95LatencyMs: 280,
};

我们可以拿证据与规格做比对:

function conforms(
  spec: DeploymentSpec,
  evidence: DeploymentEvidence
): boolean {
  return (
    evidence.deployedVersion ===
      spec.version &&
    evidence.availableReplicas >=
      spec.minAvailableReplicas &&
    evidence.errorRate <=
      spec.maxErrorRate &&
    evidence.p95LatencyMs <=
      spec.maxP95LatencyMs
  );
}

然后执行:

console.log(
  conforms(spec, evidence)
);

结果是:

true

再设想一种情况:流水线在技术上执行成功,但最终只剩两个副本可用:

const evidence: DeploymentEvidence = {
  deployedVersion: "2026.09.19",
  availableReplicas: 2,
  errorRate: 0.004,
  p95LatencyMs: 280,
};

执行器可能仍会报告成功。

但规格不会:

conforms → false

这正是我们想要做出的区分。

将成功标准转化为证据要求

只有当规范中的声明可被评估时,它才具备实用价值。

假设规范规定:

错误率必须保持在 1% 以下

那么系统就需要关于以下内容的证据:

错误率

如果规定:

至少 3 个副本必须保持可用

那么就需要关于以下内容的证据:

可用副本数量

这听起来显而易见,但它引入了一种重要的纪律性:

每项运维要求都应隐含某种形式的可观测证据。

举例来说:

要求 证据
部署了正确版本 正在运行的镜像/版本
最少副本数可用 副本数量
错误率低于阈值 请求/错误指标
延迟低于阈值 延迟指标
位于正确区域 运行时部署位置
无架构回退 架构校验结果

这种关系之所以重要,是因为模糊的运维目标很难安全地自动化。

例如:

安全部署。

什么证据能证明这一点?

这个陈述太模糊了。

更好的规范会将“安全”分解为可检查的条件。

为什么仅有可观测性是不够的

此时你可能会问:

这不就是可观测性吗?

不完全是。可观测性有助于回答:

正在发生什么?

而规范有助于回答:

应该发生什么?

这两个问题是互补的。

仪表盘可能会告诉你:

error rate = 1.4%

这是一个观测结果。

但 1.4% 是否可接受,取决于预期的条件。

规范可能会说:

maxErrorRate = 1%

现在你可以评估:

observed: 1.4%
expected: <= 1%

result: non-conformant

没有预期条件,指标只是一个孤立的数字;没有指标,规范就无法得到验证。两者缺一不可。

其概念结构如下:

规范
     +
观测证据
     ↓
评估

规范使自动化过程可验证

缺乏独立规范约束的自动化系统,验证难度极高。

设想一个执行以下操作的脚本:

扩缩容服务
重启 Pod
调整路由
等待
完成

如果脚本也是编码预期结果的唯一地方,那么质疑其是否正确就陷入了循环论证。

你实际上是在问:

自动化是否做了它声称应该做的事?

独立的规范提供了另一个参照系。

现在你可以这样审视:

原本的意图是什么?

执行器实际做了什么?

执行过程产生了什么证据?

证据是否满足规范要求?

这让运维过程更容易审计和测试,也让故障定位更有价值。

这样你就不会只看到:

部署失败

而是可以潜在地指出:

部署执行已完成

但规范校验未通过,原因如下:

availableReplicas:
期望 >= 3
实际 = 2

这样的信息量大得多。

规范应与执行器保持独立

该模型最显著的优势之一是执行器无关性。

假设规范如下:

部署订单服务版本 2026.09.19

要求:
- >= 3 个副本
- 错误率 <= 1%
- p95 延迟 <= 400 ms

不同的执行器可以采用不同的技术栈:一个基于 Kubernetes,一个基于托管云平台,还有一个可能是自研编排器。

即使执行器发生变化,规范本身也不应因此调整。

其概念示意图如下:

                 ┌── Kubernetes 执行器
规范 ─────────────┼── 云托管执行器
                 ├── 自研编排执行器
                 └── AI Agent

每种执行器都会产生执行证据,而每次执行都将基于同一套意图进行评估。

这就形成了一种有用的职责分离:

发生什么(目标状态)

与:

如何发生(执行方式)

这种分离在软件工程的其他领域也很常见:接口将调用方与实现分离,SQL 将查询与存储机制分离,期望状态系统将目标状态与协调逻辑分离。

操作规格将类似的思路应用到了运维工作流上。

一个极简的 TypeScript 模型

一个简单的通用模型大概长这样:

type Constraint<T> = {
  name: string;
  evaluate(
    evidence: T
  ): boolean;
};

type OperationalSpec<T> = {
  name: string;
  constraints: Constraint<T>[];
};

针对部署证据:

type Evidence = {
  version: string;
  replicas: number;
  errorRate: number;
};

你可以定义:

const deploymentSpec:
  OperationalSpec<Evidence> = {
    name: "deploy-orders",
    constraints: [
      {
        name: "correct-version",
        evaluate: (evidence) =>
          evidence.version ===
          "2026.09.19",
      },
      {
        name: "minimum-replicas",
        evaluate: (evidence) =>
          evidence.replicas >= 3,
      },
      {
        name: "error-rate",
        evaluate: (evidence) =>
          evidence.errorRate <= 0.01,
      },
    ],
  };

然后对每条约束进行求值:

function evaluate<T>(
  spec: OperationalSpec<T>,
  evidence: T
) {
  return spec.constraints.map(
    (constraint) => ({
      constraint: constraint.name,
      passed:
        constraint.evaluate(
          evidence
        ),
    })
  );
}

对于:

const evidence: Evidence = {
  version: "2026.09.19",
  replicas: 2,
  errorRate: 0.003,
};

你可能会得到:

correct-version    PASS
minimum-replicas   FAIL
error-rate         PASS

这比一个笼统的成功或失败标志有用得多——它能准确告诉你预期操作中哪一部分不符合要求。

如何应用到 CI/CD

CI/CD 系统本身已经包含一些声明式的元素。

比如:

steps:
  - test
  - build
  - deploy

但这些步骤大多只描述了执行顺序。规格可以在其基础上补充运维层面的预期。

例如:

部署目标:
发布版本 X

约束条件:
测试通过
构件摘要与已批准的构建一致
最小副本数保持可用
错误率维持在阈值以下
回滚仍可行

流水线仍负责执行具体工作,而规范则定义流水线必须满足的条件。这让替换流水线变得更加容易。

如果你从:

GitHub Actions

迁移到:

GitLab CI

或者:

Argo

执行器发生了变化。

但运营目标不一定需要改变。

这如何适用于基础设施

基础设施即代码(Infrastructure-as-code)已经让我们拥有了期望状态,这与上述理念紧密相关。

例如:

resource "aws_instance" "app" {
  instance_type = "t3.medium"
}

但运营意图往往超越了配置状态。

你可能还需要关注:

服务可用性
成本限制
区域限制
安全控制
容量
延迟
备份新鲜度

这些约束可能存在于 IaC 定义之外。运营规范可以将它们整合起来。

例如:

预配应用程序环境

必需条件:
3 个实例
区域 = us-east-1
月度预计成本 < $500
启用加密
备份年龄 < 24h

执行器可能会使用 Terraform。

证据可能来自:

云 API
成本系统
安全扫描器
备份元数据

规范为这些来源提供了共同的目的。

这如何适用于事件响应

事件响应是另一个执行与意图经常混淆的地方。

操作手册(Runbook)可能会说:

重启服务
清除缓存
扩展副本数

但实际的运营目标可能是:

恢复结账可用性

同时:
避免重复支付
保持订单状态
将错误率保持在阈值以下

这种区别至关重要。

如果重启服务无法恢复结账可用性,那么操作手册虽然技术上执行了,但该操作已失败。

可执行规范可以表达恢复条件:

结账成功率 > 99%
支付重复次数 = 0
队列积压 < 阈值
错误率 < 1%

这样,事件自动化就能根据其达成的结果来评估,而非仅仅依据它执行的操作。

如何适用于 AI 智能体

对于 AI 智能体,这一点变得更加关键。传统自动化通常遵循预定义的执行逻辑。

而 AI 智能体可能动态选择执行路径。例如,运维智能体可能会决定:

inspect metrics
restart a service
change capacity
modify a feature flag
reroute traffic

具体的执行序列可能因事件而异。这使得执行层面的验证更加困难。

我们不能总是通过检查智能体是否遵循了某条特定脚本来验证它。但我们仍然可以验证其运维意图。

例如:

Objective:
restore API availability

Constraints:
do not disable authentication
do not lose queued requests
error rate < 1%
p95 latency < 500 ms
cost increase < 20%

智能体可能会选择不同的操作,但规范本身保持稳定。

这建立了一种有用的控制结构:

Human / organizational intent
        ↓
Operational specification
        ↓
Agent
        ↓
Actions
        ↓
Evidence
        ↓
Evaluation

执行越自主,这种分离的价值就越高。

运维规范应包含什么

一份实用的规范通常包含几个类别。

目标

需要达成什么?

例如:

Deploy Orders service version 2026.09.19

范围

该操作适用于哪里?

例如:

environment: production
region: us-east-1
service: orders

约束

哪些条件必须保持?

例如:

available replicas >= 3
error rate <= 1%
p95 latency <= 400 ms

所需证据

必须观察到什么?

例如:

running version
replica count
error rate
latency

评估规则

如何判断执行是否合规?

例如:

version must match exactly
replicas must be >= 3
error rate must be <= 0.01

恢复条件

如果合规失败,应该发生什么?

例如:

stop rollout
restore previous route
require human approval

并非每个规格都需要包含上述所有部分。

但把它们区分开,能让运维意图清晰得多。

哪些东西不应该写进规格?

规格不应该变成另一份实现脚本,也就是说,要避免与特定执行器绑定的具体细节。

比如,下面这种写法就太偏实现了:

run kubectl command X
wait 10 seconds
call endpoint Y
run shell command Z

这些应该放到执行器里。规格应该聚焦于期望达成的运维结果。

例如:

service version = 2026.09.19
available replicas >= 3
health checks passing

一个实用的判断标准是:

如果更换执行工具就得重写规格,那说明规格里掺入了太多实现细节。

有些执行器相关的约束无法避免,但默认原则应该是把意图和机制分开。

一个可落地的实践流程

如果要把可执行运维规格引入现有系统,我会从小处着手。

1. 选一个重要操作

比如:

deploy service
rotate certificate
restore backup
scale worker pool

2. 写下目标

问自己:

成功到底意味着什么?

而不是:

我们要执行哪些命令?

3. 明确约束

例如:

minimum availability
maximum error rate
security requirements
regional restrictions
cost limits

4. 明确证据

针对每条约束,问:

什么样的观察能证实或证伪这个条件?

5. 把执行器独立出来

让实际执行操作的机制与规格保持独立。

6. 执行后评估

收集证据,并与规格进行比对。

7. 报告符合情况

与其输出:

operation failed

不如输出:

3 constraints passed
1 constraint failed

8. 持续改进规格

缺失的证据和模糊的约束很快就会暴露出来。

这很有价值。

随着运维知识被显式化,规格也会不断完善。

可执行规格解决不了的问题

可执行规格说明并非一套完整的运维架构。

它们无法自动解决以下问题:

需求定义不当
指标错误
可观测性缺失
分布式事务处理
安全漏洞
执行器实现质量差
职责归属不清
业务目标冲突

它们也会引入自身特有的风险:

  • 糟糕的规格说明可能会固化错误的目标。

  • 不完整的规格说明会营造虚假的信心。

  • 过时的规格说明会成为另一种漂移来源。

  • 并非所有运维决策都能简化为一个简单的阈值判断。

人的判断依然至关重要。目标不是消除判断,而是让运维意图更加明确、更具可测试性。

从自动化运维到可验证运维

软件运维多年来一直在走向自动化,这一趋势仍将持续。但自动化程度越高,新的问题随之而来:

如何确认自动化达成了正确的结果?

执行日志、流水线成功状态以及智能体的置信度都不足以说明问题。我们需要一个基准来对比执行情况,这正是可执行运维规格说明发挥作用的地方。

它为我们提供了:

意图
↓
约束条件
↓
证据要求
↓
执行
↓
观察到的证据
↓
评估

这种结构将运维行为从:

某件事发生了

转变为:

某件事发生了,
我们清楚预期是什么,
我们收集了证据,
并且可以评估结果。

这为自动化奠定了坚实基础。

结语

软件运维的自动化程度越高,我们就越需要区分我们想要什么与工具如何执行。

流水线是执行器。

基础设施工具、脚本和 AI 智能体也都是执行器。它们都能执行动作。

但运维目标应当独立于执行机制而存在。

可执行运维规格说明让我们能够以以下方式描述该目标:

期望结果
约束条件
所需证据
评估规则

如此一来,执行过程便不再是单纯被观察,而是可以被验证的。

在当前,这对部署、基础设施和事故响应至关重要。

随着运维系统日益走向自治,其重要性将进一步提升。

自动化只能告诉我们某项操作是否已执行,

但我们真正需要确认的是系统是否最终达到了预期状态。

原始来源: freeCodeCamp

评论 (0)