CI/CDパイプラインにおけるtfcmtの活用法:可読性の高いPR作成&変更ログ管理

CI/CD

Terraformのコードをチームで開発する際、Pull Request (PR) を作成すると、レビュワーは terraform plan の実行結果を基に修正の要否を判断します。なぜなら、この結果を確認することで、実際に適用される変更内容に基づいてレビューできるからです。しかし、PR内で新しい変更が加わるたびに、ローカル環境にコードをpullして terraform plan を実行し、変更内容を確認するのは手間がかかります。また、そのような運用では、リソースに問題が発生した際に、どの変更が原因かを特定するのにも多くの時間と労力を要します。

そこで今回は、 tfcmt というツールを使用して、PRに変更内容を可視化し、レビュープロセスを効率化するとともに、変更履歴を記録することで将来的なトラブルシューティングの負担軽減を目指します。

tfcmtの概要と特徴

tfcmt は、Terraformの terraform planterraform apply の結果をGitHubのPRコメントとして自動的に投稿するツールです。このツールを活用することで、レビュワーがわざわざローカルで terraform plan を実行する手間を省き、PR画面上で直接変更内容を確認できるようになります。主な特徴として以下の点が挙げられます:

  • 変更の可視化: terraform planterraform apply の結果を整形し、見やすい形式でPRにコメントします。
  • ログの記録: PRに対して変更内容が記録されるため、将来のトラブルシューティングに役立ちます。
  • チームの生産性向上: レビューの効率化により、開発サイクルの短縮が期待できます。

最低限のCI/CDパイプラインを構築する

ここでは、GitHub Actions を用いて tfcmt を組み込んだ具体的なCI/CDパイプラインの例を示します。なお、以下のパイプラインでは、 Google CloudWorkload Identity を使用して認証を通しています。Google Cloud, AWS, Azureにおいて、OIDCを設定する際は、以下のドキュメントを参考に認証を通してください。

※Google Cloudでの設定方法の記事を書いているので、よろしければご参照ください。
Workload Identityを使ってGitHub ActionsからGoogle Cloudにアクセスする

CIの構築

ではまずはCIの部分から。.github/workflows/terraform-ci.ymlに下記コードを記述してください。

name: "Terraform-ci"

on:
  pull_request:
    types:
      - opened
      - reopened
      - synchronize
    paths:
      - '**.tf'
      - '**.tfvars'

permissions:
  id-token: write
  contents: read
  pull-requests: write

jobs:
  terraform-ci:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        
      - name: Authenticate to GCP
        uses: google-github-actions/auth@v1
        with:
          workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }}
          service_account: ${{ secrets.SERVICE_ACCOUNT }}

      - name: Setup tfcmt
        env:
          TFCMT_VERSION: v4.0.0
        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
          mv /tmp/tfcmt /usr/local/bin
          tfcmt --version

      - name: Terraform Format
        run: terraform fmt -check

      - name: Terraform Init
        run: terraform init

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Plan
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: tfcmt plan -patch -- terraform plan -no-color -input=false

このパイプラインでは、プルリクエストに含まれる変更において、拡張子が .tf または .tfvars のファイルであるときのみトリガーされ、 terraform plan の結果をPRにコメントします。

      - name: Terraform Plan
        if: github.event_name == 'pull_request'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: tfcmt plan -patch -- terraform plan -no-color -input=false

具体的にこのステップで terraform plan の結果をPRにコメントするようにしています。また、修正のたびに terraform plan の結果のコメントが追加されていくことを防ぐために、 -patch オプションを使用して terraform plan の結果を上書きするようにしています。
参考: -patch 公式ドキュメント

CDの構築

次にCDの部分。.github/workflows/terraform-cd.ymlに下記コードを記述してください。

name: "Terraform-cd"

on:
  push:
    branches:
      - 'main'
    paths:
      - '**.tf'
      - '**.tfvars'

permissions:
  id-token: write
  contents: read
  pull-requests: write

jobs:
  terraform-cd:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        
      - name: Authenticate to GCP
        uses: google-github-actions/auth@v1
        with:
          workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }}
          service_account: ${{ secrets.SERVICE_ACCOUNT }}

      - name: Setup tfcmt
        env:
          TFCMT_VERSION: v4.0.0
        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
          mv /tmp/tfcmt /usr/local/bin
          tfcmt --version

      - name: Terraform Format
        run: terraform fmt -check

      - name: Terraform Init
        run: terraform init

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Plan
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: terraform plan -input=false -out=tfplan

      - name: Terraform Apply
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: tfcmt apply -- terraform apply tfplan

このパイプラインでは、main ブランチに対する push において、拡張子が .tf または .tfvars のファイルの変更が含まれているときのみトリガーされ、 terraform apply の結果をPRにコメントします。

      - name: Terraform Plan
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: terraform plan -input=false -out=tfplan

      - name: Terraform Apply
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: tfcmt apply -- terraform apply tfplan

terraform plan において、-out=tfplan とし、tfplan というバイナリ形式のファイルに計画を保存し、terraform apply でそのファイルを基に変更を適用するようにしています。
main ブランチへの直接 push を制限するためには、ブランチルールを作成しておくことをお勧めします。詳細は ブランチ保護ルールを管理する を参考にしてください

動作確認

CIの動作検証

任意の名前で main からブランチを切り、プロジェクトのルートに gcs_bucket.tf ファイルを作成し、下記コードを記述してください。

resource "google_storage_bucket" "sample_bucket" {
  name     = "unique-bucket-name"
  location = "asia-northeast1"
}

push した後、PRを作成するとCIのWorkflowが実行され、PR内に terraform plan の結果がコメントされます。また、 terraform plan の結果に則したラベルが追加されていることも確認できます。

CDの動作検証

次に、このPRをマージすると、main ブランチへの push となり、CDのWorkflowが実行されます。
一連のWorkflowが成功すると、 terraform apply の結果がコメントされます。

terraform apply が失敗したらこんな表示になります。
 (サービスアカウントに権限をつけ忘れていた)

まとめ

今回は、Terraformコードをチームで効率よく開発・レビューするために、tfcmt を使用して、最低限のCI/CDの構築をしました。PR作成時に自動的に terraform plan を実行し、その結果を可視化することで、レビュワーが変更内容を直感的に把握でき、修正の要否を迅速に判断できるようになります。これにより、レビュー作業の手間を大幅に削減でき、将来的なトラブルシューティングも容易になります。tfcmtを活用することで、チーム全体の開発プロセスが効率化され、品質の向上が期待できるでしょう。