跳转至

Pulumi IaC

一句话概述:Pulumi 是新一代基础设施即代码工具,用你熟悉的编程语言(Python/TypeScript/Go)而不是专用配置语言来定义云资源,有完整的 IDE 支持和测试能力。

核心知识点

概念白话解释
Stack栈 = 一套独立的基础设施实例(如 dev、staging、prod)
Project项目 = 一个 Pulumi 程序,包含基础设施代码
Resource资源 = 一个云资源(如 EC2、S3 桶)
Output输出 = 资源创建后的返回值(如 IP、URL)
State状态 = 记录当前基础设施的快照
Provider提供商 = 云平台的 SDK(AWS、Azure、GCP 等)
Config配置 = 每个 Stack 独立的参数设置
ComponentResource组件资源 = 自定义的可复用资源组合

安装配置

# === 安装 Pulumi ===
# macOS/Linux
curl -fsSL https://get.pulumi.com | sh  # 一键安装脚本

# macOS (Homebrew)
brew install pulumi  # Homebrew 安装

# 验证安装
pulumi version  # 查看版本

# === 配置后端 ===
# 方式1:Pulumi Cloud(默认,免费套餐够个人用)
pulumi login  # 登录 Pulumi Cloud

# 方式2:本地存储(不联网)
pulumi login --local  # 状态文件存本地

# 方式3:S3 后端
pulumi login s3://my-pulumi-state  # 状态存到 S3

# === 创建新项目 ===
mkdir my-infra && cd my-infra  # 创建项目目录
pulumi new aws-python  # 创建 AWS + Python 项目(交互式)
# 会问你:项目名、描述、Stack 名、AWS 区域

基本使用

1. 创建 S3 桶(Python)

# __main__.py
import pulumi  # 导入 Pulumi SDK
import pulumi_aws as aws  # 导入 AWS Provider

# 创建 S3 桶
bucket = aws.s3.Bucket(
    "my-bucket",  # 资源逻辑名
    bucket="my-bioinfo-data-2026",  # 桶的物理名(全球唯一)
    tags={"Environment": "dev", "Project": "bioinfo"},  # 标签
)

# 启用版本控制
versioning = aws.s3.BucketVersioningV2(
    "my-bucket-versioning",
    bucket=bucket.id,  # 引用上面创建的桶
    versioning_configuration=aws.s3.BucketVersioningV2VersioningConfigurationArgs(
        status="Enabled",  # 启用版本控制
    ),
)

# 导出桶名(在命令行可以看到)
pulumi.export("bucket_name", bucket.id)  # 输出桶名
pulumi.export("bucket_arn", bucket.arn)  # 输出桶的 ARN
# 执行流程
pulumi preview   # 预览变更(类似 terraform plan)
pulumi up        # 创建/更新资源(类似 terraform apply)
pulumi stack output bucket_name  # 查看输出值
pulumi destroy   # 销毁资源

2. 创建 EC2 + VPC

import pulumi
import pulumi_aws as aws

# 创建 VPC
vpc = aws.ec2.Vpc(
    "main-vpc",
    cidr_block="10.0.0.0/16",  # IP 地址范围
    enable_dns_hostnames=True,  # 启用 DNS
    tags={"Name": "main-vpc"},
)

# 创建子网
subnet = aws.ec2.Subnet(
    "public-subnet",
    vpc_id=vpc.id,  # 关联到 VPC
    cidr_block="10.0.1.0/24",  # 子网范围
    map_public_ip_on_launch=True,  # 自动分配公网 IP
    tags={"Name": "public-subnet"},
)

# 安全组(防火墙规则)
sg = aws.ec2.SecurityGroup(
    "web-sg",
    vpc_id=vpc.id,
    description="Allow HTTP and SSH",  # 允许 HTTP 和 SSH
    ingress=[
        {"protocol": "tcp", "from_port": 80, "to_port": 80, "cidr_blocks": ["0.0.0.0/0"]},  # HTTP
        {"protocol": "tcp", "from_port": 22, "to_port": 22, "cidr_blocks": ["0.0.0.0/0"]},  # SSH
    ],
    egress=[
        {"protocol": "-1", "from_port": 0, "to_port": 0, "cidr_blocks": ["0.0.0.0/0"]},  # 允许所有出站
    ],
)

# 查找最新的 Amazon Linux AMI
ami = aws.ec2.get_ami(
    most_recent=True,
    owners=["amazon"],
    filters=[{"name": "name", "values": ["amzn2-ami-hvm-*-x86_64-gp2"]}],  # Amazon Linux 2
)

# 创建 EC2 实例
server = aws.ec2.Instance(
    "web-server",
    instance_type="t3.micro",  # 实例类型
    ami=ami.id,  # 使用查到的 AMI
    subnet_id=subnet.id,  # 放在公有子网
    vpc_security_group_ids=[sg.id],  # 绑定安全组
    tags={"Name": "web-server"},
)

pulumi.export("public_ip", server.public_ip)  # 输出公网 IP

高级用法

1. 组件资源(可复用模块)

import pulumi
from pulumi import ComponentResource, ResourceOptions
import pulumi_aws as aws

class WebServer(ComponentResource):
    """自定义 Web 服务器组件(把多个资源打包成一个可复用的模块)"""

    def __init__(self, name: str, instance_type: str = "t3.micro",
                 opts: ResourceOptions = None):
        super().__init__("custom:WebServer", name, None, opts)

        # 安全组
        self.sg = aws.ec2.SecurityGroup(
            f"{name}-sg",
            ingress=[{"protocol": "tcp", "from_port": 80, "to_port": 80,
                       "cidr_blocks": ["0.0.0.0/0"]}],
            opts=ResourceOptions(parent=self),  # 设置父资源
        )

        # EC2 实例
        self.instance = aws.ec2.Instance(
            f"{name}-instance",
            instance_type=instance_type,
            ami="ami-xxx",
            vpc_security_group_ids=[self.sg.id],
            opts=ResourceOptions(parent=self),
        )

        self.register_outputs({"public_ip": self.instance.public_ip})

# 使用组件
web1 = WebServer("web1", instance_type="t3.small")
web2 = WebServer("web2", instance_type="t3.micro")

2. 多栈管理

pulumi stack init dev     # 创建 dev 栈
pulumi stack init prod    # 创建 prod 栈
pulumi stack select dev   # 切换到 dev
pulumi stack ls           # 列出所有栈

# 每个栈独立配置
pulumi config set aws:region us-east-1  # 设置当前栈的 AWS 区域
pulumi config set instanceType t3.micro  # 设置实例类型

3. 单元测试

# test_infra.py
import pulumi
import unittest

class MyMocks(pulumi.runtime.Mocks):
    """模拟 Pulumi 资源(不真的创建)"""
    def new_resource(self, args):
        return [args.name + "_id", args.inputs]
    def call(self, args):
        return {}

pulumi.runtime.set_mocks(MyMocks())

from my_infra import bucket  # 导入你的基础设施代码

class TestInfra(unittest.TestCase):
    @pulumi.runtime.test
    def test_bucket_tags(self):
        """测试 S3 桶有正确的标签"""
        def check_tags(tags):
            self.assertIn("Environment", tags)
        bucket.tags.apply(check_tags)

常见报错

报错信息原因解决方法
error: no Pulumi.yaml project file found不在 Pulumi 项目目录cd 到项目根目录
error: could not load pluginProvider 插件缺失pulumi plugin install
error: the current stack does not exist未选择 Stackpulumi stack select <name>
error: duplicate resource URN资源名重复给资源取不同的逻辑名
error: update failed资源创建失败查看详细错误,检查 AWS 权限

速查表

# === 核心命令 ===
pulumi new <template>    # 创建新项目
pulumi preview           # 预览变更
pulumi up                # 执行变更
pulumi destroy           # 销毁资源
pulumi stack ls          # 列出栈
pulumi stack select <n>  # 切换栈
pulumi stack output      # 查看输出
pulumi config set k v    # 设置配置
pulumi refresh           # 刷新状态
pulumi import <type> <name> <id>  # 导入已有资源
pulumi logs              # 查看日志

# === Pulumi vs Terraform 对比 ===
# Terraform: HCL 专用语言,学一门新语言
# Pulumi:    Python/TS/Go/Java,用你已经会的语言
# Terraform: plan → apply
# Pulumi:    preview → up
# Terraform: module 复用
# Pulumi:    class/function 复用(原生编程能力)
# Terraform: 社区更大、资料更多
# Pulumi:    IDE 支持更好、可写单元测试

参考:Pulumi 文档 | 更新于 2026 年