【実務・中級編】Pulumiでよくあるエラー10選と解決策:デプロイ失敗時のトラブルシューティング – インフラ構成管理(IaC)活用バイブル

伝説のSREが明かす:Pulumiデプロイ地獄からの脱出 ―― 実戦で踏み抜くエラー10選と極限のトラブルシューティング

こんにちは。大規模クラウドインフラの自動化とSREを統括しているテックリードだ。

いま、君のチームではPulumiを使ったインフラ構成管理が進んでいることだろう。JSON/YAML地獄だったCloudFormationや、独自のDSLに縛られるTerraformから脱却し、TypeScript、Python、Goといった慣れ親しんだプログラミング言語でインフラを記述できる快感は、一度知ると戻れないものがある。

しかし、「コードで書ける」ということは、コード特有のバグや非同期処理の罠、そしてクラウドAPIの泥臭い制約がダイレクトに牙を剥くということでもある。CI/CDパイプラインが赤く染まり、夜中にPagerDutyが鳴り響くとき、あなたを救うのは表面的なエラーログの読み方ではない。インフラのライフサイクルとプロバイダーの挙動を熟知した「構造的な理解」だ。

今回は、実務の現場で容赦なくエンジニアの心を折りにくる「Pulumiでよくあるエラー10選」をピックアップし、その根本的な原因と、明日から使える解決策を魂を込めて伝授する。

—

開発スピードを極限まで高める:プロの環境構築

本題に入る前に、日々のデプロイ速度を劇的に向上させるための「隠し味」を共有しておこう。

1. 開発スピードを爆発させるキーボードショートカット&CLIテクニック

  • `pulumi up –refresh`:実インフラとStateの乖離(ドリフト)を強制同期させながらプレビューする。迷ったらまずこれ。
  • `pulumi preview –diff`:JSON形式での差分出力を有効化し、CI上で何が変更されるかを一目で把握する(環境変数 `PULUMI_DIFF_FORMAT=detailed` も推奨)。
  • `pulumi cancel`:後述するスタックロックの迅速な解除。

2. 絶対に入れるべき神ツール・プラグイン

  • Pulumi VS Code Extension: リソースのツリービュー、エディタ上でのスタック切り替え、コード補完の精度が段違いになる。
  • Direnv: プロジェクトごとに `PULUMI_ACCESS_TOKEN` やAWSのプロファイルを自動切り替えし、誤爆を防止する。

—

領域1:認証エラー・権限不足エラーの切り分け方法

クラウドインフラの自動化において、最も頻発するのが「権限がない」という壁だ。ここではローカルとCI/CDの挙動の違いに起因するエラーを斬る。

エラー1: `aws:s3:Bucket (my-bucket): error creating S3 Bucket: AccessDenied`

  • 原因: Pulumiを実行しているIAMアイデンティティ(ユーザー、ロール)に、対象リソースを作成する権限がない。特に、CI/CD用ロールの信頼ポリシー(Trust Policy)の条件ミスや、SCP(サービスコントロールポリシー)によるブロックが多い。
  • 解決策:

1. エラーメッセージから「どのプリンシパルが、どの操作で弾かれたか」を特定する。
2. ローカルでは動くのにCIで落ちる場合、AWSプロファイルの参照先違い(`AWS_PROFILE` や環境変数の混入)を疑う。
3. 権限付与のベストプラクティスとして、最小権限の原則に基づき、Pulumi実行専用のIAMロールに `AdministratorAccess` を安易に渡すのではなく、CloudTrailやIAM Access Analyzerを用いて必要な権限を逆算して付与する。

エラー2: `403 Forbidden` / `InvalidToken` (Pulumi Backend関連)

  • 原因: Pulumi Service、あるいはAWS S3 / GCSバックエンドへの認証トークンの有効期限切れ、または環境変数の設定漏れ。
  • 解決策:
  • CI/CDパイプラインでは、長期的なアクセストークンではなく、OIDC(OpenID Connect)プロバイダーを利用した一時認証(AWSであればIAMロールのAssumeRole)を必ず採用すること。シークレット漏洩のリスクをゼロにするのがSREの責務だ。

—

領域2:リソースの依存関係(DependsOn)に起因するデプロイ失敗の解消

Pulumiはコードの代入や参照関係から自動的に依存関係グラフを構築するが、クラウドAPIの「見えない制約」や「結果整合性(Eventual Consistency)」の前には無力なことがある。

エラー3: `DependencyViolation: the role cannot be deleted because it is still in use`

  • 原因: IAMロールを削除しようとした瞬間、そのロールにアタッチされたポリシーや、ロールを使用しているリソース(Lambda等)の削除が完了していない。
  • 解決策:
  • プログラミング言語の非同期処理の特性上、リソースの削除順序が逆転することがある。明示的な依存関係 `dependsOn` オプションを使用するか、`deleteBeforeReplace: true` をリソースのオプションに指定し、「新しいリソースを作ってから古いものを消す(Blue-Green的アプローチ)」を徹底する。

// TypeScriptでの実例:新しいロールを完全に作成してから古いものを安全に置換する
const myRole = new aws.iam.Role(“my-role”, {
assumeRolePolicy: “…”,
}, {
deleteBeforeReplace: true, // ゼロダウンタイム・デプロイの要
});

エラー4: `Resource not found` (作成直後のリソースを参照する場合)

  • 原因: リソースの作成APIが「リクエストを受け付けた(202 Accepted)」段階でPulumiに制御が戻り、後続のリソースがその作成直後のリソースを参照しようとして404になる。
  • 解決策: Pulumiの暗黙的な依存関係(Outputの伝播)を正しく利用する。プロパティを直接渡すことで、Pulumiは自動的に依存関係を解決する。生の文字列(IDなど)をハードコードせず、必ず `.id` や `.arn` の `Output` 型として渡すこと。

—

領域3:タイムアウトやレートリミット対策

大規模なインフラを一度に構築したり、数千個のサブネットやDNSレコードをループで生成すると、クラウドベンダーのAPI制限に激突する。

エラー5: `429 Too Many Requests` / `RateExceeded`

  • 原因: 短時間に膨大なAPIリクエストを送信したため、プロバイダー側からスロットリングを受けた。
  • 解決策:
  • プロバイダーの設定で並行度(Concurrency)を絞る。Pulumiの実行時に環境変数 `PULUMI_PARALLEL` を設定し、同時に処理するリソース数を制限する(例: `PULUMI_PARALLEL=4`)。
  • リトライロジックを持たない古いプロバイダーバージョンを使っている場合は即座にアップデートする。

エラー6: `context deadline exceeded` (タイムアウト)

  • 原因: RDSの作成、Kubernetesクラスターのプロビジョニング、大規模なVPCピアリングなど、完了までに時間がかかる処理でPulumiのデフォルトタイムアウト(通常は数十分)を超過した。
  • 解決策:
  • 各リソースオプションの `customTimeouts` を用いて、タイムアウト時間を明示的に延長する。

// タイムアウトを明示的に延ばす設定例
const cluster = new aws.eks.Cluster(“my-cluster”, {
// …設定…
}, {
customTimeouts: {
create: “45m”,
update: “45m”,
delete: “30m”,
},
});

—

領域4:スタックがロックされた場合の強制解除手順

チーム開発において最も冷や汗をかく瞬間が、「前回のデプロイが異常終了し、Stateがロックされたまま操作不能になる」現象だ。

エラー7: `[auto-error] error: the stack is currently locked by a lock ID`

  • 原因: CI/CDジョブが途中でOOMKilled(メモリ不足)になったり、誰かの手元でのデプロイ中にCtrl+Cでプロセスが強制終了されたため、バックエンドストレージ(S3やPulumi Service)にロックファイルが残った。
  • 解決策:
  • 絶対のタブー: 手動でS3バケットから直接ロックファイルを削除してはならない。並行実行によるStateの破損(Corrupted State)を招く。
  • 正しい手順: 以下のコマンドで安全にロックを強制解除する。

ロックを強制解除する(※チームメンバーが現在デプロイしていないことを必ず確認せよ)
pulumi stack refresh –yes
pulumi cancel –yes

—

領域5:その他の致命的な罠(シークレット・型エラー・言語固有の闇)

残りの3つは、コードベースや運用フェーズの深化に伴って現れる実務特有のトラブルだ。

エラー8: 平文でのシークレット漏洩 (`PlainTextSecretWarning` / ログへの出力)

  • 原因: DBのパスワードやAPIキーを普通の文字列として扱い、`console.log()` や `print()` で標準出力に出てしまった。Pulumiはこれを検知して警告、あるいは暗号化漏れを引き起こす。
  • 解決策:
  • 機密情報は必ず `pulumi.secret()` でラップする。
  • また、Pulumiのコンフィグシステムを使い、環境変数や設定ファイル経由で `pulumi config set –secret` を通して暗号化保管する。

エラー9: `TypeError: Cannot read properties of undefined (reading ‘id’)`

  • 原因: Pulumiの `Output` の概念を無視し、非同期値(PromiseやOutput)の中身を直接参照しようとした。TypeScript等でよくある初学者の罠。
  • 解決策:
  • `.apply()` メソッドを使用するか、TypeScript 5.x以降であれば `output.apply(val => val.id)` のように記述して値を安全に取り出す。決して非同期値をそのまま通常のロジックに流し込まないこと。

エラー10: プロバイダーのバージョン不整合による `Panics` や予期せぬ差分

  • 原因: ローカル環境のPulumi CLIやSDKのバージョンと、CI/CD環境、および `package.json`(または `requirements.go.mod`)のプロバイダーバージョンが乖離している。
  • 解決策:
  • プロジェクトのルートに `Pulumi.yaml` を置き、言語ランタイムとプラグインのバージョンを厳格に固定する。チーム全員が同じバージョンを使うよう、CIのLinterやDevcontainerで強制力を働かせること。

—

チーム開発で絶対に導入すべき設定ファイル・ベストプラクティス

最後に、ここまでのエラーを未然に防ぎ、チーム全体の生産性を底上げするための「神設定ファイル構成」を授けよう。

1. ディレクトリ構造のベストプラクティス

モノリスなスタック構成は絶対に避け、環境ごと・ドメインごとにディレクトリを分離せよ。

infrastructure/
├── Pulumi.yaml # プロジェクト定義
├── package.json # 依存関係(バージョン固定)
├── tsconfig.json # TypeScript設定
├── common/ # 共通コンポーネント(VPCや共通IAMなど)
│ ├── index.ts
│ └── tsconfig.json
└── stacks/
├── dev/
│ ├── Pulumi.dev.yaml # 環境別設定値
│ └── index.ts # エントリーポイント
└── prod/
├── Pulumi.prod.yaml
└── index.ts

2. ベストプラクティス設定ファイル (`Pulumi.yaml`)

言語ランタイムのバージョンを明記し、予期せぬ破壊的変更を防ぐ。

name: my-cloud-infrastructure
runtime:
name: nodejs
options:
typescript: true
description: Production-grade Infrastructure as Code with Pulumi
config:
pulumi:tags:
value:
environment: production
managed-by: pulumi

—

結びにかえて

Pulumiは、インフラストラクチャを「ただのテキスト(YAML/JSON)」から「洗練されたソフトウェア」へと昇華させる最高のツールだ。しかし、それは同時に、ソフトウェアエンジニアリングのベストプラクティス(エラーハンドリング、依存関係の制御、バージョン管理)をインフラの世界に持ち込むことを意味する。

ここで紹介した10の知見と解決策を武器に、君のチームのデプロイパイプラインからすべての「お祈りデプロイ」を駆逐してほしい。エラーログに怯える夜は今日で終わりにしよう。さあ、コードを書け。そしてインフラを支配せよ。

タイトルとURLをコピーしました