pulumi-automation-api について
pulumi-automation-api は、Pulumi Automation API をコードから利用してインフラ操作を行うスキルです。デプロイのオーケストレーション、自助型プラットフォーム、インフラを構築するアプリ向けに、複数 Stack の管理パターンを紹介します。
主な機能
- 01Pulumi 操作のプログラム制御
- 02複数 Stack の順次・並列実行
- 03ローカルまたはインラインのプログラムソース
- 04設定のプログラム適用と出力取得
- 05デプロイエラーの処理
活用シーン
- 01依存関係のあるインフラ Stack の調整
- 02セルフサービス型プロビジョニングツールの構築
- 03アプリへのインフラ構築機能の組み込み
- 04Bash や Makefile のデプロイスクリプトの置き換え
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ pulumi/ agent-skills --skill pulumi-automation-apiインストール後、Claude Code で/pulumi-automation-apiを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yamluse_cases.yaml
詳細
Pulumi Automation API
このスキルを使う場面
次のような場合にこのスキルを呼び出します。
- 複数の Pulumi スタックにまたがるデプロイをオーケストレーションする
- カスタムアプリケーションに Pulumi の操作を組み込む
- セルフサービス型のインフラストラクチャプラットフォームを構築する
- 壊れやすい Bash/Makefile のオーケストレーションスクリプトを置き換える
- インフラストラクチャ管理用のカスタム CLI を作成する
- インフラストラクチャをプロビジョニングする Web アプリケーションを構築する
Automation API とは
Automation API を使うと、Pulumi の操作をプログラムから実行できます。CLI から pulumi up を実行する代わりに、同じ操作を行う関数をコード内で呼び出します。
import * as automation from "@pulumi/pulumi/automation";
// Create or select a stack
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
projectName: "my-project",
program: async () => {
// Your Pulumi program here
},
});
// Run pulumi up programmatically
const upResult = await stack.up({ onOutput: console.log });
console.log(`Update summary: ${JSON.stringify(upResult.summary)}`);
Automation API を使う場面
適したユースケース
複数スタックのオーケストレーション:
インフラストラクチャを複数の目的別プロジェクトに分割する場合、Automation API を使うと、スタック間の操作をオーケストレーションして、増加した複雑さを軽減できます。
infrastructure → platform → application
↓ ↓ ↓
(VPC) (Kubernetes) (Services)
Automation API を使えば、手動で介入しなくても、適切な順序で処理できます。
セルフサービス型プラットフォーム:
開発者が Pulumi を学ばなくてもインフラストラクチャをリクエストできる社内ツールを構築します。
- 環境をプロビジョニングする Web ポータル
- リソースを作成・削除する Slack ボット
- 組織に合わせてカスタマイズした CLI
インフラストラクチャの組み込み:
独自のインフラストラクチャをプロビジョニングするアプリケーションです。
- テナントごとにリソースを作成する SaaS プラットフォーム
- テスト環境を起動するテストフレームワーク
- 動的なインフラストラクチャを必要とする CI/CD システム
壊れやすいスクリプトの置き換え:
複数の pulumi コマンドをつなぎ合わせる Bash スクリプトや Makefile を使用している場合、Automation API を使うと次の機能を利用できます。
- 適切なエラー処理
- 型安全性
- 出力へのプログラムからのアクセス
使わないほうがよい場合
- 標準的なデプロイ要件を持つ単一のプロジェクトの場合
- 操作をプログラムから制御する必要がない場合
アーキテクチャの選択肢
ローカルソースとインラインソース
ローカルソース — Pulumi プログラムを別ファイルに配置します。
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
workDir: "./infrastructure", // Points to existing Pulumi project
});
使用する場面:
- オーケストレーターと Pulumi プログラムを別々のチームが保守する場合
- Pulumi プログラムがすでに存在する場合
- バージョン管理とリリースサイクルを独立させたい場合
- プラットフォームチームがアプリケーションチームのインフラストラクチャをオーケストレーションする場合
インラインソース — Pulumi プログラムをオーケストレーターに埋め込みます。
import * as aws from "@pulumi/aws";
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
projectName: "my-project",
program: async () => {
const bucket = new aws.s3.Bucket("my-bucket");
return { bucketName: bucket.id };
},
});
使用する場面:
- すべてを単一のチームが所有する場合
- オーケストレーションとインフラストラクチャを緊密に結合したい場合
- コンパイル済みバイナリとして配布する場合(ソースファイルは不要)
- デプロイ成果物をよりシンプルにしたい場合
言語の独立性
Automation API のプログラムでは、オーケストレーションする Pulumi プログラムとは異なる言語を使用できます。
Orchestrator (Go) → manages → Pulumi Program (TypeScript)
これにより、プラットフォームチームは好みの言語を使い、アプリケーションチームはそれぞれの言語を使うことができます。
よくあるパターン
複数スタックのオーケストレーション
依存関係の順序に従って複数のスタックをデプロイします。
import * as automation from "@pulumi/pulumi/automation";
async function deploy() {
const stacks = [
{ name: "infrastructure", dir: "./infra" },
{ name: "platform", dir: "./platform" },
{ name: "application", dir: "./app" },
];
for (const stackInfo of stacks) {
console.log(`Deploying ${stackInfo.name}...`);
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "prod",
workDir: stackInfo.dir,
});
await stack.up({ onOutput: console.log });
console.log(`${stackInfo.name} deployed successfully`);
}
}
async function destroy() {
// Destroy in reverse order
const stacks = [
{ name: "application", dir: "./app" },
{ name: "platform", dir: "./platform" },
{ name: "infrastructure", dir: "./infra" },
];
for (const stackInfo of stacks) {
console.log(`Destroying ${stackInfo.name}...`);
const stack = await automation.LocalWorkspace.selectStack({
stackName: "prod",
workDir: stackInfo.dir,
});
await stack.destroy({ onOutput: console.log });
}
}
設定の受け渡し
スタックの設定をプログラムから指定します。
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
workDir: "./infrastructure",
});
// Set configuration values
await stack.setConfig("aws:region", { value: "us-west-2" });
await stack.setConfig("dbPassword", { value: "secret", secret: true });
// Then deploy
await stack.up();
出力の読み取り
デプロイ後にスタックの出力へアクセスします。
const upResult = await stack.up();
// Get all outputs
const outputs = await stack.outputs();
console.log(`VPC ID: ${outputs["vpcId"].value}`);
// Or from the up result
console.log(`Outputs: ${JSON.stringify(upResult.outputs)}`);
エラー処理
デプロイの失敗を適切に処理します。
try {
const result = await stack.up({ onOutput: console.log });
if (result.summary.result === "failed") {
console.error("Deployment failed");
process.exit(1);
}
} catch (error) {
console.error(`Deployment error: ${error}`);
throw error;
}
スタック操作の並列実行
スタック間に依存関係がない場合は、並列でデプロイします。
const independentStacks = [
{ name: "service-a", dir: "./service-a" },
{ name: "service-b", dir: "./service-b" },
{ name: "service-c", dir: "./service-c" },
];
await Promise.all(independentStacks.map(async (stackInfo) => {
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "prod",
workDir: stackInfo.dir,
});
return stack.up({ onOutput: (msg) => console.log(`[${stackInfo.name}] ${msg}`) });
}));
ベストプラクティス
設定とコードを分離する
設定をファイルまたは環境変数に外部化します。
import * as fs from "fs";
interface DeployConfig {
stacks: Array<{ name: string; dir: string; }>;
environment: string;
}
const config: DeployConfig = JSON.parse(
fs.readFileSync("./deploy-config.json", "utf-8")
);
for (const stackInfo of config.stacks) {
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: config.environment,
workDir: stackInfo.dir,
});
await stack.up();
}
これにより、ソースコードを公開せずにコンパイル済みバイナリを配布できます。
長時間の操作では出力をストリーミングする
リアルタイムでフィードバックを得るには、onOutput コールバックを使用します。
await stack.up({
onOutput: (message) => {
process.stdout.write(message);
// Or send to logging system, websocket, etc.
},
});
クイックリファレンス
| シナリオ | アプローチ |
|---|---|
| 既存の Pulumi プロジェクト | workDir を指定したローカルソース |
| 新しい組み込みインフラストラクチャ | program 関数を使ったインラインソース |
| 異なるチーム | 独立性を保てるローカルソース |
| コンパイル済みバイナリの配布 | インラインソースまたはバンドルしたローカルソース |
| 複数スタック間の依存関係 | 順序に従った逐次デプロイ |
| 独立したスタック | Promise.all による並列デプロイ |
関連スキル
- pulumi-best-practices:Pulumi プログラムのコードレベルのパターン