苦しんで習得したTerraformのマイベストプラクティス
2020-06-24
azblob://2022/11/11/eyecatch/2020-06-24-my-best-practices-of-terraform-that-i-learned-through-suffering-000.jpg

先週の関さんの「そのリソース本当に消しても大丈夫? #Azureリレー」に 引き続き、毎週水曜日に Azure 関連の記事を掲載する Azure リレー第17回を担当します。

最近は四日市に行きがちな名古屋事業所の松枝です。
皆さんはTerraformでシステム全体のインフラ構築を自動化したことはありますか?
私は何度かチャレンジする機会をいただき、苦しみ、自分なりのベストな構成を見つけたつもりになりました。
今回は、比較的大規模なTerraformを組む時にどうすると良さそうかを紹介します。

…とはいえ正直、前から見ていた下記のブログで説明いただいている内容の完成度が高いことを身をもって認識した、というのがベースにあります。
https://torumakabe.github.io/post/terraform_azure_sample_201801/

まずは上記を見ていただくのが良いです。
私の苦労したポイントまで興味を持っていただける場合は、次にお進みください。
※ Azureでのリソース作成を想定して記載します

[1] VNetやPublic IPの作成は、リソースグループ横断で作成する

例えば Front DoorとApplication Gatewayをterraformで作成することを考えてみてください。
terraformのprojectは、Front Door用とApplication Gateway用で分けて作るとします。
そうすると、Application GatewayのフロントエンドIP(パブリックIP)はApplication Gateway側で作成し、Front DoorのバックエンドホストにそのIPアドレスを入れることになりますね。

terraformを実行するときは、Application Gateway用のterraformを流してからFront Door用のterraformを流すことになります。依存関係ができてしまい、ちょっと嫌ですね。

しばらくその構成で使っていたところ、Application Gatewayを再作成したくなり terraform destroy でApplication Gateway用の定義を一度削除し、 terraform apply で作成するとしましょう。
これでFront Doorのバックエンドとの接続は途切れます。パブリックIPは別のものが作られ、割り当てられるIPアドレスが変わるので、Front Doorのバックエンドホストの設定が矛盾した状態になります。

このような状態を避けるためには、Public IPは簡単に消えない状態にするべきです。
同様な理由でVNetも簡単には作り替えられません。

VNetとPublic IPの作成のみを実施する、リソースグループ横断の実行単位を用意するのが良いと考えます。

[2] projectsの単位は計画的に

一度に実行するtfファイルの集合は、どの範囲のリソースを対象にすべきなのかが迷いどころになります。

例えばAzure Kubernetes Services(AKS)とAzure Firewallを組み合わせて使用する場合、両者の関係が深くなるので一度で作りたくなりました。
しかしいざ組み合わせてみると、AKSのサイズ調整等でAKSの再作成をしたいときにFirewallとの関係が邪魔になり、実行しにくい状態でした。
さらにAKSの作成もFirewallの作成もそれなりに実行時間が長くかかるので、取り回しが難しいです。

また、KeyVaultやContainer Registryなど、一度作ったら簡単には削除できないリソースはまとめて作っておきたいところです。
今のところ、下記の流れで実行単位を組むのがよさそうだと思っています。

  • 全体のリソースグループの作成 (terraformでやっていいかは要検討)
  • 全体のVNet、サブネット、VNetピアリング、Public IPの作成
  • LogAnalyticsの作成
  • KeyVault、Container Registryの作成
  • その他のリソース作成 (例えばリソースグループ単位、必要に応じてさらに分割)

[3] modulesのvariableのデフォルト値は、本番環境を想定した内容にする

冒頭で紹介したMS真壁さんのブログではworkspaceで開発/ステージング/本番を用意する方針のサンプルでした。
ただ、私が依頼された内容に「開発でも複数の環境を作ってほしい」という話があり、そういった場合はworkspaceで環境番号のようなものを設定すると良いと思います。

となると、projectsのフォルダをdev/stage/prodとかで細分化してほぼ同じtfファイルを書くことになります。
ただ、開発環境ではリソースのSKUを低めに設定したりして料金を抑えたくなります。
この場合はmodulesをどう書くべきでしょうか?

個人的には、本番環境を想定した設定値をデフォルト値で設定しておいて、projects側でSKUを調整する形が良いと思います。
そうしておけば、本番環境を構築したら設定間違えていた、という危険な事態を回避しやすいです。

[4] 大事なリソースにはロックをかける

関さんの記事で記載されている通りなので詳細は省略します。
リソースグループにも設定しておきたいですね。

まとめ

ほかにもリソース名の作成部分などで細かい工夫はしていますが、上記で紹介した辺りを意識して組めば再実行が安全に、容易にできる状態になります。
大規模に組んでもそれなりに見通しやすい状態になりました。

これでもまだ、リソース名の設計を間違えると改修が大変になって辛いです。
社内のディスカッションでは、いっそのことリソース名は完全にランダム文字列にして、タグに設定した値でリソースの用途を特定する案も出ましたが、うまく運用していけるのか十分な検討が必要です。

引き続きterraform職人?として日々勉強ですね。