既存のTerraform資産を殺さずに近代化せよ:Pulumi Bridgeプロバイダ実践ガイド
こんにちは。大規模クラウドインフラのモダナイゼーションをいくつも率いてきたテックリードだ。
君のチームは今、こんなジレンマに陥っていないか?
「Terraformで築き上げた膨大なHCL資産がある。しかし、条件分岐やループ、テスト容易性の低さ、そしてCI/CDの遅さに開発スピードが殺されている。かといって、全リソースをゼロからPulumi(TypeScript / Python / Go)に書き換えるリソースなどどこにもない」
世の中には `tf2pulumi` というコード変換ツールが存在するが、あれは単なる「片道切符の翻訳機」に過ぎない。変換した瞬間にスナップショットとなり、本家のTerraformプロバイダのアップデート追従や、動的なIaCロジックの恩恵を受けることは困難になる。
ここで紹介するのが、Pulumiの真骨頂である 「Terraform Bridge(Pulumi Terraform Bridge)」 だ。
これを使えば、既存のあらゆるTerraformプロバイダ(公式、サードパーティ、さらには社内製のカスタムプロバイダまで)を、1行のコード修正もなしに、ネイティブなPulumiプロバイダとして完全かつ動的に稼働させることができる。
今回は、このTerraform Bridgeのメカニズムと、明日からチームの開発スピードを劇的に引き上げるための実践知を叩き込む。
—
1. なぜ `tf2pulumi` ではなく 「Bridge」 なのか?
`tf2pulumi` はHCLをPulumiのコードに静的に変換する。しかし、Terraform Bridgeは「TerraformプロバイダのgRPCインターフェースをラップし、Pulumi Engineから直接叩けるネイティブプロバイダにリアルタイム変換する」仕組みだ。
[Pulumi Code (TS/Py/Go)]
↓ (gRPC)
[Pulumi Engine]
↓ (Bridge Layer)
[Terraform Provider Binary (Go)]
↓ (API Call)
[Cloud Provider (AWS/GCP/etc.)]
このアーキテクチャがもたらす最大のメリットは以下の3点だ。
1. タイムラグゼロの追従性: AWSやGCPのプロバイダがアップデートされた際、Terraform版がリリースされれば、Bridgeを経由して即座にPulumiから最新リソースを叩ける。
2. 社内製カスタムプロバイダの即時流用: 自社で独自に生やしたTerraformプロバイダ(社内認証基盤連携など)を、そのままPulumiのエコシステムに組み込める。
3. 段階的移行(Strangler Figパターン)の完成形: インフラのコアロジックはPulumiの強力なプログラミング言語(TypeScript等の型安全性、ループ、関数分割)で書きつつ、複雑なモジュールは既存のTerraformプロバイダの挙動をそのまま維持できる。
—
2. 実践:カスタムTerraformプロバイダをPulumiにブリッジする
ここでは、一般的なAWS/GCPプロバイダではなく、あえて「独自のTerraformプロバイダ(例: `terraform-provider-internal-auth`)」をPulumi用プロバイダにトランスフォームする手順をコードベースで解説する。
ステップ1: ブリッジプロジェクトの構造化
Pulumiの `pulumi-tf-provider` スキャッフォルドを使用し、ブリッジ用のGoプロジェクトを作成する。
ブリッジプロジェクトの初期化(Go言語製)
pulumi new tf-provider –name internal-auth
プロジェクトルートにある `provider/resources.go` が、TerraformプロバイダとPulumiの世界を結ぶ心臓部だ。ここでリソースのマッピングとトランスレーションを定義する。
ステップ2: `resources.go` の極限チューニング
以下のコードは、既存のTerraformプロバイダをPulumi向けにラップし、型安全なリソースとしてマッピングする実戦的な設定だ。
// provider/resources.go
package internalauth
import (
“fmt”
“path/filepath”
// 既存のTerraformプロバイダをインポート
internalauth “github.com/my-company/terraform-provider-internal-auth/internalauth”
“github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge”
shimv2 “github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2”
“github.com/pulumi/pulumi/sdk/v3/to”
)
// プロバイダ名
const majorVersion = “1”
const $(ProviderName) = “internal-auth”
func Provider() tfbridge.ProviderInfo {
// 既存のTerraform v2 SDKプロバイダをシム層でラップ
prov := tfbridge.ProviderInfo{
P: shimv2.NewProvider(internalauth.Provider()),
Name: “internal-auth”,
// パッケージ名(TypeScriptやPythonでインポートする際の名前)
DisplayName: “Internal Auth”,
Publisher: “MyCompany”,
LogoURL: “https://raw.githubusercontent.com/…/logo.png”,
PluginDownloadURL: “github://api.github.com/my-company”,
Description: “A Pulumi package for managing internal auth via Terraform Bridge.”,
Keywords: []string{“pulumi”, “internal-auth”, “category/security”},
License: “Apache-2.0”,
Homepage: “https://example.com”,
Repository: “https://github.com/my-company/pulumi-internal-auth”,
Config: map[string]tfbridge.SchemaInfo{
// プロバイダレベルの設定値の型マッピング
“api_endpoint”: {
Default: &tfbridge.DefaultInfo{
EnvVars: []string{“INTERNAL_AUTH_ENDPOINT”},
},
},
},
Resources: map[string]tfbridge.ResourceInfo{
// Terraform側のリソース名をPulumi側のクラス名にマッピング
“internalauth_user”: {
Tok: tfbridge.MakeResource($(ProviderName), “index”, “User”),
Fields: map[string]tfbridge.SchemaInfo{
// 特殊なフィールド変換やドキュメントのオーバーライドが必要な場合ここに記述
“secret_key”: {
Secret: to.BoolPtr(true), // PulumiのSecrets管理に自動統合
},
},
},
},
DataSources: map[string]tfbridge.DataSourceInfo{
“internalauth_user”: {
Tok: tfbridge.MakeDataSource($(ProviderName), “index”, “GetUser”),
},
},
}
// ドキュメントの自動生成設定
prov.SetAutonaming(255, “-“)
return prov
}
ステップ3: ビルドとローカルインストール
このプロジェクトをビルドすることで、Pulumiが認識できるネイティブプラグイン(バイナリ)が生成される。
プロバイダのビルド
make provider
ローカルのPulumiプラグインディレクトリにインストール
pulumi plugin install resource internal-auth v1.0.0 –file ./bin/pulumi-resource-internal-auth
これで、TypeScriptやPythonから `import as internalAuth from “@my-company/pulumi-internal-auth”;` のように、あたかも最初からPulumi製だったかのように呼び出せるようになる。
—
3. チーム開発で絶対に破綻させないための設計ルール
ブリッジプロバイダや既存プロバイダを混在させたPulumi環境を複数人で運用する場合、ガバナンスを効かせないとカオスが訪れる。テックリードとして強制すべきルールを共有しよう。
① 状態の排他制御(Backend Configの統一)
PulumiはデフォルトでPulumi Service(SaaS)をバックエンドに使うが、企業秘密やレギュレーションの観点からAWS S3 / GCP GCSを backend に指定することが多い。
チームメンバー全員が同じステートを参照できるよう、ルートディレクトリに `Pulumi.yaml` と併せて共通の環境変数を強制する。
Pulumi.yaml のベストプラクティス構成
name: infrastructure-core
runtime:
name: nodejs
options:
packagemanager: npm
description: Enterprise Core Infrastructure with Bridge Providers
config:
pulumi:tags:
value:
environment: production
managed-by: pulumi
team: platform-eng
② チームで共有すべき `tsconfig.json` / リント設定
TypeScriptを言語として採用する場合、型安全性を極限まで高めるためのコンフィグを全リポジトリで統一する。Terraform Bridgeを通したリソースは型定義(`@pulumi/…`)が自動生成されるため、厳格な型チェックが必須だ。
{
“compilerOptions”: {
“target”: “ES2022”,
“module”: “NodeNext”,
“moduleResolution”: “NodeNext”,
“lib”: [“ES2022”],
“strict”: true,
“noImplicitAny”: true,
“strictNullChecks”: true,
“noImplicitReturns”: true,
“noUncheckedIndexedAccess”: true,
“skipLibCheck”: true,
“forceConsistentCasingInFileNames”: true
},
“include”: [“index.ts”, “config//.ts”]
}
特に `noUncheckedIndexedAccess: true` は、Terraformの配列・マップ出力を扱う際に未定義エラーをコンパイル時に検知できるため、インフラのデプロイ事故を9割減らせる。
—
4. 開発スピードを異次元に引き上げるプロの技
最後に、日々のコーディングとデプロイの速度を限界まで高めるための実践テクニックを授ける。
神プラグイン & エディタ拡張 (VS Code)
1. Pulumi Snippets: リソース定義のボイラープレートを一瞬で展開。
2. HashiCorp Terraform (参考用): ブリッジプロバイダを書く際、本家のスキーマを確認するために手放せない。
3. Error Lens: インフラコードの型エラーやプロパティのタイポをコード行内にインライン表示させ、視線移動をゼロにする。
爆速フィードバックループを作るエイリアス集
Terraformの `plan` / `apply` は時に遅いが、Pulumiはプレビューが速い。さらに以下のエイリアスを `~/.zshrc` に仕込むことで、日々のイテレーションスピードが3倍になる。
変更差分をJSONで即座に吐き出し、CIのテストモックに使う
alias pl-preview-json=”pulumi preview –json > last-preview.json”
スタックのシークレットを復号してローカル確認(デバッグ用)
alias pl-config-reveal=”pulumi config –show-secrets”
壊れたステートの修復(リソースのインポート漏れや競合時)
alias pl-refresh-force=”pulumi refresh –yes –suppress-outputs”
—
5. おわりに
Terraform Bridgeという技術は、過去の資産(Terraform)と未来の表現力(Pulumiのプログラミング言語によるIaC)を繋ぐ「最強の架け橋」だ。
「全てをスクラップ&ビルドする」という幻想は捨てろ。プロであれば、既存の資産をスマートにラップし、エコシステムの美味しいところだけを摘み取るべきだ。
このアプローチを取り入れれば、移行コストを最小限に抑えながら、チームのインフラ開発スピードを圧倒的な次元へと引き上げることができる。
さあ、今すぐ `pulumi-tf-provider` をクローンし、君たちの手でその架け橋を築き上げろ。