pulumi-typescript
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePulumi TypeScript Skill
Pulumi TypeScript 技能
Development Workflow
开发工作流
1. Project Setup
1. 项目搭建
bash
undefinedbash
undefinedCreate new TypeScript project
创建新的TypeScript项目
pulumi new typescript
pulumi new typescript
Or with a cloud-specific template
或者使用云服务商特定模板
pulumi new aws-typescript
pulumi new azure-typescript
pulumi new gcp-typescript
**Project structure:**my-project/
├── Pulumi.yaml
├── Pulumi.dev.yaml # Stack config (use ESC instead)
├── package.json
├── tsconfig.json
└── index.ts
undefinedpulumi new aws-typescript
pulumi new azure-typescript
pulumi new gcp-typescript
**项目结构:**my-project/
├── Pulumi.yaml
├── Pulumi.dev.yaml # 栈配置(建议使用ESC替代)
├── package.json
├── tsconfig.json
└── index.ts
undefined2. Pulumi ESC Integration
2. Pulumi ESC 集成
Instead of using or stack config files, use Pulumi ESC for centralized secrets and configuration.
pulumi config setLink ESC environment to stack:
bash
undefined替代或栈配置文件,使用Pulumi ESC集中管理密钥和配置。
pulumi config set将ESC环境关联到Pulumi栈:
bash
undefinedCreate ESC environment
创建ESC环境
pulumi env init myorg/myproject-dev
pulumi env init myorg/myproject-dev
Edit environment
编辑环境
pulumi env edit myorg/myproject-dev
pulumi env edit myorg/myproject-dev
Link to Pulumi stack
关联到Pulumi栈
pulumi config env add myorg/myproject-dev
**ESC environment definition (YAML):**
```yaml
values:
# Static configuration
pulumiConfig:
aws:region: us-west-2
myapp:instanceType: t3.medium
# Dynamic OIDC credentials for AWS
aws:
login:
fn::open::aws-login:
oidc:
roleArn: arn:aws:iam::123456789:role/pulumi-oidc
sessionName: pulumi-deploy
# Pull secrets from AWS Secrets Manager
secrets:
fn::open::aws-secrets:
region: us-west-2
login: ${aws.login}
get:
dbPassword:
secretId: prod/database/password
# Expose to environment variables
environmentVariables:
AWS_ACCESS_KEY_ID: ${aws.login.accessKeyId}
AWS_SECRET_ACCESS_KEY: ${aws.login.secretAccessKey}
AWS_SESSION_TOKEN: ${aws.login.sessionToken}pulumi config env add myorg/myproject-dev
**ESC环境定义(YAML):**
```yaml
values:
# 静态配置
pulumiConfig:
aws:region: us-west-2
myapp:instanceType: t3.medium
# 用于AWS的动态OIDC凭证
aws:
login:
fn::open::aws-login:
oidc:
roleArn: arn:aws:iam::123456789:role/pulumi-oidc
sessionName: pulumi-deploy
# 从AWS Secrets Manager拉取密钥
secrets:
fn::open::aws-secrets:
region: us-west-2
login: ${aws.login}
get:
dbPassword:
secretId: prod/database/password
# 暴露为环境变量
environmentVariables:
AWS_ACCESS_KEY_ID: ${aws.login.accessKeyId}
AWS_SECRET_ACCESS_KEY: ${aws.login.secretAccessKey}
AWS_SESSION_TOKEN: ${aws.login.sessionToken}3. TypeScript Patterns
3. TypeScript 模式
Basic resource creation:
typescript
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// Get configuration from ESC
const config = new pulumi.Config();
const instanceType = config.require("instanceType");
// Create resources with proper tagging
const bucket = new aws.s3.Bucket("my-bucket", {
versioning: { enabled: true },
serverSideEncryptionConfiguration: {
rule: {
applyServerSideEncryptionByDefault: {
sseAlgorithm: "AES256",
},
},
},
tags: {
Environment: pulumi.getStack(),
ManagedBy: "Pulumi",
},
});
// Export outputs
export const bucketName = bucket.id;
export const bucketArn = bucket.arn;Component resources for reusability:
typescript
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
interface WebServiceArgs {
port: pulumi.Input<number>;
imageUri: pulumi.Input<string>;
}
class WebService extends pulumi.ComponentResource {
public readonly url: pulumi.Output<string>;
constructor(name: string, args: WebServiceArgs, opts?: pulumi.ComponentResourceOptions) {
super("custom:app:WebService", name, {}, opts);
// Create child resources with { parent: this }
const lb = new aws.lb.LoadBalancer(`${name}-lb`, {
loadBalancerType: "application",
// ... configuration
}, { parent: this });
this.url = lb.dnsName;
this.registerOutputs({ url: this.url });
}
}Stack references for cross-stack dependencies:
typescript
import * as pulumi from "@pulumi/pulumi";
// Reference outputs from networking stack
const networkingStack = new pulumi.StackReference("myorg/networking/prod");
const vpcId = networkingStack.getOutput("vpcId");
const subnetIds = networkingStack.getOutput("privateSubnetIds");Working with Outputs:
typescript
import * as pulumi from "@pulumi/pulumi";
// Use apply for transformations
const uppercaseName = bucket.id.apply(id => id.toUpperCase());
// Use pulumi.all for multiple outputs
const combined = pulumi.all([bucket.id, bucket.arn]).apply(
([id, arn]) => `Bucket ${id} has ARN ${arn}`
);
// Conditional resources
const isProd = pulumi.getStack() === "prod";
const monitoring = isProd ? new aws.cloudwatch.MetricAlarm("alarm", {
// ... configuration
}) : undefined;基础资源创建:
typescript
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// 从ESC获取配置
const config = new pulumi.Config();
const instanceType = config.require("instanceType");
// 创建带正确标签的资源
const bucket = new aws.s3.Bucket("my-bucket", {
versioning: { enabled: true },
serverSideEncryptionConfiguration: {
rule: {
applyServerSideEncryptionByDefault: {
sseAlgorithm: "AES256",
},
},
},
tags: {
Environment: pulumi.getStack(),
ManagedBy: "Pulumi",
},
});
// 导出输出结果
export const bucketName = bucket.id;
export const bucketArn = bucket.arn;用于复用的组件资源:
typescript
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
interface WebServiceArgs {
port: pulumi.Input<number>;
imageUri: pulumi.Input<string>;
}
class WebService extends pulumi.ComponentResource {
public readonly url: pulumi.Output<string>;
constructor(name: string, args: WebServiceArgs, opts?: pulumi.ComponentResourceOptions) {
super("custom:app:WebService", name, {}, opts);
// 创建子资源并指定{ parent: this }
const lb = new aws.lb.LoadBalancer(`${name}-lb`, {
loadBalancerType: "application",
// ... 配置内容
}, { parent: this });
this.url = lb.dnsName;
this.registerOutputs({ url: this.url });
}
}跨栈依赖的栈引用:
typescript
import * as pulumi from "@pulumi/pulumi";
// 引用网络栈的输出结果
const networkingStack = new pulumi.StackReference("myorg/networking/prod");
const vpcId = networkingStack.getOutput("vpcId");
const subnetIds = networkingStack.getOutput("privateSubnetIds");处理输出结果:
typescript
import * as pulumi from "@pulumi/pulumi";
// 使用apply进行转换
const uppercaseName = bucket.id.apply(id => id.toUpperCase());
// 使用pulumi.all处理多个输出结果
const combined = pulumi.all([bucket.id, bucket.arn]).apply(
([id, arn]) => `存储桶 ${id} 的ARN为 ${arn}`
);
// 条件化资源
const isProd = pulumi.getStack() === "prod";
const monitoring = isProd ? new aws.cloudwatch.MetricAlarm("alarm", {
// ... 配置内容
}) : undefined;4. Using ESC with pulumi env run
4. 结合 pulumi env run 使用ESC
Run any command with ESC environment variables injected:
bash
undefined注入ESC环境变量运行任意命令:
bash
undefinedRun pulumi commands with ESC credentials
使用ESC凭证运行pulumi命令
pulumi env run myorg/aws-dev -- pulumi up
pulumi env run myorg/aws-dev -- pulumi up
Run tests with secrets
使用密钥运行测试
pulumi env run myorg/test-env -- npm test
pulumi env run myorg/test-env -- npm test
Open environment and export to shell
打开环境并导出到Shell
pulumi env open myorg/myproject-dev --format shell
undefinedpulumi env open myorg/myproject-dev --format shell
undefined5. Async Patterns
5. 异步模式
typescript
// Export async function for top-level await
export = async () => {
const data = await fetchExternalData();
const resource = new aws.s3.Bucket("bucket", {
tags: { data: data.value },
});
return {
bucketName: resource.id,
};
};typescript
// 导出异步函数以支持顶层await
export = async () => {
const data = await fetchExternalData();
const resource = new aws.s3.Bucket("bucket", {
tags: { data: data.value },
});
return {
bucketName: resource.id,
};
};6. Multi-Language Components
6. 多语言组件
Create components in TypeScript that can be consumed from any Pulumi language (Python, Go, C#, Java, YAML).
Project structure for multi-language component:
my-component/
├── PulumiPlugin.yaml # Required for multi-language
├── package.json
├── tsconfig.json
└── index.ts # Component definitionPulumiPlugin.yaml:
yaml
runtime: nodejsComponent with proper Args interface:
typescript
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// Args interface - use Input types for all properties
export interface SecureBucketArgs {
// Wrap all scalar members in Input types
bucketName: pulumi.Input<string>;
enableVersioning?: pulumi.Input<boolean>;
tags?: pulumi.Input<Record<string, pulumi.Input<string>>>;
}
export class SecureBucket extends pulumi.ComponentResource {
public readonly bucketId: pulumi.Output<string>;
public readonly bucketArn: pulumi.Output<string>;
// Constructor must have 'args' parameter with type annotation
constructor(name: string, args: SecureBucketArgs, opts?: pulumi.ComponentResourceOptions) {
super("myorg:storage:SecureBucket", name, {}, opts);
const bucket = new aws.s3.Bucket(`${name}-bucket`, {
bucket: args.bucketName,
versioning: { enabled: args.enableVersioning ?? true },
serverSideEncryptionConfiguration: {
rule: {
applyServerSideEncryptionByDefault: {
sseAlgorithm: "AES256",
},
},
},
tags: args.tags,
}, { parent: this });
this.bucketId = bucket.id;
this.bucketArn = bucket.arn;
this.registerOutputs({
bucketId: this.bucketId,
bucketArn: this.bucketArn,
});
}
}Publishing for multi-language consumption:
bash
undefined创建可被任意Pulumi语言(Python、Go、C#、Java、YAML)调用的TypeScript组件。
多语言组件的项目结构:
my-component/
├── PulumiPlugin.yaml # 多语言支持必需文件
├── package.json
├── tsconfig.json
└── index.ts # 组件定义PulumiPlugin.yaml:
yaml
runtime: nodejs带Args接口的组件:
typescript
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// Args接口 - 所有属性使用Input类型
export interface SecureBucketArgs {
// 所有标量成员使用Input类型包装
bucketName: pulumi.Input<string>;
enableVersioning?: pulumi.Input<boolean>;
tags?: pulumi.Input<Record<string, pulumi.Input<string>>>;
}
export class SecureBucket extends pulumi.ComponentResource {
public readonly bucketId: pulumi.Output<string>;
public readonly bucketArn: pulumi.Output<string>;
// 构造函数必须带类型声明的'args'参数
constructor(name: string, args: SecureBucketArgs, opts?: pulumi.ComponentResourceOptions) {
super("myorg:storage:SecureBucket", name, {}, opts);
const bucket = new aws.s3.Bucket(`${name}-bucket`, {
bucket: args.bucketName,
versioning: { enabled: args.enableVersioning ?? true },
serverSideEncryptionConfiguration: {
rule: {
applyServerSideEncryptionByDefault: {
sseAlgorithm: "AES256",
},
},
},
tags: args.tags,
}, { parent: this });
this.bucketId = bucket.id;
this.bucketArn = bucket.arn;
this.registerOutputs({
bucketId: this.bucketId,
bucketArn: this.bucketArn,
});
}
}发布以支持多语言调用:
bash
undefinedConsume from git repository
从Git仓库引入
pulumi package add github.com/myorg/my-component
pulumi package add github.com/myorg/my-component
With version tag
指定版本标签
pulumi package add github.com/myorg/my-component@v1.0.0
pulumi package add github.com/myorg/my-component@v1.0.0
Local development
本地开发使用
pulumi package add /path/to/local/my-component
**Multi-language Args requirements:**
- Use `pulumi.Input<T>` for all scalar properties
- Avoid union types (`string | number`) - not supported
- Avoid functions/callbacks - not serializable
- Constructor must have `args` parameter with type declarationpulumi package add /path/to/local/my-component
**多语言Args要求:**
- 所有标量属性使用`pulumi.Input<T>`
- 避免联合类型(`string | number`)- 不被支持
- 避免函数/回调 - 无法序列化
- 构造函数必须带类型声明的`args`参数Best Practices
最佳实践
Security
安全
- Use Pulumi ESC for all secrets - never commit secrets to stack config files
- Enable OIDC authentication instead of static credentials
- Use dynamic secrets with short TTLs when possible
- Apply least-privilege IAM policies
- 使用Pulumi ESC管理所有密钥 - 绝不要将密钥提交到栈配置文件
- 启用OIDC认证替代静态凭证
- 尽可能使用带短TTL的动态密钥
- 应用最小权限IAM策略
Code Organization
代码组织
- Use ComponentResources for reusable infrastructure patterns
- Leverage TypeScript's type system for configuration validation
- Keep stack-specific config in ESC environments
- Use stack references for cross-stack dependencies
- 使用ComponentResources实现可复用的基础设施模式
- 利用TypeScript的类型系统进行配置校验
- 将栈特定配置存储在ESC环境中
- 使用栈引用处理跨栈依赖
Deployment
部署
- Always run before
pulumi previewpulumi up - Use ESC environment versioning and tags for releases
- Implement proper tagging strategy for all resources
- 执行前务必运行
pulumi uppulumi preview - 使用ESC环境版本控制和标签管理发布
- 为所有资源实现规范的标签策略
Common Commands
常用命令
bash
undefinedbash
undefinedEnvironment Commands (pulumi env)
环境命令(pulumi env)
pulumi env init <org>/<project>/<env> # Create environment
pulumi env edit <org>/<env> # Edit environment
pulumi env open <org>/<env> # View resolved values
pulumi env run <org>/<env> -- <command> # Run with env vars
pulumi env version tag <org>/<env> <tag> # Tag version
pulumi env init <org>/<project>/<env> # 创建环境
pulumi env edit <org>/<env> # 编辑环境
pulumi env open <org>/<env> # 查看解析后的值
pulumi env run <org>/<env> -- <command> # 注入环境变量运行命令
pulumi env version tag <org>/<env> <tag> # 为版本打标签
Pulumi Commands
Pulumi 命令
pulumi new typescript # New project
pulumi config env add <org>/<env> # Link ESC environment
pulumi preview # Preview changes
pulumi up # Deploy
pulumi stack output # View outputs
pulumi destroy # Tear down
undefinedpulumi new typescript # 创建新项目
pulumi config env add <org>/<env> # 关联ESC环境
pulumi preview # 预览变更
pulumi up # 部署
pulumi stack output # 查看输出结果
pulumi destroy # 销毁资源
undefinedReferences
参考资料
- references/pulumi-esc.md - ESC patterns and commands
- references/pulumi-patterns.md - Common infrastructure patterns
- references/pulumi-typescript.md - TypeScript-specific guidance
- references/pulumi-best-practices-aws.md - AWS best practices
- references/pulumi-best-practices-azure.md - Azure best practices
- references/pulumi-best-practices-gcp.md - GCP best practices
- references/pulumi-esc.md - ESC模式与命令
- references/pulumi-patterns.md - 常见基础设施模式
- references/pulumi-typescript.md - TypeScript专属指南
- references/pulumi-best-practices-aws.md - AWS最佳实践
- references/pulumi-best-practices-azure.md - Azure最佳实践
- references/pulumi-best-practices-gcp.md - GCP最佳实践