3. 漂移检测原理:Pulumi Refresh 机制、Refresh vs Preview、漂移检测的触发时机
漂移检测是堆栈复核流程的核心前置环节。Pulumi 通过 Refresh 机制将云商实际资源状态拉取到本地状态文件,再与期望的 IaC 代码进行比对,从而发现非代码变更导致的差异。理解 Refresh 的内部原理、与 Preview 的区别以及触发时机,是构建可靠复核流程的基础。
3.1 Pulumi Refresh 机制
Refresh 的本质是 状态同步 操作。它不会修改云上资源,而是用云商返回的最新属性覆盖 Pulumi 状态文件(pulumi.state)中的对应字段。其核心流程如下:
- 读取状态文件:Pulumi 加载当前堆栈的
.pulumi/stacks/<stack-name>.json,获取所有托管资源的 URN 和 ID。 - 调用云商 API:对每个资源调用对应的 Read 操作(如 AWS
DescribeInstances、AzureGetVM)。 - 比对并更新状态:将 API 返回的属性与状态文件中的属性逐字段比对,若不一致则用最新值更新状态文件。
- 输出差异摘要:在终端或日志中列出所有发生变化的属性,但不会生成 IaC 代码层面的变更计划。
关键认知:Refresh 只更新状态文件,不修改
index.ts 或 Pulumi.yaml 等代码文件。漂移检测的最终结论需要将 Refresh 后的状态与代码进行 pulumi preview 比对才能得出。
以下是一个 Refresh 操作的典型输出示例:
$ pulumi refresh --yes
Previewing refresh (dev):
Type Name Plan Info
pulumi:pulumi:Stack infra-dev running...
~ aws:s3:Bucket my-app-bucket update [diff: +tags, -versioning]
~ aws:ec2:Instance web-server update [diff: ~instanceType, +userData]
aws:iam:Role app-role no change
Resources:
~ 2 to update
1 no change
3 resources refreshed
Duration: 4.2s
上述输出中,~ 表示状态文件中的属性被更新,+ 表示新增属性,- 表示移除属性。这些变化仅反映状态文件与云商实际资源之间的差异,并非代码与云商之间的差异。
3.2 Refresh vs Preview:核心差异
初学者常混淆 Refresh 和 Preview。两者虽然都涉及比对,但目的、操作对象和结果完全不同。下表从多个维度进行对比:
| 对比维度 | pulumi refresh | pulumi preview |
|---|---|---|
| 操作对象 | 状态文件 vs 云商实际资源 | 状态文件 vs IaC 代码(index.ts 等) |
| 是否修改状态 | 是,用云商最新属性覆盖状态文件 | 否,只读操作,不修改任何文件 |
| 是否修改云资源 | 否,只读取不写入 | 否,只计算不执行 |
| 输出内容 | 状态文件与云商资源的差异 | 代码与状态文件的差异(即变更计划) |
| 典型用途 | 漂移检测前的状态校准 | 代码变更影响评估、CI 审批 |
| 执行速度 | 较慢,需调用云商 API 读取所有资源 | 较快,仅基于本地状态和代码计算 |
在漂移复核流程中,两者的关系是 先 Refresh 后 Preview:
- Step 1:执行
pulumi refresh,将状态文件与云商实际资源对齐。 - Step 2:执行
pulumi preview,此时状态文件已反映真实云环境,Preview 输出的差异即为 代码与真实环境之间的漂移。
常见误区:直接执行
pulumi preview 而不先 Refresh,得到的差异是代码与旧状态文件的差异,而非代码与真实云环境的差异。如果云上资源已被手动修改,这种 Preview 会漏报漂移。
3.3 漂移检测的触发时机
漂移检测并非每次操作都自动执行,需要根据场景选择合适的触发时机。以下是生产环境中推荐的四种触发模式:
- 定时触发(推荐):通过 CI/CD 定时任务(如 CronJob、GitHub Actions Schedule)每 6 小时或每天执行一次
pulumi refresh && pulumi preview,适用于合规性要求高的生产环境。 - 事件触发:当云商发生资源变更事件(如 AWS CloudTrail、Azure Monitor 告警)时,自动触发漂移检测。适合需要快速响应的动态环境。
- 人工触发:运维人员在排查故障或进行变更前,手动执行漂移检测命令。适用于临时性复核。
- 变更前触发:在每次
pulumi up之前自动执行 Refresh,确保部署基于最新的真实状态。Pulumi 默认在up前会询问是否 Refresh,可通过--skip-preview跳过,但不建议在生产环境跳过。
下图展示了漂移检测在堆栈复核流程中的完整触发链路:
3.4 漂移检测的自动化脚本示例
以下是一个适用于 CI/CD 环境的漂移检测脚本,集成了 Refresh 和 Preview 两个步骤,并输出结构化结果:
#!/bin/bash
# drift-detection.sh - 堆栈漂移检测脚本
# 用法: ./drift-detection.sh <stack-name> [--json]
set -euo pipefail
STACK_NAME="${1:?请提供堆栈名称}"
OUTPUT_FORMAT="${2:--normal}"
echo "=== 步骤 1: 执行 Refresh 同步状态 ==="
if [ "$OUTPUT_FORMAT" == "--json" ]; then
pulumi refresh --stack "$STACK_NAME" --yes --json > refresh-result.json 2>&1
else
pulumi refresh --stack "$STACK_NAME" --yes
fi
echo "=== 步骤 2: 执行 Preview 检测漂移 ==="
if [ "$OUTPUT_FORMAT" == "--json" ]; then
pulumi preview --stack "$STACK_NAME" --json > preview-result.json 2>&1
echo "漂移报告已保存至 preview-result.json"
else
pulumi preview --stack "$STACK_NAME"
fi
echo "=== 漂移检测完成 ==="
生产建议:在 CI 流水线中,建议将
--json 输出解析为结构化数据,通过 Webhook 发送到告警平台(如 PagerDuty、Slack),实现漂移事件的自动通知与工单创建。
3.5 漂移检测的触发时机对比表
下表总结了四种触发时机的适用场景、频率和优缺点,帮助你在实际项目中做出选择:
| 触发方式 | 频率 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 定时触发 | 每 6h / 12h / 24h | 生产环境合规巡检 | 自动化、可预测、审计友好 | 无法实时发现漂移 |
| 事件触发 | 实时(秒级) | 动态环境、安全敏感场景 | 响应快、覆盖手动变更 | 依赖云商事件服务、成本较高 |
| 人工触发 | 按需 | 故障排查、变更前复核 | 灵活、无额外成本 | 依赖人员主动性、可能遗漏 |
| 变更前触发 | 每次 pulumi up 前 |
CI/CD 部署流水线 | 确保部署基于最新状态 | 增加部署耗时(约 10-30s) |
在实际的堆栈复核流程中,建议采用 定时触发 + 变更前触发 的组合策略:定时任务负责周期性巡检,变更前触发确保每次部署的准确性。对于安全等级较高的环境,可额外叠加事件触发,实现近乎实时的漂移监控。