在 GitHub Actions 中,如何将 terraform plan 的结果附加到 PR 上

你好,我是属于SRE部门的@ishii1648。
这篇文章是All About Group(株式会社オールアバウト) Advent Calendar 2022中的第19天的文章。

首先

我們目前正在 All About 進行 Terraform 的 CI 轉換。CI 的流程通常按以下順序進行相關操作:根據 PR 的創建和更新觸發相應的動作。

    1. 检测目标更改的目录

 

    1. 设置terraform

 

    1. 初始化terraform

 

    1. 计划terraform

 

    1. 验证terraform

 

    将terraform计划结果附加到PR中

我觉得这是一个相当常见的结构,但有一个容易出错的地方,所以我希望能够分享解决方案和大家一起解决这个问题。
虽然这个内容相当专业,但如果对此感兴趣或有相同困扰的人能够从中获得帮助,那就非常幸运了。

关于绊倒点

如果使用terraform validate(使用conftest同样适用)的话,在terraform的设置中需要设置以下选项。

- name: Setup terraform
  uses: hashicorp/setup-terraform@v2
    with:
      terraform_version: 1.x.x
      terraform_wrapper: false

请注意 terraform_wrapper 选项,它的默认设置是 true,但是如果不将其设置为 false,验证操作将无法正常执行。

然而,如果设置为此,terraform将无法进行标准输出,从而使将计划结果附加到PR变得困难。
例如,在省略验证的CI构建中,可以使用以下代码将计划结果附加到PR上。

- name: Setup terraform
  uses: hashicorp/setup-terraform@v2
  with:
    terraform_version: 1.2.0
- name: Terraform init & plan
  id: plan
  run: |
    terraform init
    terraform plan -no-color
  working-directory: ${{ matrix.dir }}
  continue-on-error: true
- name: Notify
  if: steps.plan.outputs.exitcode == 2
  uses: actions/github-script@v3.0.0
  with:
    github-token: ${{ secrets.github_token }}
    script: |
      const output = `## \`${{ matrix.dir }}\`
      <details><summary>Show Plan</summary>

      \`\`\`terraform\n${{ steps.plan.outputs.stdout }}\`\`\`

      </details>`;

      github.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: output
      })

我正在接收并通知 terraform plan 的结果作为下一个作业的标准输出(steps.plan.outputs.stdout)。但是,如果我尝试添加验证过程,就无法再使用之前提到的标准输出,这让我感到困惑。

方法去除

有两种方式可以在提交请求(PR)附上结果的同时对其进行验证:
以下是其中一种方式的代码:

- name: Setup terraform
  uses: hashicorp/setup-terraform@v2
  with:
    terraform_version: 1.2.0
    terraform_wrapper: false
- name: Terraform init & plan
  id: plan
  run: |
    terraform init
    terraform plan -no-color -out=tfplan
  working-directory: ${{ matrix.dir }}
  continue-on-error: true
- name: Terraform show
  id: show
  run: |
    terraform show -no-color tfplan > tfplan.txt
    terraform show -no-color -json tfplan > tfplan.json
    cat tfplan.txt
  working-directory: ${{ matrix.dir }}
- name: Terraform validate
  id: validate
  run: |
    cp ${GITHUB_WORKSPACE}/policies/constraints/* ${GITHUB_WORKSPACE}/policy-library/policies/constraints
    gcloud beta terraform vet tfplan.json --policy-library=${GITHUB_WORKSPACE}/policy-library --format=json
- name: Notify
  uses: actions/github-script@v3.0.0
  with:
    github-token: ${{ secrets.github_token }}
    script: |
      const output = `## \`${{ matrix.dir }}\`
      <details><summary>Show Plan</summary>

      \`\`\`terraform\n${{ steps.show.outputs.stdout }}\`\`\`

      </details>`;

      github.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: output
      })

重点是在执行 terraform plan 时设置 out 选项。out 选项会将 plan 的执行结果以二进制文件形式保存。由于我们没有使用标准输出,因此即使禁用了 terraform_wrapper,这里的功能仍然有效。

保存为二进制格式的plan结果可以通过使用terraform show命令将其转化为文本,并将其内容作为通知处理。

最后

“那个怎么样了?” le?)

我认为这是非常具有专业性的内容,但如果要将Terraform进行持续集成,我认为在其中包含静态检查例如validate也是很普遍的。在我想出这种方法之前,我花费了一个多月的时间,所以如果有相同烦恼的人,我希望你们可以参考一下。

今天是All About Group(株式会社オールアバウト)Advent Calendar 2022的第19天。

广告
将在 10 秒后关闭
bannerAds