Stack:环境隔离的核心机制
什么是 Stack?
在 Pulumi 中,Stack 是同一套代码的一个独立部署实例。一套 Pulumi 程序可以对应多个 Stack,每个 Stack 代表一个隔离的环境(dev/staging/prod)。每个 Stack 有:
- 独立的 State(不同环境的资源互不影响)
- 独立的 配置值(dev 用小机型,prod 用大机型)
- 独立的 输出值(不同环境的 URL、IP 不同)
同一套代码 → 多个 Stack
my-infra/
├── __main__.py ← 一套代码
├── Pulumi.yaml
├── Pulumi.dev.yaml ← dev Stack 配置
├── Pulumi.staging.yaml← staging Stack 配置
└── Pulumi.prod.yaml ← prod Stack 配置
Pulumi Cloud State:
├── org/my-infra/dev ← dev 的 State(独立)
├── org/my-infra/staging ← staging 的 State(独立)
└── org/my-infra/prod ← prod 的 State(独立)
Stack 管理命令
# 创建新 Stack
pulumi stack init dev
pulumi stack init staging
pulumi stack init prod
# 列出所有 Stack(* 号标注当前激活的 Stack)
pulumi stack ls
# NAME LAST UPDATE RESOURCE COUNT URL
# dev * 2h ago 12 https://app.pulumi.com/...
# staging 3d ago 12 https://app.pulumi.com/...
# prod 1w ago 12 https://app.pulumi.com/...
# 切换到 prod Stack
pulumi stack select prod
# 查看当前 Stack 信息
pulumi stack
# 查看当前 Stack 的所有输出值
pulumi stack output
# 导出 Stack State(备份或调试)
pulumi stack export > stack-backup.json
# 删除 Stack(必须先 destroy 所有资源)
pulumi stack rm dev
pulumi config:Stack 配置管理
设置与读取配置值
# 切换到 dev Stack,设置配置
pulumi stack select dev
pulumi config set environment dev
pulumi config set aws:region us-east-1
pulumi config set instanceType t3.micro # dev 用小机型
pulumi config set minNodes 1
# 切换到 prod,设置不同配置
pulumi stack select prod
pulumi config set environment prod
pulumi config set aws:region us-east-1
pulumi config set instanceType c5.xlarge # prod 用大机型
pulumi config set minNodes 3
# 查看当前 Stack 的所有配置
pulumi config
# KEY VALUE
# environment prod
# instanceType c5.xlarge
# minNodes 3
# 查看特定值
pulumi config get instanceType
加密的 Secret 配置
# 设置加密 Secret(值会被加密存储在 Pulumi.dev.yaml 中)
pulumi config set --secret dbPassword "sup3r-s3cret"
pulumi config set --secret awsSecretKey "EXAMPLEKEY"
# 查看 Pulumi.dev.yaml 中的 secret(已加密)
# config:
# myapp:dbPassword:
# secure: AAABADwAB...(AES-256 加密)
# 获取解密后的值(仅在有授权的机器上)
pulumi config get dbPassword # 输出明文
# 默认加密方式是 Pulumi Cloud 管理密钥
# 也可以使用 passphrase:
PULUMI_CONFIG_PASSPHRASE="my-passphrase" pulumi up
# 或使用 AWS KMS:
pulumi stack init prod --secrets-provider="awskms://alias/pulumi-secrets"
在代码中读取配置
import pulumi
import pulumi_aws as aws
# 读取当前 Stack 的配置
config = pulumi.Config()
# get:如果不存在返回 None
env = config.get("environment") or "dev"
# require:如果不存在则报错(强制要求)
instance_type = config.require("instanceType")
# get_int/get_float/get_bool:类型转换
min_nodes = config.get_int("minNodes") or 1
# require_secret:读取加密值(返回 Output[str])
db_password = config.require_secret("dbPassword")
# get_object:读取 JSON 对象配置
tags_config = config.get_object("tags") or {}
# 根据环境决定资源规格
is_prod = env == "prod"
db_instance = aws.rds.Instance(
"app-db",
instance_class="db.r5.large" if is_prod else "db.t3.micro",
multi_az=is_prod, # prod 开启多可用区
allocated_storage=100 if is_prod else 20,
username="admin",
password=db_password, # Output[str] Secret
skip_final_snapshot=not is_prod,
opts=pulumi.ResourceOptions(protect=is_prod), # 生产环境保护
)
Pulumi.dev.yaml 配置文件示例
# Pulumi.dev.yaml — dev Stack 配置
# 可以提交到 Git(secrets 已加密)
config:
aws:region: us-east-1
myapp:environment: dev
myapp:instanceType: t3.micro
myapp:minNodes: 1
myapp:dbPassword:
secure: AAABAKoRkU3JV...
Stack Reference:跨 Stack 引用输出
使用场景
Stack Reference 解决了"基础设施分层"的问题:将基础网络(VPC)、共享服务(数据库)和应用层部署放在不同的 Pulumi 项目中,通过 Stack Reference 引用底层 Stack 的输出值。
分层基础设施架构
┌─────────────────────────────────────────────┐
│ network-stack (pulumi/network/prod) │
│ 输出:vpcId, subnetIds, securityGroupId │
└─────────────────────┬───────────────────────┘
│ Stack Reference
┌─────────────────────▼───────────────────────┐
│ platform-stack (pulumi/platform/prod) │
│ 引用:vpcId → 创建 RDS、EKS │
│ 输出:dbEndpoint, clusterName │
└─────────────────────┬───────────────────────┘
│ Stack Reference
┌─────────────────────▼───────────────────────┐
│ app-stack (pulumi/apps/my-service/prod) │
│ 引用:dbEndpoint, clusterName → 部署应用 │
└─────────────────────────────────────────────┘
# app-stack 的 __main__.py
import pulumi
# 引用 network-stack 的输出
network_stack = pulumi.StackReference("myorg/network/prod")
# 格式:"{organization}/{project}/{stack}"
vpc_id = network_stack.get_output("vpcId")
subnet_ids = network_stack.get_output("privateSubnetIds")
# 引用 platform-stack 的输出
platform_stack = pulumi.StackReference("myorg/platform/prod")
db_endpoint = platform_stack.get_output("dbEndpoint")
# 使用跨 Stack 引用的值创建资源
import pulumi_aws as aws
import pulumi_kubernetes as k8s
# vpc_id 和 subnet_ids 是 Output[Any],可以直接用作资源属性
sg = aws.ec2.SecurityGroup(
"app-sg",
vpc_id=vpc_id, # Output 直接用
description="App security group",
)
实战:三环境配置管理
# __main__.py — 统一代码处理三个环境
import pulumi
import pulumi_aws as aws
config = pulumi.Config()
env = config.require("environment")
# 环境配置映射
ENV_CONFIG = {
"dev": {
"instance_type": "t3.micro",
"min_size": 1,
"max_size": 2,
"db_class": "db.t3.micro",
"deletion_protection": False,
},
"staging": {
"instance_type": "t3.small",
"min_size": 1,
"max_size": 3,
"db_class": "db.t3.small",
"deletion_protection": False,
},
"prod": {
"instance_type": "c5.xlarge",
"min_size": 3,
"max_size": 20,
"db_class": "db.r5.large",
"deletion_protection": True,
},
}
cfg = ENV_CONFIG[env]
is_prod = (env == "prod")
# 统一的资源创建代码,配置来自字典
vpc = aws.ec2.Vpc(
f"vpc-{env}",
cidr_block="10.0.0.0/16",
tags={"Environment": env, "ManagedBy": "Pulumi"},
)
# 生产环境创建 Multi-AZ RDS
db_password = config.require_secret("dbPassword")
db = aws.rds.Instance(
f"db-{env}",
instance_class=cfg["db_class"],
engine="postgres",
engine_version="15",
allocated_storage=100 if is_prod else 20,
multi_az=is_prod,
deletion_protection=cfg["deletion_protection"],
username="admin",
password=db_password,
skip_final_snapshot=not is_prod,
opts=pulumi.ResourceOptions(protect=is_prod),
)
pulumi.export("vpc_id", vpc.id)
pulumi.export("db_endpoint", db.address)
pulumi.export("environment", env)
# 三环境部署工作流
# Dev 环境
pulumi stack select dev
pulumi config set environment dev
pulumi config set --secret dbPassword "dev-password"
pulumi up
# Staging 环境(dev 测试通过后)
pulumi stack select staging
pulumi config set environment staging
pulumi config set --secret dbPassword "staging-password"
pulumi up
# Prod 环境(staging 验证通过后)
pulumi stack select prod
pulumi config set environment prod
pulumi config set --secret dbPassword "prod-super-secret"
pulumi preview # 先预览!
pulumi up
Stack 名称建议使用 org/project/stack 格式
Stack Reference 使用 "org/project/stack" 格式(如 "mycompany/network/prod")。建议在团队中统一 Stack 命名规范,并将 Stack 归属到组织(Organization)下而不是个人账号下,以方便团队协作和权限管理。
本章小结
本章核心要点
- Stack = 环境实例:同一套代码 × N个 Stack = N 个独立环境,每个 Stack 有独立的 State 和配置。
- config.require() 强制要求、config.get() 可选默认值,config.require_secret() 读取加密值返回 Output[str]。
- Secret 加密存储:
pulumi config set --secret将值加密后写入 Pulumi.{stack}.yaml,可以安全提交到 Git。 - Stack Reference:引用其他 Stack 的输出值,实现基础设施分层(网络层 → 平台层 → 应用层)而无需将所有资源放在一个巨大的 Stack 中。
- 环境配置字典:用 Python 字典映射环境名到配置值,避免大量 if/else 分支,代码更清晰。