SREの侘美です。
最近はfirst call for オンライン診療の開発でRailsのコードを書いてました。
hashicorp/terraform-github-actions から後継である hashicorp/setup-terraformへ移行した際にいくつか設定でハマったので、そのことについて書いていきたいと思います。
背景
メドピアではterraformでAWSのインフラを管理しています。
terraformのリポジトリでは、レビューがスムーズに行えるようにGitHub Actions上で terraform plan
や terraform apply
、 terraform fmt
等を実行できる hashicorp/terraform-github-actions を利用し、下の画像のようにplan結果をPRに自動で投稿するようにしていました。
新サービスをリリースし仕事も一段落した先日、TerraformのGitHub Actionsに関するとあるドキュメントが更新されていることを発見しました。
Teraform GitHub Actions - Terraform by HashiCorp
なんと hashicorp/terraform-github-actions のメンテナンスが終了されていました!
メンテナンスされていないActionsを利用したままでは、最新のterraformのバージョンに対応できない日がやってきそうなので、さっそく後継の setup-terraform でGitHub Actionsの設定を書き換えることにしました。
準備
まずGitHub Actionsの設定を修正する前に、 terraform-github-actions と 後継である setup-terraform の特徴と terraform plan
の実行例を比較してみました。
terraform-github-actions
リポジトリ
特徴
- 各ステップで
uses: hashicorp/terraform-github-actions@master
を指定して、init
やplan
などのサブコマンドを指定して使う tf_actions_comment: 'true'
を指定することで、plan結果をPRに投稿してくれる- planの差分が無い場合はPRに投稿はしない
Actions上でterraform planを実行するサンプル
steps: - uses: actions/checkout@v2 - name: Terraform Init uses: hashicorp/terraform-github-actions@master with: tf_actions_version: ${{ env.TF_VERSION }} tf_actions_subcommand: 'init' - name: Terraform plan uses: hashicorp/terraform-github-actions@master with: tf_actions_version: ${{ env.TF_VERSION }} tf_actions_subcommand: 'plan' tf_actions_comment: 'true' # PRへplan結果を投稿する設定
setup-terraform
リポジトリ
特徴
- 文字通りterraformをsetupし、
terraform
コマンドが利用できるようにする - GitHub Actionsのoutput等に対応するようにscriptでwrapされている
- plan等は
run: terraform plan
で実行する - その他の機能は無く、plan結果のPRへの投稿などは自前で設定する必要がある
Actions上でterraform planを実行するサンプル
steps: - uses: actions/checkout@v2 - uses: hashicorp/setup-terraform@v1 with: terraform_version: ${{ env.TF_VERSION }} - run: terraform init - run: terraform plan -no-color
setup-terraformへの乗り換え
特徴が把握できたところで、setup-terraformを利用してPRにplan結果を投稿する設定をしていきます。 基本的には terraform-github-actions の仕様を再現する形としています。
具体的には下記の3点です。
- PRへのplan結果の投稿
- 差分が無い場合は投稿を抑制
- 差分以外の余計な出力の削除
PRへのplan結果の投稿
setup-terraform の README に記載されている設定を参考にします。
下記のように actions/github-script
を使い createComment
関数でコメントを投稿します。
secrets.GITHUB_TOKEN
はActions上で自動で定義される変数です。
- uses: actions/github-script@v1 env: # id: planのステップの出力を参照 STDOUT: "```terraform\n${{ steps.plan.outputs.stdout }}```" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const output = `<details><summary>tf plan:</summary>\n\n${process.env.STDOUT}\n\n</details>`; github.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: output })
差分が無い場合は投稿を抑制
実装方法としては2通りあります。
1つはterraformの -detailed-exitcode オプションを使うやり方です。
このオプションを付与することで、コマンドのexit codeが下記のようになります。
- 0: 成功かつ差分なし
- 1: エラー
- 2: 成功かつ差分あり
GitHub Actionsではexit codeが0以外の場合はエラーとなりworkflowで利用するには continue-on-error: true
をplanのステップに追加する必要があります。
steps: # 他のstepは省略 - name: terraform plan id: plan run: terraform plan -detailed-exitcode continue-on-error: true # 0以外のexit codeでもworkflowを継続する - name: comment on PR if: ${{ steps.plan.outputs.exitcode == 2 }} # 以下PRにコメントする処理
2つめは単純に出力内容の文字列から取得する方法です。
こちらはあまりロバストではないですが、 continue-on-error: true
を利用しなくてすむため、今回はこの方法を採用しています。
steps: # 他のstepは省略 - name: terraform plan id: plan run: terraform plan - name: comment on PR if: ${{ !contains(steps.plan.outputs.stdout, 'No changes.') }} # 以下PRにコメントする処理
差分以外の余計な出力の削除
terraform-github-actions ではterraform planを実行した際に大量に出力される <resource_id>: Refreshing state...
のような出力を削除した上でPRにコメントしてくれます。
terraform-github-actionsの実装 を確認してみると、 sed
コマンドで ------(略
の区切り線を基準に行を削除していました。
terraform-github-actions 同様に sed
コマンドで消しても良いのですが、PR投稿のgithub-script内でついでに整形する実装にします。
steps: - uses: actions/github-script@v1 env: STDOUT: "${{ steps.plan.outputs.stdout }}" with: github-token: ${{ secrets.GITHUB_TOKEN }} # NOTE: 区切り文字で囲まれた範囲のみを出力する script: | const lines = process.env.STDOUT.split('\n') const separator = '-'.repeat(72) let index = lines.indexOf(separator) let outputLines = lines.slice(index + 1) index = outputLines.indexOf(separator) if (index) { outputLines = outputLines.slice(0, index) } const planOutput = '```' + outputLines.join('\n') + '```' const output = `<details><summary>plan:</summary>\n\n${planOutput}\n\n</details>`; github.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: output })
最終的なGitHub Actionsの設定
最終的な設定は下記のようになりました。
steps: - name: Checkout Repo uses: actions/checkout@v2 - name: setup Terraform uses: hashicorp/setup-terraform@v1 with: terraform_version: ${{ env.TF_VERSION }} - name: terraform init run: terraform init - name: terraform plan id: plan run: terraform plan -no-color -lock=false - uses: actions/github-script@v1 if: ${{ !contains(steps.plan.outputs.stdout, 'No changes.') }} env: STDOUT: "${{ steps.plan.outputs.stdout }}" with: github-token: ${{ secrets.GITHUB_TOKEN }} # NOTE: 区切り文字で囲まれた範囲のみを出力する script: | const lines = process.env.STDOUT.split('\n') const separator = '-'.repeat(72) let index = lines.indexOf(separator) let outputLines = lines.slice(index + 1) index = outputLines.indexOf(separator) if (index) { outputLines = outputLines.slice(0, index) } const planOutput = '```' + outputLines.join('\n') + '```' const output = `<details><summary>tf plan:</summary>\n\n${planOutput}\n\n</details>`; github.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: output })
所感
terraform-github-actions から比べるとPRへplan結果を投稿する付近の処理を自前で用意しなければならず、難易度は上昇したように思えました。
ですが、無事に後継の setup-terraform へ移行することができたので、terraformの最新バージョンへの追従する際のActions関連の懸念を減らすことができました。
メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!
■募集ポジションはこちら
https://medpeer.co.jp/recruit/entry/
■開発環境はこちら