pulumi-typescript

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Pulumi TypeScript Skill

Pulumi TypeScript 技能

Development Workflow

开发工作流

1. Project Setup

1. 项目搭建

bash
undefined
bash
undefined

Create 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
undefined
pulumi 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
undefined

2. Pulumi ESC Integration

2. Pulumi ESC 集成

Instead of using
pulumi config set
or stack config files, use Pulumi ESC for centralized secrets and configuration.
Link ESC environment to stack:
bash
undefined
替代
pulumi config set
或栈配置文件,使用Pulumi ESC集中管理密钥和配置。
将ESC环境关联到Pulumi栈:
bash
undefined

Create 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
undefined

Run 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
undefined
pulumi env open myorg/myproject-dev --format shell
undefined

5. 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 definition
PulumiPlugin.yaml:
yaml
runtime: nodejs
Component 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
undefined

Consume 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 declaration
pulumi 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
    pulumi preview
    before
    pulumi up
  • Use ESC environment versioning and tags for releases
  • Implement proper tagging strategy for all resources
  • 执行
    pulumi up
    前务必运行
    pulumi preview
  • 使用ESC环境版本控制和标签管理发布
  • 为所有资源实现规范的标签策略

Common Commands

常用命令

bash
undefined
bash
undefined

Environment 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
undefined
pulumi new typescript # 创建新项目 pulumi config env add <org>/<env> # 关联ESC环境 pulumi preview # 预览变更 pulumi up # 部署 pulumi stack output # 查看输出结果 pulumi destroy # 销毁资源
undefined

References

参考资料

  • 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最佳实践