如何在GitHub Actions中使用Terragrunt和tfcmt来使计划结果更易于阅读

我想做的事情

我在使用GitHub Actions中的Terragrunt时,正在研究如何在pull request中评论plan结果。
虽然我能够直接评论plan结果,但我想知道是否有更好的方法,所以我决定尝试与tfcmt结合使用。

Terragrunt是什么?

Terragrunt是一个轻量级的封装工具,它使得Terraform更加方便。
它能够将设置保持DRY,并且使得管理多个Terraform模块和远程状态变得更加容易。

如果Terraform的状态被分为多个目录,并且存在依赖关系,我认为这是一个非常实用的工具。
由于它拥有许多便利功能,所以我想如果您还没有使用过它,一定要尝试一次。

 

Tfcmt是什么?

tfcmt 是一个CLI工具,将terraform plan和apply的结果作为评论通知到GitHub的Pull Request(以下简称PR)中。
使用该工具可以在PR页面上直接查看结果,无需查看CI日志。
而且相较于原始日志,结果更加清晰易懂的特点。

 

如何使用tfcmt

使用以下方式替换terraform plan 和terraform apply.

$ tfcmt plan -- terraform plan [terraform plan の引数...]
$ tfcmt apply -- terraform apply [terraform apply の引数...]

如果将terraform命令直接替换为terragrunt命令,由于无法使用run-all选项,因此需要稍加修改。

使用Terragrunt和tfcmt的组合方法

在terragrunt命令的选项中指定–terragrunt-tfpath。通过这个选项,您可以指定在Terragrunt内部执行的terraform命令所替代的可执行文件。通过指定到像下面的shell脚本的路径,您可以自定义terraform命令的行为。

terragrunt run-all plan --terragrunt-tfpath $GITHUB_WORKSPACE/.github/scripts/tfwrapper.sh

 

#!/bin/bash

set -euo pipefail

# コマンドの種類を取得(例: apply, plan, fmt...)
type=$(echo "$@" |  awk '{print $1}')

# 実行しているディレクトリ名を取得
current_dir=$(pwd | sed 's/.*\///g')

if [ "$type" == "plan" ]; then
    # planのときは-patchオプションを付ける
    # 実行ディレクトリ名をターゲットとして指定
    tfcmt -var "target:${current_dir}" plan -patch -- terraform "$@"
elif [ "$type" == "apply" ]; then
    tfcmt -var "target:${current_dir}" apply -- terraform "$@"
else
    terraform "$@"
fi

我会根据terraform命令的类型进行条件分支。
在执行plan和apply时,会运行tfcmt命令,但是在执行plan时会加上-patch选项来减少评论的数量。
其他命令将直接执行。

 

另外,在tfcmt中,可以通过使用“-var”选项来区分每个结果,例如“target:foo”,通过标签的前缀来区分。我们利用此功能将执行目录名称指定为目标。

示例代码

.
├── .github
│   ├── scripts
│   │   └── tfwrapper.sh
│   └── workflows
│       └── plan.yml
└── app
    ├── envs
    │   ├── dev
    │   │   ├── app
    │   │   │   ├── 〇〇.tf
    │   │   │   └── terragrunt.hcl
    │   │   ├── cicd
    │   │   │   ├── 〇〇.tf
    │   │   │   └── terragrunt.hcl
    │   │   ├── db
    │   │   │   ├── 〇〇.tf
    │   │   │   └── terragrunt.hcl
    │   │   └── ...
    │   └── prod
    ├── modules
    │   ├── acm
    │   │   ├── main.tf
    │   │   ├── outputs.tf
    │   │   └── variables.tf
    │   ├── cloudfront
    │   ├── cognito
    │   └── ...
    └── shared
        ├── provider.tf
        ├── variables.tf
        └── version.tf

name: Terraform plan
on:
  pull_request:
    branches:
      - main
      - develop
    types:
      - opened
      - synchronize

env:
  AWS_REGION: ap-northeast-1
  PROJECT: sample
  TF_VERSION: 1.3.7
  TG_VERSION: 0.43.0
  TFCMT_VERSION: 4.0.1

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

jobs:
  plan:
    name: Terraform plan
    runs-on: ubuntu-latest

    steps:
      - name: Set env vars for dev
        if: github.base_ref == 'develop'
        run: |
          echo "ENVIRONMENT=dev" >> $GITHUB_ENV
          echo "AWS_ACCOUNT_ID=123456789012" >> $GITHUB_ENV
          echo "WORK_DIR=app/envs/dev" >> $GITHUB_ENV

      - name: Set env vars for prod
        if: github.base_ref == 'main'
        run: |
          echo "ENVIRONMENT=dev" >> $GITHUB_ENV
          echo "AWS_ACCOUNT_ID=123456789012" >> $GITHUB_ENV
          echo "WORK_DIR=app/envs/prod" >> $GITHUB_ENV

      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup Terraform
        uses: hashicorp/setup-Terraform@v1
        with:
          terraform_version: ${{ env.TF_VERSION }}
          terraform_wrapper: false

      - name: Setup Terragrunt
        run: |
          sudo wget -q -O /bin/terragrunt "https://github.com/gruntwork-io/terragrunt/releases/download/v${TG_VERSION}/terragrunt_linux_amd64"
          sudo chmod +x /bin/terragrunt
          terragrunt --version

      - name: Setup tfcmt
        run: |
          wget "https://github.com/suzuki-shunsuke/tfcmt/releases/download/v${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: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@master
        with:
          role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/${{ env.PROJECT }}-${{ env.ENVIRONMENT }}-github-actions-terraform-role
          role-session-name: ${{ env.PROJECT }}-${{ env.ENVIRONMENT }}-github-actions-terraform-session
          aws-region: ${{ env.AWS_REGION }}

      - name: Terragrunt init
        working-directory: ${{ env.WORK_DIR }}
        run: terragrunt run-all init

      - name: Check terraform fmt
        working-directory: ${{ env.WORK_DIR }}
        run: terraform fmt -check -recursive

      - name: Terragrunt validate
        working-directory: ${{ env.WORK_DIR }}
        run: terragrunt run-all validate

      - name: Terragrunt plan
        working-directory: ${{ env.WORK_DIR }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          terragrunt run-all plan --terragrunt-tfpath $GITHUB_WORKSPACE/.github/scripts/tfwrapper.sh

请参考

 

bannerAds