はじめに
こんにちは!今月はタコスにハマり自宅でタコスを作るようになったエンジニアのまんだです。
Terraformでインフラ変更を行う際、こんな課題に直面していませんか?
- レビュアーがPRの影響範囲を把握するため、ローカルで
terraform planを実行する必要がある - 環境によってTerraformのバージョンやプロバイダーが異なり、結果に差が生じる
- Plan結果がレビューコメントに残らず、議論の記録として蓄積されない
- デプロイ担当者が特定の個人に偏り、新メンバーの参入障壁が高い
本記事では、GitHub Actionsによるリモート実行とtfcmtによる結果の可視化を組み合わせることで、これらの課題を解決するCI/CD環境を構築します。
本記事のアプローチ
今回の構成は理想的なものでは決してなく、運用上のトレードオフを理解した上でチームの状況に応じて選択・調整する必要がありますが、なんとか運用できそうな実装を共有します:
✅ 実用性を優先: GitHub Free/Teamプランでも動作する構成
✅ 段階的導入: 小さく始めて徐々に改善できる設計
実現する価値
- 統一された実行環境: ローカル環境の差異を排除し、一貫した結果を保証
- レビュー体験の向上: PRコメントで即座にインフラ変更の影響を確認
- 議論の記録化: Plan結果がPRの文脈と共に履歴として蓄積
- 参加障壁の削除: ローカルセットアップ不要で、すべてのメンバーが参加可能
本記事内のコードがそのままコピペで使えることを保証はしません。各自の環境に合わせて調整してください。
全体アーキテクチャ
基本的な流れ
- Pull Request作成 →
terraform plan実行 → tfcmtで変更内容をPRコメント - レビュー・承認 → マージ
- mainブランチへのpush →
terraform apply自動実行 - インフラ反映完了
この流れにより、リモートでの統一された実行環境と、PRコメントによる可視化を実現します。
tfcmt による Plan 結果の可視化
tfcmt とは
tfcmt は、Terraform planの結果をGitHub/GitLab のPull Request/Merge Requestに自動的にコメントするツールです。元々は mercari/tfnotify のフォークとして開発され、Terraform v0.15以降のサポートや高度なフォーマット機能など、多くの改善が加えられています。
開発者のsuzuki-shunsuke氏によって活発にメンテナンスされており、以下の特徴があります:
- 見やすい差分表示: 作成・変更・削除されるリソースを整形して表示
- 複数実行の対応: 同じPRで複数回planを実行しても、コメントを更新(スパム防止)
- カスタマイズ可能: テンプレート機能で表示形式を自由に調整
- エラーハンドリング: plan失敗時も適切にコメント投稿
基本的な使用方法
tfcmtの核となる機能は、以下の要素で構成されます:
- インストール: GitHub releasesからバイナリをダウンロード
- 実行:
terraform planの出力をパイプでtfcmtに渡す - コメント投稿: GITHUB_TOKENを使ってPRに自動投稿
# 基本的な実行パターン
tfcmt plan -- terraform plan -no-color
重要なオプション:
-patch: 差分形式での見やすい表示-var target:環境名: テンプレート内での変数使用
完成形:統合ワークフロー
ここまでの要素を組み合わせた、ワークフローの全体像です。
PR時の自動Plan + コメント投稿
# .github/workflows/terraform-plan.yml
name: Terraform Plan
on:
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
paths:
- "infrastructure/**"
- ".github/workflows/terraform-*.yml"
permissions:
id-token: write # AWS OIDC認証用
contents: read
pull-requests: write # PRコメント投稿用
# issues: write # tfcmtがラベル作成する場合は必要
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.11.0"
terraform_wrapper: false # tfcmtでパイプ処理するため必須
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
- name: Install tfcmt
env:
TFCMT_VERSION: v3.4.1
run: |
wget "<https://github.com/suzuki-shunsuke/tfcmt/releases/download/${TFCMT_VERSION}/tfcmt_linux_amd64.tar.gz>" -O /tmp/tfcmt.tar.gz
tar xzf /tmp/tfcmt.tar.gz -C /tmp
sudo mv /tmp/tfcmt /usr/local/bin
- name: Terraform Init
run: terraform -chdir=infrastructure init -input=false
- name: Select Workspace
run: |
cd infrastructure
terraform workspace select dev || terraform workspace new dev
- name: Plan with PR Comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
tfcmt --var target:dev plan --patch -- \\\\
terraform -chdir=infrastructure plan \\\\
-var-file=environments/dev.tfvars \\\\
-input=false \\\\
-no-color

マージ後の自動Apply
GitHub Free/Team プランでは、プライベートリポジトリで environment protection rules(承認フローなど)が使えません[^1]。したがって、承認ステップを利用したapplyは利用できません。しかしPRのレビュー・承認プロセス自体が承認フローとして機能するため、planとapplyのワークフローを分割し、マージをトリガーにした自動Applyも実践的な選択肢です。
[^1]: Using environments for deployment - GitHub Docs - "If you are on a GitHub Free, GitHub Pro, or GitHub Team plan, other deployment protection rules, such as a wait timer or required reviewers, are only available for public repositories."
# .github/workflows/terraform-apply.yml
name: Terraform Apply - Development
on:
# mainブランチへのマージで自動実行
push:
branches: [main]
paths:
- "infrastructure/**"
- ".github/workflows/terraform-*.yml"
# 緊急時の手動実行オプション
workflow_dispatch:
inputs:
reason:
description: "Reason for manual deployment"
required: true
permissions:
id-token: write # AWS OIDC認証用
contents: read
jobs:
apply:
runs-on: ubuntu-latest
steps:
- name: Deployment info
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "📋 Manual deployment: ${{ github.event.inputs.reason }}"
else
echo "🔄 Automatic deployment from PR merge"
fi
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.11.0"
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
- name: Terraform Init
run: terraform -chdir=infrastructure init -input=false
- name: Select Workspace
run: |
cd infrastructure
terraform workspace select dev
- name: Terraform Apply
run: |
terraform -chdir=infrastructure apply \\\\
-var-file=environments/dev.tfvars \\\\
-input=false \\\\
-auto-approve
動作フロー
- 開発者がPRを作成 → Plan workflowが自動起動
- tfcmtがPRにコメント → レビュアーが変更内容を確認
- レビュー・承認・マージ → mainブランチへpush
- 自動Apply実行 → Terraform変更が本番環境に反映
GitHub プラン制約への対処
GitHub Free/Teamプランでenvironment protection rulesが使えない制約に対して:
PRレビューを承認フローとして活用
- PRの承認必須設定(Branch protection rules)
- マージ後の自動Applyで、レビュー済み変更のみ適用
追加の安全対策
- 手動実行オプション(workflow_dispatch)を残す
- 実行理由の記録(監査証跡)
- Slack/メール通知で実行を可視化
この方式により、GitHub Enterpriseがなくても実用的な承認フローを実現できます。
注意: planとapplyでは必要な権限が異なり、apply時に初めて構成変更の失敗に気づく可能性があります。PRをマージしたあとに対象のActionが正常に完了しているかどうかは、Slack通知連携と組み合わせながら、失敗を見逃さないような運用を検討しましょう。
まとめ
GitHub Actions + tfcmt による Terraform CI/CDのリモート実行と可視化を通じて、ローカル環境の課題を解決し、チーム全体でインフラ変更に参加できる環境を構築できました。
解決した課題
✅ 統一された実行環境の実現
- ローカル環境の差異による結果のブレを排除
- 全メンバーが同じ条件でTerraformを実行可能
✅ レビュープロセスの可視化
- Plan結果がPRコメントとして自動的に記録
- インフラ変更の議論が文脈と共に履歴として蓄積
✅ 参加障壁の大幅な削減
- ローカルセットアップ不要でインフラ変更に参加
- 新メンバーも即座にレビューに参加可能
Terraformを使うチームの生産性向上に少しでも貢献できれば幸いです。