使用 Github Actions 執行 Terraform,以部署至 GCP
简而言之
我用Github Actions来执行了Terraform。
前提是指一个基本的条件或假设
后台
在使用Terraform进行后端配置时,应了解以下两点。(※由于我选择了GCS作为提供者,所以如果提供者不同,可能还需要注意其他事项。)
-
- 需要预先创建存储空间。
-
- 无法在 apply 中同时创建指定给后端的存储空间。必须先预先创建。
-
- 授权顺序
- 根据以下文章,Terraform 在加载模块之前加载,因此需要在后端指定凭据。如果在提供方 (provider) 中指定凭据,则不需要在后端指定。如果没有在提供方指定并且没有在后端指定,则将使用默认服务帐户。因此,除非特殊情况,否则我们不太经常这样做。但正如后面所述,我们将凭据作为环境变量传递,因此无需设置任何路径。
请参考以下链接获取帮助:
https://www.terraform.io/docs/github-actions/actions/plan.html
HCL语法的更改转换为yaml
截至2019年9月21日,Github Actions工作流语法已更改为yaml格式(尽管仍可用但已被弃用)。因此,根据以下文章的指示,需要执行迁移工具将HCL转换为yaml格式。
开始
首先,将Terraform官方提供的工作流示例复制并粘贴。
workflow "Terraform Cloud" {
resolves = "terraform-plan"
on = "pull_request"
}
action "filter-to-pr-open-synced" {
uses = "actions/bin/filter@master"
args = "action 'opened|synchronize'"
}
action "terraform-fmt" {
uses = "hashicorp/terraform-github-actions/fmt@<latest tag>"
needs = "filter-to-pr-open-synced"
secrets = ["GITHUB_TOKEN"]
}
action "terraform-init" {
uses = "hashicorp/terraform-github-actions/init@<latest tag>"
needs = "terraform-fmt"
secrets = ["GITHUB_TOKEN", "TF_ACTION_TFE_TOKEN"]
env = {
TF_ACTION_TFE_HOSTNAME = "app.terraform.io"
}
}
action "terraform-validate" {
uses = "hashicorp/terraform-github-actions/validate@<latest tag>"
needs = "terraform-init"
secrets = ["GITHUB_TOKEN"]
}
action "terraform-plan" {
uses = "hashicorp/terraform-github-actions/plan@<latest tag>"
needs = "terraform-validate"
secrets = ["GITHUB_TOKEN", "TF_ACTION_TFE_TOKEN"]
env = {
TF_ACTION_TFE_HOSTNAME = "app.terraform.io"
}
}
我对Pull Request执行简单的操作,包括fmt、init、validate和plan。每个操作都在uses中指定了相应的脚本。
将其改写为YAML文件
首先,将其转换为YAML格式。
然后,从这里下载最新的二进制文件,并设置路径。
将要转换的HCL工作流文件放置在存储库根目录下的.github/main.workflow。
在存储库根目录下执行migrate-actions。
然后将创建一个转换后的文件到存储库根目录下的.github/workflows/pull_request.yml。就是这样。
on: pull_request
name: Terraform Cloud
jobs:
filter-to-pr-open-synced:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: filter-to-pr-open-synced
uses: actions/bin/filter@master
with:
args: action 'opened|synchronize'
- name: terraform-fmt
uses: hashicorp/terraform-github-actions/fmt@<latest tag>
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: terraform-init
uses: hashicorp/terraform-github-actions/init@<latest tag>
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TF_ACTION_TFE_HOSTNAME: app.terraform.io
TF_ACTION_TFE_TOKEN: ${{ secrets.TF_ACTION_TFE_TOKEN }}
- name: terraform-validate
uses: hashicorp/terraform-github-actions/validate@<latest tag>
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: terraform-plan
uses: hashicorp/terraform-github-actions/plan@<latest tag>
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TF_ACTION_TFE_HOSTNAME: app.terraform.io
TF_ACTION_TFE_TOKEN: ${{ secrets.TF_ACTION_TFE_TOKEN }}
填写必要的事项
只需要跟着《入门指南》逐渐阅读,并填写必要的部分即可。
设置凭据
由于本次使用的Provider是Google,我们需要将Service Account的秘钥设置为凭据。创建Service Account,并为其分配Terraform所需的角色(具体操作取决于具体需求)。将下载的Service Account秘钥的JSON文件添加到GitHub仓库设置 -> Secrets中,并命名为GOOGLE_CREDENTIALS。然后只需将其作为环境变量传递给工作流程即可。
最终文件
最终文件是这个。
我认为可能存在一些目录和命令标志方面的小差异。
on: pull_request
name: Terraform
jobs:
filter-to-pr-open-synced:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: filter-to-pr-open-synced
uses: actions/bin/filter@master
with:
args: action 'opened|synchronize'
- name: terraform-fmt
uses: hashicorp/terraform-github-actions/fmt@v0.4.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TF_ACTION_WORKING_DIR: ./main
- name: terraform-init
uses: hashicorp/terraform-github-actions/init@v0.4.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
TF_ACTION_WORKING_DIR: ./main
- name: terraform-validate
uses: hashicorp/terraform-github-actions/validate@v0.4.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TF_ACTION_WORKING_DIR: ./main
- name: terraform-plan
uses: hashicorp/terraform-github-actions/plan@v0.4.0
with:
args: '-var-file=./config.tfvars'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TF_ACTION_WORKING_DIR: ./main
TF_ACTION_WORKSPACE: default
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
只需将此文件放置在存储库根目录的.github/workflows/pull_request.yml位置,然后创建拉取请求即可完成。工作流将被执行,并将结果作为评论贴出来。
总结和未来计划
尝试一下,意外地很简单。其他就是希望将 apply 作为 issue 评论(例如 /apply)触发成为一个事件。