使用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