3. Policy as Code 基础:策略即代码的核心概念

Policy as Code(策略即代码,PaC)是将基础设施、安全、合规与运维策略以机器可读的代码形式进行声明、版本化、测试和自动执行的方法论。它打破了传统策略依赖人工审核、静态文档和事后审计的局限,将策略直接嵌入 CI/CD 流水线,实现“策略即护栏”的自动化治理。

3.1 核心概念:从文档到代码的范式迁移

维度 传统策略管理 Policy as Code
载体 Word/PDF 文档、Wiki 页面 版本化代码文件(.rego, .hcl, .sentinel)
执行时机 事后审计、人工抽查 流水线门禁(Pre-commit / CI 阶段)
一致性 依赖个人理解,易产生偏差 机器执行,结果可复现
变更管理 邮件审批,无版本追溯 Git PR + Code Review + 自动化测试
回滚能力 无原生支持 策略版本回退 + 流水线自动阻断
关键洞察: PaC 的核心价值不在于“写代码”,而在于将策略的可观测性、可测试性和可追溯性提升到与业务代码同等的水平。回滚护栏正是这一能力的直接体现——当部署违反策略时,流水线自动阻断并触发回滚,而非等待人工发现。

3.2 声明式策略 vs 命令式策略

理解两种策略编写范式是掌握 PaC 的基础。它们决定了策略的表达方式、执行模型和可维护性。

3.2.1 命令式策略(Imperative Policy)

描述“如何做”才能满足策略。通常包含 if-else 分支、循环、显式步骤。与通用编程语言(Python、Go)结合紧密,但策略逻辑与执行逻辑耦合度高。

# 伪代码:命令式策略示例
def check_container_resources(container):
    if container.cpu_limit is None:
        raise PolicyViolation("CPU limit must be set")
    if container.memory_limit is None:
        raise PolicyViolation("Memory limit must be set")
    if container.cpu_limit > 4:
        raise PolicyViolation("CPU limit cannot exceed 4 cores")
    return True

3.2.2 声明式策略(Declarative Policy)

描述“应该是什么状态”,而不关心如何检查。策略引擎自动将输入数据与规则进行匹配和推理。代码更简洁、可组合性强,适合大规模策略库管理。

# Rego 语言:声明式策略示例(OPA)
package kubernetes.admission

violation[msg] {
    container := input.request.object.spec.containers[_]
    not container.resources.limits.cpu
    msg := sprintf("Container %v must have CPU limit set", [container.name])
}

violation[msg] {
    container := input.request.object.spec.containers[_]
    cpu_limit := container.resources.limits.cpu
    to_number(cpu_limit) > 4
    msg := sprintf("Container %v CPU limit %v exceeds max 4 cores", [container.name, cpu_limit])
}
对比维度 命令式策略 声明式策略
表达焦点 检查步骤(How) 期望状态(What)
可读性 随逻辑复杂度下降 接近自然语言规则
组合性 需手动编排函数 规则自动合并/覆盖
测试难度 需 Mock 执行环境 纯数据驱动,易于单元测试
回滚场景适配 需额外编写回滚逻辑 策略变更即回滚条件变更
实践建议: 在回滚护栏场景中,优先采用声明式策略。因为回滚条件(如“金丝雀错误率 > 5%”)天然适合用声明式规则表达,且策略引擎可以独立于流水线执行,降低耦合风险。

3.3 策略引擎介绍:OPA 与 Sentinel

策略引擎是 PaC 的执行运行时。它接收输入数据(如部署清单、监控指标、请求上下文),根据预定义策略规则输出决策(允许/拒绝/警告)。当前业界主流引擎为 OPA(Open Policy Agent)和 HashiCorp Sentinel。

3.3.1 OPA(Open Policy Agent)

  • 语言: Rego — 专为声明式策略设计的 DSL
  • 部署模型: 独立进程 / Sidecar / Go Library
  • 集成方式: REST API、Kubernetes Admission Webhook、Terraform Provider
  • 回滚场景优势: 支持 Bundle 热更新,策略变更无需重启;内置 Partial Evaluation 可预计算回滚条件

3.3.2 HashiCorp Sentinel

  • 语言: Sentinel — 类 Python 的声明式+命令式混合 DSL
  • 部署模型: 嵌入 Terraform / Vault / Consul 企业版
  • 集成方式: Terraform Cloud 策略集、Vault 策略检查
  • 回滚场景优势: 与 Terraform 原生集成,可在 Plan 阶段阻断并触发状态回滚
特性 OPA Sentinel
开源/商业 CNCF 毕业项目(开源) HashiCorp 企业版(商业)
策略语言 Rego(纯声明式) Sentinel(混合式)
生态范围 K8s、Terraform、Envoy、Kafka Terraform、Vault、Consul
回滚集成深度 需自定义流水线适配 Terraform Cloud 原生支持
策略分发 Bundle API / OCI 镜像 Policy Set API
策略引擎在回滚护栏中的位置 输入数据 部署清单 / 监控指标 / 请求 策略引擎 OPA / Sentinel 策略库 Rego / Sentinel 规则 决策输出 允许 / 拒绝 / 警告 回滚触发 流水线阻断 + 自动回滚 说明: 策略引擎作为独立决策点,接收流水线输入,匹配策略库规则,输出决策。 当决策为“拒绝”时,流水线触发回滚护栏,自动执行回滚操作。
引擎选型提示: 如果团队已深度使用 Terraform Cloud 且预算允许,Sentinel 可提供开箱即用的回滚集成。如果追求开源生态、多平台覆盖(K8s + Terraform + 自定义服务),OPA 是更灵活的选择。本课程后续示例将基于 OPA + Rego 展开,因其策略语言更贴近“声明式回滚条件”的表达范式。

3.4 策略即代码的版本化与测试

PaC 的工程化落地离不开版本控制和自动化测试。策略代码应像应用代码一样纳入 Git 仓库,并通过 CI 流水线进行验证。

  • 版本化: 策略仓库独立于应用仓库,使用语义化版本标签(v1.0.0)与流水线版本绑定
  • 单元测试: 为每条策略规则编写输入/期望输出用例,确保策略变更不破坏已有规则
  • 集成测试: 在预发布环境模拟真实部署数据,验证策略引擎与流水线的交互
  • 策略审计: 所有策略变更通过 PR 审查,合并后自动同步到策略引擎
# OPA 策略单元测试示例(test_policy.rego)
package kubernetes.admission

test_cpu_limit_missing {
    # 输入:容器未设置 CPU limit
    input := {"request": {"object": {"spec": {"containers": [{"name": "web"}]}}}}
    violations := violation with input as input
    count(violations) == 1
    violations[0] == "Container web must have CPU limit set"
}

test_cpu_limit_exceeded {
    # 输入:容器 CPU limit 超过 4
    input := {"request": {"object": {"spec": {"containers": [{"name": "web", "resources": {"limits": {"cpu": "6"}}}]}}}}
    violations := violation with input as input
    count(violations) == 1
    violations[0] == "Container web CPU limit 6 exceeds max 4 cores"
}
回滚护栏测试策略: 为每条回滚条件编写“触发测试”和“不触发测试”。例如:错误率 4.9% 应通过,5.1% 应触发回滚。这种边界测试能有效防止回滚护栏误判或漏判。