跳转至

Pulumi 基础设施即代码

为什么要学

Pulumi 用通用编程语言(TypeScript/Python/Go/C#)定义基础设施,替代 Terraform 的 HCL:

  • 真正的编程语言:用 TypeScript/Python 而非 DSL,享受完整的语言能力
  • IDE 支持:自动补全、类型检查、重构
  • 逻辑表达力:循环、条件、函数、类——所有编程概念都能用
  • 测试友好:用 pytest/jest 测试基础设施代码
  • 多云支持:AWS/Azure/GCP/K8s/Docker 等全支持
  • 状态管理:Pulumi Cloud 或自托管 backend

如果你觉得 Terraform 的 HCL 太受限,Pulumi 是更强大的选择。

核心概念

PulumiTerraform对比说明
ProgramConfiguration基础设施代码
ResourceResource云资源
StackWorkspace环境(dev/prod)
OutputOutput资源的输出值
ProviderProvider云服务商驱动
StateState资源状态记录
ComponentResourceModule可复用资源组

安装配置

# 安装CLI
curl -fsSL https://get.pulumi.com | sh
# 或
brew install pulumi

# 创建项目
mkdir my-infra && cd my-infra
pulumi new aws-typescript  # 或 aws-python / azure-python 等

# 登录(状态管理)
pulumi login  # Pulumi Cloud(免费)
# 或本地: pulumi login --local

快速上手

TypeScript 示例(AWS)

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// 创建S3桶
const bucket = new aws.s3.Bucket("my-bucket", {
    website: {
        indexDocument: "index.html",
    },
});

// 上传文件
const indexHtml = new aws.s3.BucketObject("index", {
    bucket: bucket.id,
    source: new pulumi.asset.FileAsset("./www/index.html"),
    contentType: "text/html",
});

// 输出
export const bucketName = bucket.id;
export const websiteUrl = bucket.websiteEndpoint;

Python 示例

import pulumi
import pulumi_aws as aws

# 创建VPC
vpc = aws.ec2.Vpc("my-vpc", cidr_block="10.0.0.0/16")

# 创建子网
subnet = aws.ec2.Subnet("my-subnet",
    vpc_id=vpc.id,
    cidr_block="10.0.1.0/24",
    availability_zone="us-east-1a"
)

# 创建EC2实例
instance = aws.ec2.Instance("web-server",
    instance_type="t3.micro",
    ami="ami-0c55b159cbfafe1f0",
    subnet_id=subnet.id,
    tags={"Name": "WebServer"}
)

pulumi.export("public_ip", instance.public_ip)

部署

pulumi up        # 预览并部署
pulumi preview   # 只预览
pulumi destroy   # 销毁所有资源
pulumi stack ls  # 列出环境

进阶用法

组件资源(可复用模块)

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// 自定义组件
class StaticSite extends pulumi.ComponentResource {
    public readonly url: pulumi.Output<string>;

    constructor(name: string, args: { indexContent: string }, opts?: pulumi.ComponentResourceOptions) {
        super("custom:StaticSite", name, {}, opts);

        const bucket = new aws.s3.Bucket(`${name}-bucket`, {
            website: { indexDocument: "index.html" },
        }, { parent: this });

        new aws.s3.BucketObject(`${name}-index`, {
            bucket: bucket.id,
            content: args.indexContent,
            contentType: "text/html",
            key: "index.html",
        }, { parent: this });

        this.url = bucket.websiteEndpoint;
    }
}

// 使用
const site = new StaticSite("my-site", {
    indexContent: "<h1>Hello!</h1>"
});
export const siteUrl = site.url;

多环境管理

# 创建环境
pulumi stack init dev
pulumi stack init prod

# 切换环境
pulumi stack select dev

# 每个环境独立配置
pulumi config set aws:region us-east-1 --stack dev
pulumi config set aws:region eu-west-1 --stack prod

测试基础设施

# test_infra.py
import pulumi
import unittest

class MyMocks(pulumi.runtime.Mocks):
    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 instance

class TestInfra(unittest.TestCase):
    @pulumi.runtime.test
    def test_instance_type(self):
        def check(args):
            self.assertEqual(args[0], "t3.micro")
        return instance.instance_type.apply(lambda t: check([t]))

Kubernetes 部署

import * as k8s from "@pulumi/kubernetes";

const app = new k8s.apps.v1.Deployment("nginx", {
    spec: {
        replicas: 3,
        selector: { matchLabels: { app: "nginx" } },
        template: {
            metadata: { labels: { app: "nginx" } },
            spec: {
                containers: [{
                    name: "nginx",
                    image: "nginx:latest",
                    ports: [{ containerPort: 80 }],
                }],
            },
        },
    },
});

常见问题

Q1: vs Terraform?

方面PulumiTerraform
语言TS/Python/Go/C#HCL(DSL)
逻辑能力完整编程语言有限(count/for_each)
IDE支持完整(类型/补全)有限
测试原生测试框架terratest(较复杂)
社区增长中非常成熟
学习曲线低(如果会编程)需学HCL
状态Cloud/S3/自托管Cloud/S3/自托管

Q2: 可以导入现有 Terraform 代码吗?

# 支持从Terraform导入
pulumi convert --from terraform --language typescript

Q3: 免费吗?

  • Pulumi CLI 和 SDK 完全免费开源
  • Pulumi Cloud 有免费层(个人使用足够)
  • 状态可以存本地或自托管 S3

参考资源