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. 01TypeScriptテンプレートでインフラプロジェクトを開始
  2. 02ESCでスタック設定と認証情報を管理
  3. 03Pulumiの複数言語で再利用可能なコンポーネントを共有
  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 config set やスタック設定ファイルを使う代わりに、シークレットと設定を一元管理するために Pulumi ESC を使用します。

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

Output の操作:

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. マルチ言語コンポーネント

任意の Pulumi 言語(Python、Go、C#、Java、YAML)から利用できるコンポーネントを TypeScript で作成します。

マルチ言語コンポーネントのプロジェクト構成:

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. Output を確認する

デプロイが成功したら、Output を確認します。

pulumi stack output

Output を期待値(バケット名、エンドポイント URL、リソース ID など)と比較します。

エラーからの復旧

pulumi up がデプロイの途中で失敗した場合:

  1. エラーメッセージで、失敗した特定のリソースを確認する
  2. リソースの設定と ESC 環境の値を確認する
  3. 根本的な問題(IAM 権限や無効な設定など)を修正する
  4. pulumi up を再度実行する — Pulumi は中断した箇所から再開します
  5. スタックの状態に一貫性がない場合は、pulumi refresh を使用して、実際のクラウドリソースと状態を同期する

ベストプラクティス

セキュリティ
  • すべてのシークレットに Pulumi ESC を使用し、スタック設定ファイルにシークレットをコミットしない
  • 静的な認証情報ではなく、OIDC 認証を有効にする
  • 可能な場合は、有効期間の短い動的シークレットを使用する
  • 最小権限の 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

参考資料

コメント