Terraform CI/CDの深淵:GitHub Actionsで構築する「壊れない」自動化パイプラインの真髄
インフラをコード化(IaC)する際、多くのエンジニアが陥る罠がある。それは「自動化を目的化し、安全性を犠牲にする」ことだ。TerraformのCI/CDパイプラインにおいて、単に `plan` を実行し、`apply` を叩く程度の自動化は、実戦レベルでは「入り口」にも立っていない。
本稿では、数千リソースを超える大規模環境を安定運用するための、「冪等性の完全保証」と「パイプラインの高速化」を両立する実践的なアーキテクチャを紐解く。
—
1. CI/CDの設計思想:なぜ「単なる自動化」では死ぬのか
多くの現場で見られる「マージ時に自動apply」という構成には、実は重大な欠陥がある。それは、`terraform plan` の結果と `apply` される対象が乖離するリスク(Race Condition)だ。
これを防ぐための鉄則はただ一つ:「プラン実行時に作成された `planfile` をバイナリとしてアーティファクト化し、それを適用する」ことだ。テキストログを目視確認してよしとする運用は、今すぐ捨てろ。
構成の黄金律
1. Plan段階: `terraform plan -out=tfplan` で実行計画をバイナリ保存。
2. Persistence: `actions/upload-artifact` で保存した `tfplan` をステージング。
3. Apply段階: `terraform apply “tfplan”` で、保存したバイナリを直接適用。
これにより、CI中のプランと適用時の状態の不一致(Drift)を物理的に排除する。
—
2. 実装:GitHub Actionsによる「極限」の自動化スクリプト
以下は、パフォーマンスと安全性を追求したワークフローのコア部分だ。
name: Terraform Pipeline
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
terraform-plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_wrapper: false # デフォルトのラッパーは制御が甘いため、CLIを直接叩く
- name: Terraform Init & Plan
run: |
terraform init -backend-config=”bucket=${{ secrets.TF_STATE_BUCKET }}”
# 実行速度を最大化するため -parallelism オプションを明示的に調整
terraform plan -parallelism=50 -out=tfplan
- name: Upload Plan Artifact
uses: actions/upload-artifact@v4
with:
name: tfplan
path: tfplan
terraform-apply:
if: github.ref == ‘refs/heads/main’
needs: terraform-plan
runs-on: ubuntu-latest
steps:
- name: Download Plan Artifact
uses: actions/download-artifact@v4
with:
name: tfplan
- name: Apply
run: terraform apply -input=false tfplan
—
3. 現場で震えるほど役立つ「最適化ハック」
① stateロック競合を回避する「条件付き排他制御」
小規模なチームならまだしも、並行開発が激しい環境では `terraform init` がロック待ちでタイムアウトすることが多々ある。これを防ぐには、GitHub Actionsの `concurrency` 設定で、環境(ディレクトリ)ごとにジョブをシリアライズするのが唯一の正解だ。
concurrency:
group: terraform-${{ github.ref }} # ブランチごとの排他制御
cancel-in-progress: true
② 大規模インフラのメモリ消費を抑える
リソースが1,000を超えてくると、`terraform plan` は驚くほどメモリを食い、CI環境のメモリ不足(OOM Killer)を誘発する。
- 回避策: `TF_CLI_ARGS` を利用して `plan` 時にターゲットを絞る、あるいは `terraform state mv` を駆使してStateファイルを適切に分割(マイクロインフラストラクチャ化)せよ。単一の巨大Stateファイルは、IaCにおける「技術的負債の塊」だ。
③ インタラクティブ・コンソールを超えた「APIドリブン通知」
`terraform show -json` をパイプラインで解析し、`jq` を使って「何が削除されるか(破壊的変更の検知)」をGitHubのコメントに投稿するスクリプトを自動化せよ。
削除対象のみを抽出して警告するワンライナー
terraform show -json tfplan | jq -r ‘.resource_changes[] | select(.change.actions[] == “delete”) | .address’
これをCIのコメントに流し込むことで、レビュアーが「意図せぬリソース削除」に即座に気づける体制を構築する。これが、伝説的なSREが現場で必ず仕込む「防波堤」だ。
—
結論:IaCは「運用」からが本番
自動化スクリプトを書くことは、プログラマであれば誰でもできる。しかし、「リソースのライフサイクルと、チームのデプロイ速度、そして何より心理的安全性」を同時に最大化するパイプラインを設計できるのは、深淵を知るエンジニアだけだ。
コードは書いた瞬間から腐敗が始まる。Terraformのバージョンアップ追従、Stateの最適化、そしてパイプラインの高速化。これら全てを「常に改善し続ける文化」こそが、クラウドインフラを統べる唯一の道である。
さあ、次は君のパイプラインに「破壊的変更の自動検知」を組み込む番だ。その一歩が、システムの信頼性を劇的に向上させるだろう。