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 |
引擎选型提示: 如果团队已深度使用 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% 应触发回滚。这种边界测试能有效防止回滚护栏误判或漏判。