概要
Github Actionsを使って、Terraformリポジトリの継続的インテグレーションが行えるようになるまでの設定手順をハンズオンライクに記載します。
Githubに機密情報を預けたくないという方には向きません。
前提
- Githubでtfファイルを管理している
- AWSアカウントを保持している
CIでチェックする内容
こちらの記事を参照ください。
Github Actionsの設定
完成形はこちらを参照ください。
特徴
CodeBuildでの設定と比べ以下のような特徴があります。
○ 設定方法が容易
○ 並列実行も可能
△ AWSやTerraform CloudのCredentialをGithubに記録する必要がある
CredentialsをGithub上に管理する必要がある点が引っかかる方は、CodeBuildによるCIをおすすめします。AWS上で実行するので、AWSのCredentialsは不要であり、その他のCredentialsはSSM Parameter-StoreでKMSを用いて機密データを保管することが可能です。
ディレクトリ構成
リポジトリのディレクトリ構成は以下のようにします。
├── .github/
│ └── workflows/
│ └── terraform_ci.yml # Actionsの設定ファイル
├── environments/ # CIの対象ファイル群
│ └── aws/
│ ├── development/
│ └── practice/
└── scripts/
└── ci/ # スクリプト群
設定ファイルの記述
GithubActionsはワークフロー実行のファイルを記載するだけで設定は完了となります。
しかもTerraform CI/CDやAWS/GCP等のパブリッククラウドへのデプロイなどワークフローテンプレートが用意されているため、これをベースに多少カスタマイズするだけで使用開始することができます。
今回もGithubで用意されているテンプレートをベースにカスタマイズしていきましょう。
テンプレートを取得するためには、リポジトリのActions
タブを押下し、Terraform
を選択します。
テンプレートが表示されるため、いったん右上のStart Commit
でファイルを作成しましょう。
テンプレートの設定概要
ここで作成したテンプレートは以下の前提で作られています。
-
master
ブランチへのpush
およびPR作成・更新時にワークフローが実行される - リポジトリのルートディレクトリに対象のtfファイルが存在する
- ステートファイルをTerraform Cloudで管理している、また
plan
等のコマンドをTerraform Cloud上で実行する -
fmt
とplan
を実行する -
master
ブランチへのpush
を契機に、applyを実行する
今回、この前提とは異なる部分に対してカスタマイズを行っていきます。すなわち、
- AWSのcredentialsを読み込む
- コマンドは
Github
上で実行する -
apply
は実行しない -
validate
tflint
も実行する -
environments
ディレクトリ以下の各環境別にCIを実行する
の変更を加えていきます。
AWSのcredentialsを読み込む
まずリポジトリにAWSとTerraformCloud(ステート管理で使用している場合)のcredentialsを登録します。
リポジトリの Settings → Secretsより、以下の環境変数名で登録します。
シークレット名称 | 概要 |
---|---|
AWS_ACCESS_KEY_ID | AWSのアクセスキーID |
AWS_SECRET_ACCESS_KEY | AWSのシークレットアクセスキー |
TF_API_TOKEN | Terraform Cloudの認証トークン |
このままではAWS認証情報は読み込まれないので、checkout
stepの次にcredentialsをセットするstepを追加します。
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
コマンドはGithub
上で実行する
これはTerraform Cloudでステート管理している場合に限ります。(S3やGCSで管理している場合は必然的にGithub Actions
上でコマンドが実行されるため、気にする必要がありません。)
Settings → General より Execution ModeをLocal
に設定します。(デフォルトだとRemote
)
apply
は実行しない
CIにフォーカスするという意味でです。単純に以下のapplyの行を削除、またはコメントアウトするだけです。
- name: Terraform Apply
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
run: terraform apply -auto-approve
validate
tflint
も実行する
validateはterraform validate
で実行可能なので、これは(init
より下に)stepとして追加するだけで完了です。
- name: Terraform Validate
id: validate
run: terraform validate -no-color
tflint
はterraform
のコマンドではないため、reviewdog/action-tflintを利用します。こちらは誤りのある部分をPRにレビューコメントしてくれるという機能もついています。せっかくなので利用する設定にしてみます。
コマンドがinit
前提のためinit
より下にstepを追加します。
- name: TFLint
uses: reviewdog/action-tflint@master
with:
github_token: ${{ secrets.github_token }}
reporter: github-pr-review # PRにコメントする
fail_on_error: true
environments
ディレクトリ以下の各環境別にCIを実行する
Github Actionsに用意されているstrategy.matrix
を利用して、複数ディレクトリのCIを実現します。
なお、この場合、ワークフローはmatrix
に設定した数分だけ(並列して)実行されます。
**matrix部分が直書きのため、対象環境が増えた場合に書き足す必要があります。**この部分をうまく解決する方法を思いつきませんでした。。。
特定のディレクトリのみ実施したい場合は、strategy.matrix
は必要なく、working-directory
を対象ディレクトリに設定すればよいです。
terraform-ci:
name: Terraform
strategy:
matrix:
env: [practice, development] # ここに対象環境名を羅列
runs-on: ubuntu-latest
defaults:
run:
shell: bash
working-directory: ./environments/aws/${{ matrix.env }} # このディレクトリでこれ以下のコマンドを実行していく
変更をpush
ここまででカスタマイズは完了です。設定ファイルの変更をコミットしてみましょう。
Actionsタブにてワークフローが実行されていることを確認できたら、正常に稼働しています!
Options1. CIの結果をPRにコメントする
上記までの設定でCIが実行されるようになりましたが、その結果はActionsタブの実施結果→対象stepを見る必要があります。しかしPR上でその確認まで済ませたいというケースもあるでしょう。そこで、CI実行結果をPRにコメントとして記載するような設定を追加してみます。また、一度のワークフローですべてのチェックを行うことができる点も魅力です。
ただし、fmt
等に失敗しても、CIの実行ステータス自体はComplete
となる点に注意してください。(うまく実行結果をチェックする機構をとれば可能かもしれません。)トレードオフで導入有無を選択ください。
各コマンドで失敗しても、ワークフローを中断しない
すべての結果を一度に見たいため、ワークフローを最後まで走らせる必要があります。そこでfmt``validate``plan
にエラー時も次へ進む設定を追記します。また、stepのidも振っておきましょう。
- name: Terraform Validate
id: validate # ここを追記
run: terraform validate -no-color
continue-on-error: true # ここを追記
コメント通知の実装
公式ReadmeのOutputs can be used in subsequent steps to comment on the pull request
の例をほぼそのまま利用します。
steps.<STEP>.outcome
はそのstepの実行結果(success、failure、cancelled、skippedのいずれか)、steps.<STEP>.outputs.stdout
はそのコマンドの実行結果標準出力を表しています。
# 一番最後のstepとして定義
- uses: actions/github-script@0.9.0
if: github.event_name == 'pull_request' # PR作成・更新時だけ実行する
env:
PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const output = `## \`${{ matrix.env }}\`
#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\`
#### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
#### Terraform Validation 🤖${{ steps.validate.outputs.stdout }}
#### Terraform Plan 📖\`${{ steps.plan.outcome }}\`
<details><summary>Show Plan</summary>
\`\`\`${process.env.PLAN}\`\`\`
</details>
*Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`, Workflow: \`${{ github.workflow }}\`*`;
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
Options2. strategy.matrix
を使わずに複数ディレクトリのCI
これはCodeBuild実行時に使用した方法と同様で、ラッパースクリプトを作成し、その中で対象のディレクトリを列挙、コマンドを実行するといった流れです。以下のような特徴があります。
- ワークフローは単一のものとなる
- 対象ディレクトリが増えた場合も、CI設定の変更は不要
- ラッパースクリプトを作成する必要がある
-
tfnotify
を利用する場合、pull_request
イベントではうまく発火されない(これは設定が悪いのかもしれません)
なお、ラッパースクリプトはこちらの記事で作成したものとほぼ同様なので参照ください。本記事では差分のみを記載します。
GithubActions設定ファイル作成
基本の流れは変わりません。以下の点を変更する程度となります。
-
strategy.matrix
は使用しない - 各stepではラッパースクリプトを実行する
runs-on: ubuntu-latest
defaults:
run:
shell: bash
working-directory: .
############## 中略 ##############
- name: Install Dependent Packages
run: ./scripts/ci/install_packages.sh
- name: Terraform Format Check
run: ./scripts/ci/format.sh
############## 以下同様 ##############
tfnotify
をGithubActions対応とする
1行目のci
の記述を変更するのみです。それ以外は、そのままで使いまわしが可能です。
ci: github-actions
また、これはtfnotify
側の問題なのかこちらの設定が悪いのかが不明ですが、pull_request
実行の場合だとうまくPRにコメントがつきませんでした。また、label
設定もうまく機能しませんでした。こちら情報ありましたら提供願います。
on:
push:
# どうもGithub-Actions上でtfnotifyはpushでないと動かない様子
# branches:
# - master
# - development
# pull_request:
PRにnotifyはされるようになるので、最低限やりたいことはクリアできていると思います。