社内APIをTerraformの支配下に置け:Goによるカスタムプロバイダー開発の極意
「AWSやGCPのリソースはTerraformで完結しているのに、社内の独自システムだけが手動運用(あるいは泥臭いシェルスクリプト)のままだ」
そんなレガシーな負債に頭を抱えていないか? SREとして、あらゆるインフラ構成をコード化し、冪等性を担保するのは我々の責務だ。今回は、社内APIをTerraformの管理下に統合し、インフラ運用のパラダイムシフトを起こすための「カスタムプロバイダー開発」の深淵を解説する。
—
1. なぜ「社内API」をTerraform化すべきなのか
Terraformの真骨頂は「宣言的構成管理」にある。既存のAPIをProvider化することで、以下の恩恵を享受できる。
- 状態の可視化(State): 誰が・いつ・何を構築したかがStateファイルに記録される。
- 依存関係のグラフ化: 既存のクラウドインフラと社内システムを同一のグラフ上で管理し、正しい順序でデプロイが可能になる。
- ガードレールの適用: チーム開発において、Terraformのプランニングを通じてレビュー可能な状態にできる。
—
2. 実践:Goによるプロバイダー開発のステップ
Terraform Plugin Frameworkは、以前のSDKに比べ非常に洗練されている。まずはスケルトンを作成し、CRUDを実装しよう。
ステップ1: スケルトンの構築
`terraform-plugin-framework` を使用するのが現代のスタンダードだ。
プロジェクト初期化
mkdir terraform-provider-internal
cd terraform-provider-internal
go mod init github.com/your-org/terraform-provider-internal
ステップ2: CRUDの実装(Resourceの定義)
`internal/provider/resource_example.go` にリソースのライフサイクルを定義する。最も重要なのは `Update` と `Delete` の冪等性担保だ。
func (r resourceExample) Create(ctx context.Context, req resource.CreateRequest, resp resource.CreateResponse) {
// 1. Planからデータを取得
// 2. 社内APIへPOSTリクエスト
// 3. Stateへ反映
}
func (r resourceExample) Update(ctx context.Context, req resource.UpdateRequest, resp resource.UpdateResponse) {
// 冪等性を担保するために、API側の差分更新ロジックを確実に組むこと。
// 「存在しなければ作成、あれば更新」というupsertの考え方が基本だ。
}
—
3. 開発スピードを加速させる「神環境」の構築
プロバイダー開発は「ビルド・インストール・実行」のサイクルが遅いと死ぬ。
開発用ショートカットと設定
`Makefile` に以下のタスクを仕込み、`make dev` 一発でビルド&ローカル配置を完了させよ。
ローカルのTerraformプラグインディレクトリに強制配置
dev:
go build -o terraform-provider-internal
mkdir -p ~/.terraform.d/plugins/registry.terraform.io/myorg/internal/1.0.0/darwin_arm64/
cp terraform-provider-internal ~/.terraform.d/plugins/registry.terraform.io/myorg/internal/1.0.0/darwin_arm64/
VS Code 必須プラグイン
- Terraform (HashiCorp): 言うまでもなく必須。
- Go: `gopls` の設定を厳しくし、静的解析で型エラーを即座に潰す。
- Prettier / GoFmt: 保存時に自動整形を強制し、コードの揺れをゼロにする。
—
4. 実用的な設定ファイルのベストプラクティス
プロバイダーの設定(`provider.tf`)には、環境ごとの切り替えを意識した構成を取り入れるべきだ。
providerの設定はmodule化し、チームで共通化する
terraform {
required_providers {
internal = {
source = “myorg/internal”
version = “1.0.0”
}
}
}
provider “internal” {
# APIエンドポイントやトークンは環境変数経由が原則
endpoint = var.api_endpoint
token = var.api_token
}
チーム開発の掟:
1. `.tfvars` をコミットするな: 必ず環境変数 (`TF_VAR_xxx`) または Secret Manager を経由せよ。
2. `providers.tf` の集約: プロバイダー定義はルートディレクトリに分離し、全環境で同一の制約を強制せよ。
—
5. Registryへの登録と共有のコツ
社内利用がメインであれば、パブリックなRegistryへの登録は不要だ。社内用のTerraform Cloud/Enterprise または 自前のTerraform Registryサーバー(`go-getter` プロトコル対応)を立てるのが賢明である。
CI/CDパイプラインを組む際は、ビルドされたバイナリをGitHub Releaseにタグ付けし、`terraform init` がそこから自動で取得するように構成せよ。これにより、チームメンバーは `terraform init` を叩くだけで、最新のプロバイダーが自動インストールされるようになる。
—
最後に:エンジニアへの提言
カスタムプロバイダーを書くことは、単なるインフラの自動化ではない。「社内のAPIというブラックボックスを、Terraformの言語で定義可能な構造体へ変換する」という設計行為だ。
この力があれば、どんな巨大なシステムも恐れるに足りない。明日から早速、手動で行っているAPI叩きを、`terraform plan` の世界へ引きずり出そう。インフラの未来は、君のコードの中にしかない。