2021、年の暮れからこんにちは。 サービス基盤本部インフラ部の @grezarjp です。
2021年も終わろうとしているこのときに、嬉しいニュースがあります。Terraformのrefactoringがかなりやりやすくなりました。今日はTerraform v1.1.0から導入されたmoved blocksという機能によってTerraformのrefactoringがどのように楽になったのか、その機能とともに紹介したいと思います。
v1.1.0で導入されたmoved blocksについて
まずはTerraform v1.1.0のリリースノートをご覧ください
https://github.com/hashicorp/terraform/releases/tag/v1.1.0
moved
blocks for refactoring within modules: Module authors can now record in module source code whenever they've changed the address of a resource or resource instance, and then during planning Terraform will automatically migrate existing objects in the state to new addresses.
moved blcoksが導入され、module内でplan時点でのstateの移動が可能になったとあります。
これまでもTerraformではresource名やmodule名などを変えるようなrefactoringを伴うときに、リソースを再作成しないようにするために terraform state mv
によってコードを変更後にstateの移行を行うことができました。しかし、terraform state mv
にはいくつかの問題点があります。
- CLIベースの操作で、宣言的に記述できない
- Refactoring後にPlan時点で差分がないことを確認したいが、その場合mainのブランチにマージする前に
terraform state mv
する必要がある
1についてはCLIベースで手続き的にstateの移行操作を行うしかなく、変更量が多いときには作業量が多くなりミスも発生しやすくなります。
2はもっと大きな問題です。普通Terraformのコードをrefactoringしたときはrefactoring前後でTerraform Planの結果に差分がないことを確認してrefactoringが安全に行えているのかどうかを判断するはずです。ただし、これを達成するためにはmainブランチにマージする前の状態で terraform state mv
を行い、stateを破壊的に操作する必要があります。これは安全な状態であることを担保するために安全でない操作をするというある種の矛盾を伴うものでした。
moved blocksがもたらしたもの
基本的な使い方は こちらにまとまっています。moved blocksの構文はシンプルです。変更前のobject名と変更後のobject名をそれぞれfromとtoに対応させて書きます。
moved { from = aws_instance.a to = aws_instance.b }
複数のresourceを変更している場合にはその数だけmoved blocksを書くことになります。moved blocksが定義されている場合、TerraformはPlan実行前に
- fromで指定されたobjectがstate内にあるか確認する
- もし1でstate内に既存のobjectが確認できればTerraformはそのobjectをtoで指定されている名前にrenameして扱う
という処理をはさみます。2の操作は内部的なものでstateへの実際の変更はapply時に反映されるためplan時点では安全な操作になります。このような内部的なstateのrenameが行われることで破壊的な変更を伴わずにrefactoring後のコードでTerraform Planに差分がないことを確認できます。また、Terraformのコードによって宣言的にstateの移行を記述できるためどのような変更が行われるのかが明確でありレビューもしやすくなります。
実際にmoved blocksを使ってrefacotringを行う際には以下のような手順になるでしょう
- Terraformコードのrefactoringを行う
- 変更したobjectについてはmoved blocksでstateの移行を記述する
- Terraform Planを実行して変更後のコードに差分がないことを確認する
- もしPlanで変更に起因する差分が会った場合は2と3を繰り返す
- Terraform Applyして実際にstateへ変更を反映する
Tips?
このupdateを受けて、実際にmoved blocksを使ってTerraformの大規模なrefacotringを行ってみたのですが変更量が多い場合moved blocksとして記述する対象が多くなるのでそこはまだ大変だと感じました。とはいえ、これまでの terraform state mv
による操作よりは格段に楽で安全になっていますし、私の場合はコードの変更差分からmoved blocksを生成する雑なスクリプト等を書いて対応したりしました。誰かの参考になればと思い、私が使ったスクリプトを置いておきます。Terraformをrefactoringしたコードをgitにコミットした上で
- 以下のファイルを適当な名前で保存
$stdin.readlines.each_slice(2) do |a, b| puts <<EOF moved { from = #{a.chomp} to = #{b.chomp} } EOF end
git show | grep 'resource "' | grep -v @@ | sed -e 's/.*resource "\(.*\)" "\(.*\)".*$/\1\.\2/' | ruby moved-blocks.rb >> moved_blocks.tf
まとめ
これまでTerraformでrefacotringをする際にはstateの変更が必要になるというのが大きなネックとなっていましたが、moved blocksの登場によりrefactoringで発生するすべての変更をTerraformのコードとして定義できるようになったのでより安全に、レビューしやすい状態でTerraformのrefactoringを行えるようになりました。Terraformの大きな課題だった部分に一定の改善が見られたのは非常に嬉しいニュースですね。ではでは。
May your Terraforming be happy!
マネーフォワードでは、エンジニアを募集しています。 ご応募お待ちしています。
【サイトのご案内】 ■マネーフォワード採用サイト ■Wantedly ■京都開発拠点
【プロダクトのご紹介】 ■お金の見える化サービス 『マネーフォワード ME』 iPhone,iPad Android
■ビジネス向けバックオフィス向け業務効率化ソリューション 『マネーフォワード クラウド』
■だれでも貯まって増える お金の体質改善サービス 『マネーフォワード おかねせんせい』