この記事はBASE Advent Calendar 2019 22日目の記事です。 devblog.thebase.in
こんにちは。最近はCorporate Engineeringをやっている山根 (@fumikony)です。すこし前まで、即時に資金調達ができる金融サービス「YELL BANK(エールバンク)」のインフラまわりに関わっていました。
今回は「YELL BANK」のインフラにおけるTerraform運用について紹介します。
目次
概要
「YELL BANK」のインフラはAWS上に構築していて、Terraformによるコード管理を行っています。Terraformのコード(tfファイル)はGitHubで管理し、変更を加えたいときはプルリクエストを作成します。普通ですね。
さて、Terraformをプルリクエストベースで運用する場合、いくつか考えることが出てきます。具体的には
- 実行する場所
- レビューのやりかた
- プルリクエスト作成から
terraform apply
までのワークフロー
です。
実行する場所について
「YELL BANK」では、 terraform plan
をAWS CodeBuild上で実行し、terraform apply
はTerraform実行用のEC2インスタンス上で実行しています。
「YELL BANK」の開発では主にCircleCIを使っているのでTerraformもCircleCI上で実行することも考えました。しかし、CircleCIにあまり強いIAMの権限を付けることがためらわれたので、CodeBuildを選択しました。
レビューのやり方について
tfファイルの変更をプルリクエストにすると、その差分としては当然、tfファイルのみが出てきます。しかしながらレビューの際には terraform plan
の結果を確認したいものです。
はじめのころはプルリクエストに terraform plan
の結果を(手で)貼ってレビューしたりしていたのですが、ここにCodeBuildとtfnotifyを導入しました。 terraform plan
の結果がプルリクエストのコメントとして(自動的に)返ってくるようになり、レビューがやりやすくなりました。
プルリクエスト作成からterraform applyまでのワークフロー
現在のところ、「YELL BANK」のTerraform変更のフローは以下のようなものになっています。
- ブランチを切ってtfを編集
git commit
,git push
- プルリクエストを作成
terraform plan
の結果がプルリクエストのコメントとして返ってくる
- レビュー
- マージ
- Terraform実行サーバ上で
terraform apply
詳細
以下、上でのべた構成の各部分について、詳しく説明していきます。
tfnotifyについて
tfnotify はメルカリさんがOSSとして公開しているツールで、teffaform plan
や terraform apply
の出力をGitHubやSlackなどに通知するためのものです。CIの中で使う想定で作られています。
以下に設定ファイルの例を示します。これはCodeBuildからtfnotifyを使用して、terraform plan
の結果をGitHubに通知するための設定です。
.tfnotify.yaml
--- ci: codebuild notifier: github: token: $GITHUB_TOKEN repository: owner: "orgname" name: "reponame" terraform: plan: template: | {{ .Title }} for Production <sup>[CI link]( {{ .Link }} )</sup> {{ .Message }} {{if .Result}} <pre><code> {{ .Result }} </pre></code> {{end}} <details><summary>Details (Click me)</summary> <pre><code> {{ .Body }} </pre></code> </details>
これを terraform
コマンドを実行するディレクトリに置いておくことで、template
に記載した内容のコメントがプルリクエストに通知されます。{{ .Title }}
などはtfnotifyが埋めてくれます。詳細はtfnotifyのREADMEをご覧ください。
AWSアカウントとTerraformディレクトリ構成について
「YELL BANK」のインフラには本番(prd), ステージング(stg), 開発(dev)の環境ごとにAWSアカウントがあります。このうちprdとstgをTerraform管理下に置いています。
Terraformのディレクトリ構成としては、 - 環境ごとに別のディレクトリを作成 - リソースの種類ごとにtfファイルを作成 という方針をとっています。
具体的には以下のようなディレクトリ構成になっています。
. ├── .gitignore ├── README.md ├── aws-basebank-prd │ └── bb-prd │ ├── .tfnotify.yaml │ ├── README.md │ ├── cloudfront.tf ... │ └── vpc.tf ├── aws-basebank-stg │ └── bb-stg │ ├── .tfnotify.yaml │ ├── README.md │ ├── cloudfront.tf ... │ └── vpc.tf ├── bin │ └── dir_is_changed └── buildspec.yml
buildspec.yml
がCodeBuildの設定ファイル、.tfnotify.yaml
がtfnotifyの設定ファイルです。
CodeBuildについて
AWS CodeBuildは、AWSのCIです。
CodeBuildを実行のトリガとしてはGitHubのプルリクエストの作成と更新を使います。 また、prd,stgそれぞれのAWSアカウントにおいてCodeBuildを設定しています。
これは実際に使用している buildspec.yml
です。
buildspec.yml
phases: install: runtime-versions: golang: 1.12 commands: - git clone https://github.com/tfutils/tfenv.git ~/.tfenv - ln -s ~/.tfenv/bin/* /usr/local/bin - tfenv install 0.12.6 - wget https://github.com/mercari/tfnotify/releases/download/v0.3.1/tfnotify_v0.3.1_linux_amd64.tar.gz - tar xzf tfnotify_v0.3.1_linux_amd64.tar.gz - cp tfnotify_v0.3.1_linux_amd64/tfnotify /usr/local/bin/ - cp bin/dir_is_changed /usr/local/bin/ build: commands: # ref. https://blog.hatappi.me/entry/2018/10/08/232625 - | if dir_is_changed $TERRAFORM_DIR; then cd $TERRAFORM_DIR terraform init -no-color terraform plan -no-color | tfnotify plan fi
ここで行っているちょっとした工夫として、dir_is_changed
と $TERRAFORM_DIR
があります。
$TERRAFORM_DIR
はCodeBuildで設定している環境変数で、terraform plan
を実行するディレクトリを指定します。
また dir_is_changed
は以下のようなシェルスクリプトで、引数にあたえたディレクトリ以下に変更があったかどうかを判定します。
dir_is_changed
#!/bin/bash # ref. https://blog.hatappi.me/entry/2018/10/08/232625 DIFF_FILES=(`git diff origin/master --name-only --relative=${1}`) if [ ${#DIFF_FILES[@]} -eq 0 ]; then exit 1 else exit 0 fi
これによって、prdかstg、変更があった方だけでplanを実行するという振る舞いを実現しています。CodeBuild自体はプルリクエストの作成・更新をトリガとして常に両方の環境で動くのですが、変更が無いほうでは何もせずに終了します。 ちなみに、この方法では一つのプルリクエストでprdとstgの両方を変更するとうまく動かないため、別々のプルリクエストにしておく必要があります。
せっかくなのでCodeBuildの設定画面のスクリーンショットも貼っておきます。よかったら参考にしてください。
実行例
下図は、CodeBuild上でterraform plan
が実行され、その出力がtfnotify
経由でプルリクエストコメントとして通知されている様子です。
Details (Click me)
というところをクリックすると、びろ〜んと伸びてterraform plan
の出力が出てきます。
今後の発展など
今のところはCodeBuildで実行するのは terraform plan
までにとどめており、terraform apply
はサーバ上で手動実行しています。apply までやってしまいたい気持ちはありましたが、
- GitHubでプルリクエストをマージしただけで本番インフラが変更できてしまうのはちょっと怖い
- 手動でAWSリソースを作ったあとで
terraform import
して辻褄をあわせるようなケースが、たまに有る
というのがあり、いったんplanまでにしました。 上については、applyの前に人間による承認をはさみたいのでCodePiplelineにするのがよいだろうか?🤔 と思っていますが未検証です。 下については、そういうことをなるべくしないというのと、それようの場所をそれはそれで用意した上で、普段はCIに任せるのが良いかなあと思っています。
おわりに
若干とりとめがなくなりましたが、「YELL BANK」のインフラにおけるTerraform運用について紹介しました。 tfnotifyはかなり便利で、オススメできるツールだと思います。
最後に、同じようなジャンルのツールを紹介しておきます。まだ詳しく調べていないのですが、面白そうなので機会を見てさわっておきたいところです。CI+tfnotifyの構成を検討する場合は、これらも検討に入れておくといいと思います。
- Atlantis
- これはGitHubのプルリクエストコメントにコマンドを書くと裏でterraformを実行してくれる感じのツールです。
- Terraform Cloud
- Terraform開発元のHashiCorp自身が運営しているSaaSです。
さて明日は、BASE BANKの清水さんとProduct Managementの山田さんです。お楽しみに。