State 管理概述
什么是 Pulumi State?
Pulumi State 是一个 JSON 文件,记录了 Pulumi 当前管理的所有云资源的快照:包括每个资源的类型、名称、属性和云平台上的实际 ID。每次 pulumi up 后,State 都会更新。
State 是 Pulumi 计算"增量变更"的依据:目标状态(你的代码)减去当前状态(State 文件)= 需要执行的操作。没有 State 文件,Pulumi 就无法知道哪些资源已经存在,会试图重新创建所有资源。
State 后端选择
| 后端 | 配置 | 优点 | 适用场景 |
|---|---|---|---|
| Pulumi Cloud | pulumi login |
免费、免运维、内置 secrets 加密、Web UI | 大多数团队的首选 |
| AWS S3 | pulumi login s3://bucket |
完全自控、无 SaaS 依赖 | 安全合规要求高 |
| Azure Blob | pulumi login azblob://container |
Azure 生态集成 | 以 Azure 为主的团队 |
| GCS | pulumi login gs://bucket |
GCP 生态集成 | 以 GCP 为主的团队 |
| 本地文件 | pulumi login --local |
简单快速 | 本地开发测试 |
# 切换到 S3 后端
pulumi login s3://my-pulumi-state-bucket/prefix
# 切换到 Azure Blob 后端
pulumi login azblob://my-state-container
# 从 Pulumi Cloud 迁移到 S3
pulumi login # 先登录 Cloud
pulumi stack export > stack-state.json # 导出状态
pulumi login s3://my-pulumi-state-bucket # 切换后端
pulumi stack import < stack-state.json # 导入状态
pulumi refresh:同步漂移
配置漂移(State Drift)是指云资源被 Pulumi 之外的方式修改(手动在控制台改配置、其他工具修改等),导致 Pulumi State 与云上实际状态不一致。
# pulumi refresh:将云上实际状态同步到 State 文件
# (更新 State,不修改代码)
pulumi refresh
# refresh 后再 plan,会显示漂移产生的差异
pulumi preview
# 自动接受 refresh(CI/CD 中)
pulumi refresh --yes
refresh 的注意事项
pulumi refresh 将 State 更新为云上实际状态,可能会"接受"一些手动改动。如果你随后运行 pulumi up,Pulumi 会尝试将这些漂移"修正"回代码描述的目标状态。要保留手动改动,应该先更新代码,再 up。
pulumi import:导入现有资源
pulumi import 将已有的云资源纳入 Pulumi 管理,而不需要销毁再重建。适合"将已有基础设施迁移到 Pulumi"的场景。
# 导入一个 AWS S3 Bucket(格式:resource_type resource_name cloud_id)
pulumi import aws:s3/bucketV2:BucketV2 my-bucket my-existing-bucket-name
# 导入 EC2 实例
pulumi import aws:ec2/instance:Instance web-server i-1234567890abcdef0
# 导入 RDS 实例
pulumi import aws:rds/instance:Instance prod-db my-database-identifier
# 导入 IAM Role
pulumi import aws:iam/role:Role my-role my-existing-role-name
# pulumi import 会输出对应的 Python/TypeScript 代码供参考
# 你需要将这段代码添加到你的程序中
# 批量导入(使用 import 文件,Pulumi v3.55+)
# 创建 import.json
# {
# "resources": [
# {"type": "aws:s3/bucketV2:BucketV2", "name": "logs-bucket", "id": "my-logs-bucket"},
# {"type": "aws:ec2/vpc:Vpc", "name": "main-vpc", "id": "vpc-0a1b2c3d4e5f"}
# ]
# }
pulumi import --file import.json
GitHub Actions CI/CD 集成
基本工作流:Push to main 自动部署
# .github/workflows/deploy.yml
name: Pulumi Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: |
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
- name: Pulumi up
uses: pulumi/actions@v5
with:
command: up
stack-name: myorg/my-infra/prod
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
PR Preview:预览基础设施变更
# .github/workflows/preview.yml — PR 时预览变更
name: Pulumi Preview
on:
pull_request:
branches: [main]
jobs:
preview:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # 需要写 PR 评论的权限
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: |
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
- name: Pulumi Preview
uses: pulumi/actions@v5
with:
command: preview
stack-name: myorg/my-infra/prod
comment-on-pr: true # 将 preview 结果评论到 PR
github-token: ${{ secrets.GITHUB_TOKEN }}
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
多环境部署流水线
# .github/workflows/multi-env.yml
name: Multi-Env Deploy
on:
push:
branches: [main]
jobs:
deploy-dev:
runs-on: ubuntu-latest
environment: dev
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install -r requirements.txt
- uses: pulumi/actions@v5
with:
command: up
stack-name: myorg/my-infra/dev
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
deploy-staging:
needs: deploy-dev # dev 成功后才部署 staging
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install -r requirements.txt
- uses: pulumi/actions@v5
with:
command: up
stack-name: myorg/my-infra/staging
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
deploy-prod:
needs: deploy-staging # 需要手动审批(在 GitHub environment 中配置)
runs-on: ubuntu-latest
environment: production # 配置了 required reviewers
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install -r requirements.txt
- uses: pulumi/actions@v5
with:
command: up
stack-name: myorg/my-infra/prod
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.PROD_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.PROD_AWS_SECRET_ACCESS_KEY }}
Secrets 加密方案
Pulumi Cloud(默认)
登录 Pulumi Cloud 后,secrets 由 Pulumi 托管的密钥加密(每个 Stack 独立密钥)。密文存储在 Pulumi.{stack}.yaml 中,可安全提交 Git。
passphrase
使用环境变量
PULUMI_CONFIG_PASSPHRASE 作为加密密钥。Self-Hosted 后端的标准选择,适合 CI/CD 环境。密钥必须在所有能运行 pulumi 的机器上一致。AWS KMS
pulumi stack init prod --secrets-provider="awskms://alias/pulumi-secrets"。使用 AWS KMS 密钥加密,权限由 IAM 控制,适合高安全要求场景。HashiCorp Vault
与企业级 Vault 集成:
--secrets-provider="vault://vault.example.com/v1/transit/keys/pulumi"。# CI/CD 中使用 passphrase 加密
# 1. 创建 Stack 时指定 passphrase provider
PULUMI_CONFIG_PASSPHRASE="super-secret-phrase" \
pulumi stack init prod --secrets-provider=passphrase
# 2. 设置 secret 配置
PULUMI_CONFIG_PASSPHRASE="super-secret-phrase" \
pulumi config set --secret dbPassword "my-db-password"
# 3. GitHub Actions 中设置为 Repository Secret
# PULUMI_CONFIG_PASSPHRASE: "super-secret-phrase"(在 GitHub Secrets 中)
# 4. CI 中运行 up
# env:
# PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }}
获取 PULUMI_ACCESS_TOKEN
在 Pulumi Cloud(app.pulumi.com)中,点击头像 → Settings → Access Tokens → Create Token,生成 Personal Access Token,然后添加到 GitHub Repository Secrets(名称:PULUMI_ACCESS_TOKEN)。每个 CI/CD 环境(dev/staging/prod)建议使用不同的 Token 以便审计追踪。
本章小结
本章核心要点
- State 是 Pulumi 的核心:记录已管理资源的快照;丢失 State = 失去对资源的管理能力(资源仍存在,但 Pulumi 不知道)。
- Pulumi Cloud 免费且推荐:不需要自建 S3+DynamoDB,内置 secrets 加密、Web UI 查看 State。
- pulumi refresh:发现并同步漂移,但 refresh 后应检查代码是否需要更新。
- pulumi import:将现有云资源纳入 Pulumi 管理,不需要重建,是"基础设施迁移到 IaC"的关键工具。
- PR Preview:
pulumi/actions@v5的comment-on-pr: true自动将 preview 结果评论到 PR,让 reviewer 知道这次 PR 会影响哪些基础设施。 - 多环境流水线:dev → staging → prod 串联部署,prod 配置 required_reviewers 实现人工审批。