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 是更强大的选择。
核心概念¶
| Pulumi | Terraform对比 | 说明 |
|---|---|---|
| Program | Configuration | 基础设施代码 |
| Resource | Resource | 云资源 |
| Stack | Workspace | 环境(dev/prod) |
| Output | Output | 资源的输出值 |
| Provider | Provider | 云服务商驱动 |
| State | State | 资源状态记录 |
| ComponentResource | Module | 可复用资源组 |
安装配置¶
# 安装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)
部署¶
进阶用法¶
组件资源(可复用模块)¶
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?¶
| 方面 | Pulumi | Terraform |
|---|---|---|
| 语言 | TS/Python/Go/C# | HCL(DSL) |
| 逻辑能力 | 完整编程语言 | 有限(count/for_each) |
| IDE支持 | 完整(类型/补全) | 有限 |
| 测试 | 原生测试框架 | terratest(较复杂) |
| 社区 | 增长中 | 非常成熟 |
| 学习曲线 | 低(如果会编程) | 需学HCL |
| 状态 | Cloud/S3/自托管 | Cloud/S3/自托管 |
Q2: 可以导入现有 Terraform 代码吗?¶
Q3: 免费吗?¶
- Pulumi CLI 和 SDK 完全免费开源
- Pulumi Cloud 有免费层(个人使用足够)
- 状态可以存本地或自托管 S3
参考资源¶
- Pulumi 官网 - 官方网站
- Pulumi 文档 - 完整文档
- Pulumi GitHub - 源代码
- Pulumi Examples - 示例项目
- Pulumi Registry - Provider列表