mcpField
P
pulumi-typescript

pulumi-typescript

github.com/dirien云与 DevOps13326 次安装今天更新
代码仓库

关于 pulumi-typescript

用于以 TypeScript 编写和部署 Pulumi 基础设施项目的技能,涵盖 Pulumi ESC 配置与密钥、可复用组件、堆栈引用,以及先预览和验证再部署的工作流。

主要功能

  1. 01TypeScript 项目设置与模式
  2. 02Pulumi ESC 配置和密钥
  3. 03可复用及多语言组件
  4. 04堆栈引用与输出处理
  5. 05预览、验证和部署工作流

适用场景

  1. 01使用 TypeScript 模板启动基础设施项目
  2. 02通过 ESC 管理堆栈配置和凭据
  3. 03在不同 Pulumi 语言间共享可复用组件
  4. 04部署前审查基础设施变更

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dirien/claude-skills --skill pulumi-typescript

安装后在 Claude Code 中输入/pulumi-typescript确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
pulumi-best-practices-aws.md
pulumi-best-practices-azure.md
pulumi-best-practices-gcp.md
pulumi-esc.md
pulumi-patterns.md
pulumi-typescript.md

详细介绍

Pulumi TypeScript 技能

开发工作流

1. 项目设置
# Create new TypeScript project
pulumi new typescript

# Or with a cloud-specific template
pulumi new aws-typescript
pulumi new azure-typescript
pulumi new gcp-typescript

项目结构:

my-project/
├── Pulumi.yaml
├── Pulumi.dev.yaml      # Stack config (use ESC instead)
├── package.json
├── tsconfig.json
└── index.ts
2. Pulumi ESC 集成

请使用 Pulumi ESC 集中管理密钥和配置,而不是使用 pulumi config set 或堆栈配置文件。

将 ESC 环境关联到堆栈:

# Create ESC environment
pulumi env init myorg/myproject-dev

# Edit environment
pulumi env edit myorg/myproject-dev

# Link to Pulumi stack
pulumi config env add myorg/myproject-dev

ESC 环境定义(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}
3. 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;

使用组件资源实现复用:

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 });
    }
}

使用堆栈引用处理跨堆栈依赖:

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");

使用 Outputs:

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;
4. 使用 pulumi env run 配合 ESC

运行任何命令,并注入 ESC 环境变量:

# Run pulumi commands with ESC credentials
pulumi env run myorg/aws-dev -- pulumi up

# Run tests with secrets
pulumi env run myorg/test-env -- npm test

# Open environment and export to shell
pulumi env open myorg/myproject-dev --format shell
5. 异步模式
// 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,
    };
};
6. 多语言组件

使用 TypeScript 创建可供任何 Pulumi 语言(Python、Go、C#、Java、YAML)使用的组件。

多语言组件的项目结构:

my-component/
├── PulumiPlugin.yaml      # Required for multi-language
├── package.json
├── tsconfig.json
└── index.ts               # Component definition

PulumiPlugin.yaml:

runtime: nodejs

使用恰当 Args 接口的组件:

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,
        });
    }
}

发布以供多语言使用:

# Consume from git repository
pulumi package add github.com/myorg/my-component

# With version tag
pulumi package add github.com/myorg/[email protected]

# Local development
pulumi package add /path/to/local/my-component

多语言 Args 要求:

  • 所有标量属性都使用 pulumi.Input<T>
  • 避免使用联合类型(string | number)——不受支持
  • 避免使用函数/回调——无法序列化
  • 构造函数必须具有带类型声明的 args 参数

带验证的部署工作流

请遵循此经过验证的工作流,确保安全部署:

1. 预览变更
pulumi preview

查看输出,了解将创建、修改或删除哪些资源。

2. 验证变更

检查预览输出,确认:

  • 是否存在意外的资源删除或修改
  • 资源的数量和类型是否正确
  • 配置值(区域、实例类型、标签等)是否正确

如果变更看起来不正确,请在继续之前调查根本原因:

# Check current stack state
pulumi stack output

# Review ESC environment values
pulumi env open myorg/myproject-dev

# Verify configuration
pulumi config
3. 部署

验证无误后,部署变更:

pulumi up
4. 验证输出

部署成功后,确认输出:

pulumi stack output

将输出与预期值(例如存储桶名称、端点 URL、资源 ID)进行比较。

错误恢复

如果 pulumi up 在部署过程中失败:

  1. 检查错误消息,找出失败的具体资源
  2. 检查资源配置和 ESC 环境值
  3. 修复根本问题(例如 IAM 权限、无效配置)
  4. 再次运行 pulumi up——Pulumi 会从中断处继续
  5. 如果堆栈状态不一致,请使用 pulumi refresh 将状态与实际云资源同步

最佳实践

安全性
  • 所有密钥都使用 Pulumi ESC——切勿将密钥提交到堆栈配置文件
  • 启用 OIDC 身份验证,而不是使用静态凭据
  • 尽可能使用 TTL 较短的动态密钥
  • 应用最小权限 IAM 策略
  • 始终为 S3 存储桶启用服务器端加密(AES256 或 KMS)——这是必须遵守的默认要求
  • 除非明确需要,否则阻止对 S3 存储桶的公开访问
  • 为存储资源启用版本控制,以保护数据
代码组织
  • 使用 ComponentResources 构建可复用的基础设施模式
  • 利用 TypeScript 类型系统验证配置
  • 将特定于堆栈的配置保存在 ESC 环境中
  • 使用堆栈引用处理跨堆栈依赖
部署
  • 在运行 pulumi up 之前,始终运行 pulumi preview
  • 使用 ESC 环境版本控制和标签进行发布
  • 为所有资源实施恰当的标签策略

常用命令

# Environment Commands (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 Commands
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
pulumi refresh                         # Sync state with cloud

参考资料

评论

支持 Markdown