Terraform Cloud の terraform バージョンアップを GitHub Actions で自動化する
Terraform Cloud がサービス開始して約1年、 state file の保存のみならず、 plan
と apply
の実行環境としてもバリバリ使わせてもらっている。ちょっと面倒なのが、 plan 等を実行する workspace の Terraform バージョン設定である。常に latest
を使うというアグレッシブな設定もできるが、そうしない限りは手動でバージョンアップが必要になっている。
まぁガンガン latest
にしていくのも考え方によってはありかもしれないが、メジャーバージョンアップ( Terraform の場合 0.12 → 0.13 をメジャーバージョンアップと呼びたい)までされてしまうのは抵抗がある人も多いのではないだろうか。そもそも Terraform には remote config の中にバージョン指定を出来る箇所があり、自分の場合はこんな感じで 0.12 台のみを許可している。
terraform {
backend "remote" {
hostname = "app.terraform.io"
organization = "sample"
workspaces {
name = "sample"
}
}
required_version = "~> 0.12.0"
}
望むらくは、この required version
をもとにしていい感じにバージョン設定してほしい。なのでそういう GitHub Actions を作った。
terraform-cloud-updater
input として最低限、対象の Terraform ファイルが保存された working_dir
を指定し、環境変数 TFE_TOKEN
で Terraform Cloud の API トークンを渡してあげれば動作する。
on:
push:
branches:
- master
jobs:
tf_cloud_update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: check update
id: check
uses: chroju/terraform-cloud-updater@v1
with:
working_dir: ./terraform
env:
TFE_TOKEN: ${{ secrets.TFE_TOKEN }}
- name: result
run: echo "${{ steps.check.outputs.output }}"
if: "${{ steps.check.outputs.is_available_update == 'true' }}"
デフォルトの設定だと workspace のバージョンアップまでは自動で行わず、新しいバージョンが見つかったら outputs.is_available_update
の値が true
になり、バージョン情報が outputs.output
にセットされるだけだ。あとは is_available_update
で条件分岐して、例えば slack などで通知する方式を想定している。 comment_pr
という input を true
にすれば、 Pull request をトリガーとして使った際にコメントで通知してくれる機能も作ってはあるが、バージョンチェックであれば cron 形式で定期実行するほうがいいだろう。
input の auto_update
を true
にすることで、自動的に更新まで行ってくれる。その際、 required version との整合性を確認し、整合しない場合には更新は行わず、通知だけが行われる。以下は comment_pr
を true
にした場合のサンプルだが、 outputs.output
からも同様のメッセージが取得できる。
実装
go-tfe
Terraform Cloud の API ライブラリは hashicorp が公開している。名前が tfe
になっているが、これは Terraform Enterprise と Cloud の共通 API ライブラリだからであって、 Cloud で特に問題なく使えた。
ちなみに Go で CLI ツールとして書いているので、この Action のもとになっているレポジトリを build すれば、ローカルで実行する CLI としても使うことができる。
$ terraform-cloud-updater -h
Usage: terraform-cloud-updater [--version] [--help] <command> [<args>]
Available commands are:
check Check if new Terraform version is available
update Update Terraform cloud workspace terraform version
required version の処理
一番面倒くさかったのが required version だった。セマンティックバージョニングはいわゆる小数ではなく、ドットを2つ挟んだ数値形式なので、単なる数値比較を行なうことができず、逐一ロジックを組んでいった。また required version を示すオペランドの中には、 ~> 0.12
(0.12.0 以上かつ 0.13.0 未満の意)といった複数の意味をはらんだものもあり、これも自前で判定ロジックを組んだ。
と、いろいろ書いた末に「セマンティックバージョニングをよろしくやってくれるライブラリあるんでは?」と思って探してみたら当の hashicorp から公開されていたわけなのだが。勉強になったのでいいか、と思いつつ、こちらも比較で見てみようと思っている。
初めての GitHub Actions
GitHub Actions 自体はよく使っているものの、自分で Action を作るのはこれが初めてだった。ここでは詳細な作り方などには触れないが、 Action を実行する Dockerfile と entrypoint.sh を書き、あとはメタ情報を定義した action.yml を設置するだけでよいので、非常にお手軽に感じた。ちなみに Action は JS か Docker で作れるのだが、後者を選んだのは単に JS が書けないから。書けるのであれば実行速度などを鑑みても JS のほうがいいと思う。
なお、 GitHub Actions は GitHub Marketplace で公開ができる。そのための操作も非常にシンプルで、レポジトリのルートに action.yml を置くと勝手に判定されて、 Marketplace で公開するためのボタンが表示されるようになっていた。
Terraform のバージョン管理という根深い問題
Terraform のバージョン管理問題はなかなか根深い。というのも Terraform の仕様上、一度使用したバージョンより古いバージョンに戻ることはできないようになっているからだ。そのため複数の Terraform レポジトリを扱っている場合、バージョンは required version
に従って一括で揃えられるようにしたいという欲求が大きい。
複数の Terraform バージョンを切り替えるためのコマンドラインツール tfenv においても、 tfenv doesn't read the required_version from conf.tf · Issue #124 · tfutils/tfenv ということで、 required version に則って自動的に切り替えてほしいという issue が挙がっており、このあたりは悩んでいる人が多いのではないかと推察している。