使用GitHub Actions自动化Terraform的Monorepo结构

当Terraform命令如terraform plan等在每个Pull Request自动执行时,Terraform的运维将变得更加轻松。本文将介绍在GitHub Actions中如何使用自动化实现以单个代码库结构支持Terraform的运维。需要注意的是,本文中的示例是基于AWS的,但总体内容应该对其他云平台也有参考价值。

请简要概括以下内容的中文释义。请只给出一种选项:

内容: 指某种信息、知识或资料所包含的全部信息、要素或事物。

这是我们最近在GitHub中实施的工作流程。

执行Terraform

使用GitHub Actions来执行Terraform命令。
参考以下内容,将Terraform的format, validate和plan结果作为PR的评论。

 

name: 'Terraform'
on:
  pull_request:
jobs:
...
  terraform:
...
    steps:
    - name: Checkout
      uses: actions/checkout@v3

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        role-to-assume: arn:aws:iam::XXXXXXXXXXXX:role/terraform-role
        aws-region: ap-northeast-1

    - name: Setup Terraform
      uses: hashicorp/setup-terraform@v1

    - name: Terraform Init
      id: init
      run: terraform init
      working-directory: ${{ matrix.workdir }}

    - name: Terraform Format
      id: fmt
      run: terraform fmt -check
      continue-on-error: true
      working-directory: ${{ matrix.workdir }}

    - name: Terraform Validate
      id: validate
      run: terraform validate -no-color
      continue-on-error: true
      working-directory: ${{ matrix.workdir }}

    - name: Terraform Plan
      id: plan
      if: github.event_name == 'pull_request'
      run: terraform plan -no-color -input=false
      continue-on-error: true
      working-directory: ${{ matrix.workdir }}

    - name: Update Pull Request
      uses: actions/github-script@v6
      if: github.event_name == 'pull_request'
      env:
        PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
      with:
        github-token: ${{ secrets.GITHUB_TOKEN }}
        script: |
          const output = `#### Terraform Format and Style ?\`${{ steps.fmt.outcome }}\`
          #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
          #### Terraform Plan ?\`${{ steps.plan.outcome }}\`
          #### Terraform Validation ?\`${{ steps.validate.outcome }}\`
          <details><summary>Show Plan</summary>
          \`\`\`\n
          ${process.env.PLAN}
          \`\`\`
          </details>
          *Pushed by: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
          github.rest.issues.createComment({
            issue_number: context.issue.number,
            owner: context.repo.owner,
            repo: context.repo.repo,
            body: output
          })
    - name: Terraform Plan Status
      if: steps.plan.outcome == 'failure'
      run: exit 1

使用aws-actions/configure-aws-credentials@v1以获取AWS身份验证信息。
推荐使用role-to-assume,这是一种安全且值得推荐的方法。

working-directory位于执行每个Terraform命令的步骤中,与单一代码库的处理相关。下面将进行解释。

对于物料库存系统做出响应

为了执行在monorepo中每个Terraform工作目录中准备的上述Terraform作业,我们使用dorny/paths-filter操作。
通过使用该操作,可以根据YAML文件的定义来判断目标目录中的文件是否有变化。这是可以在GitHub Actions的作业内执行路径筛选功能的操作。

...
jobs:
  determine-workdir:
    runs-on: ubuntu-20.04
    permissions:
      pull-requests: read
      contents: read
    timeout-minutes: 10
    outputs:
      workdirs: ${{ steps.filter.outputs.workdirs }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - uses: dorny/paths-filter@v2
        id: changes
        with:
          filters: .github/path-filter.yml

      - name: filter
        id: filter
        run: |
          WORKDIRS=$(echo '${{ toJSON(steps.changes.outputs) }}' | jq '. | to_entries[] | select(.value == "true") | .key')
          echo "workdirs=$(echo $WORKDIRS | jq -sc '.')" >> $GITHUB_OUTPUT

  terraform:
    needs: determine-workdir
    runs-on: ubuntu-20.04
    permissions:
      id-token: write
      contents: read
      pull-requests: write
    timeout-minutes: 10
    if: needs.determine-workdir.outputs.workdirs != '[]'
    strategy:
      matrix:
        workdir: ${{ fromJSON(needs.determine-workdir.outputs.workdirs) }}
...

在 YAML 文件中定义了在目录中是否有更改的条件如下:
在 key 部分中写入工作目录的名称,在 value 部分中写入要针对工作目录进行更改筛选的路径过滤器的值。在下面的示例中,如果在 account-a 目录下和 modules 目录下有更改,则将其视为 account-a 目录中有更改。
通过在多个目录中进行定义,可以适应单一仓库的结构。

account-a:
  - 'account-a/**'
  - 'modules/**'
account-b:
  - 'account-b/**'
  - 'modules/**'
account-c:
  - 'account-c/**'
  - 'modules/**'

您可以根据 strategy.matrix 传递的多个值来执行多次作业。通过将由 dorny/paths-filter 获取的多个工作目录名称指定为 strategy.matrix 的值,可以在单体库中对每个已更改的工作目录执行作业。此外,还将由 matrix 获取的工作目录名称通过前述各个 Terraform 命令的 working-directory 进行指定。

关于 matrix 的详细说明可在以下文档中找到:
https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix

在此之前,您可以使用GitHub Actions自动化Terraform的Monad Repository结构。

总结

以下是GitHub Actions代码的整体部分。
在官方上,有一个针对自动化的Terraform产品叫作Terraform Cloud。
如果由于各种原因难以使用Terraform Cloud,我个人认为使用GitHub Actions作为实现Terraform自动化的另一种方法是不错的选择。

name: 'Terraform'

on:
  pull_request:

jobs:
  determine-workdir:
    runs-on: ubuntu-20.04
    permissions:
      pull-requests: read
      contents: read
    timeout-minutes: 10
    outputs:
      workdirs: ${{ steps.filter.outputs.workdirs }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - uses: dorny/paths-filter@v2
        id: changes
        with:
          filters: .github/path-filter.yml

      - name: filter
        id: filter
        run: |
          WORKDIRS=$(echo '${{ toJSON(steps.changes.outputs) }}' | jq '. | to_entries[] | select(.value == "true") | .key')
          echo "workdirs=$(echo $WORKDIRS | jq -sc '.')" >> $GITHUB_OUTPUT
  terraform:
    needs: determine-workdir
    runs-on: ubuntu-20.04
    permissions:
      id-token: write
      contents: read
      pull-requests: write
    timeout-minutes: 10
    if: needs.determine-workdir.outputs.workdirs != '[]'
    strategy:
      matrix:
        workdir: ${{ fromJSON(needs.determine-workdir.outputs.workdirs) }}

    steps:
    - name: Checkout
      uses: actions/checkout@v3

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        role-to-assume: arn:aws:iam::XXXXXXXXXXXX:role/terraform-role
        aws-region: ap-northeast-1

    - name: Setup Terraform
      uses: hashicorp/setup-terraform@v1

    - name: Terraform Init
      id: init
      run: terraform init
      working-directory: ${{ matrix.workdir }}

    - name: Terraform Format
      id: fmt
      run: terraform fmt -check
      continue-on-error: true
      working-directory: ${{ matrix.workdir }}

    - name: Terraform Validate
      id: validate
      run: terraform validate -no-color
      continue-on-error: true
      working-directory: ${{ matrix.workdir }}

    - name: Terraform Plan
      id: plan
      if: github.event_name == 'pull_request'
      run: terraform plan -no-color -input=false
      continue-on-error: true
      working-directory: ${{ matrix.workdir }}

    - name: Update Pull Request
      uses: actions/github-script@v6
      if: github.event_name == 'pull_request'
      env:
        PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
      with:
        github-token: ${{ secrets.GITHUB_TOKEN }}
        script: |
          const output = `#### Terraform Format and Style ?\`${{ steps.fmt.outcome }}\`
          #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
          #### Terraform Plan ?\`${{ steps.plan.outcome }}\`
          #### Terraform Validation ?\`${{ steps.validate.outcome }}\`
          <details><summary>Show Plan</summary>
          \`\`\`\n
          ${process.env.PLAN}
          \`\`\`
          </details>
          *Pushed by: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
          github.rest.issues.createComment({
            issue_number: context.issue.number,
            owner: context.repo.owner,
            repo: context.repo.repo,
            body: output
          })
    - name: Terraform Plan Status
      if: steps.plan.outcome == 'failure'
      run: exit 1

请提供以下内容的本土化汉语释义(仅需一个选项):

1. Reference

我参考了以下内容。

    • https://developer.hashicorp.com/terraform/tutorials/automation/github-actions

 

    https://zenn.dev/naofumimurata/articles/tf-monorepo-github-actions
bannerAds