はじめに
この記事は terraform Advent Calendar 2022 の19日目です。
IaCツールの1つであるTerraformのディレクトリ構成をどうするかについては、Terraformを利用しているエンジニアであれば一度は考えたことがあるのではないでしょうか。
私も、2年前のAdvent Calendarにて投稿させていただきました。 (記事リンク)
さて、Terraformのディレクトリ構成で検討するべき項目として、「複数環境(Production環境とStaging環境など)が存在する状況でのRootディレクトリの構成」が挙げられるかと思います。
これについて、
「Workspace機能は使うべきではない」
「Production環境とStaging環境はディレクトリで分けるのが良さそう」
「でもProduction環境とStaging環境のコード差異の吸収がめんどくさく、何ならちょこちょこ事故る」
...みたいな記事が散見されておりました。
しかし、結局の所 「ディレクトリを分けずに環境差分を表現し実行できれば一番」 だと思いませんか?
私はそうしてしまいたいです。
というわけで、なんとか実現できないかを検討してみました。
本記事では、 -backend-config
と -var-file
の2つのoptionを活用して、単一のTerraform Rootディレクトリで複数環境を制御する方法を示します。
前提条件
以下を前提条件とします(違う文脈の場合は適宜読み替えたり応用したりしてください)
- prd環境とstg環境の2環境を単一のTerraform Rootディレクトリで表現したい
- Terragrunt は使わない
結論
Terragrunt使うほうが楽な気がするけどまだ検証は終わっていない
素のTerraformだけで頑張る場合、ディレクトリ構成を以下のようにします:
(repository)
├─ root # 本文で ${TERRAFORM_ROOT} を指す
│ ├─ envs
│ │ ├─ prd.tfbackend # backendの設定として渡す値
│ │ ├─ prd.tfvars # variableとして渡す値
│ │ ├─ stg.tfbackend
│ │ └─ stg.tfvars
│ ├─ state.tf
│ ├─ variables.tf
│ ├─ ...
: :
Terraform Initでは以下のコマンドを叩きます:
cd ${TERRAFORM_ROOT}
terraform init -backend-config=envs/${ENV}.tfbackend
Terraform Plan/Applyでは以下のコマンドを叩きます:
# applyの場合
cd ${TERRAFORM_ROOT}
terraform apply -var-file=envs/${ENV}.tfvars
サンプルコードは、リンク先のGitRepositoryを参照してください。
(サンプルコードは動作可能なようにlocal backendを利用しています。 解説においては実戦を想定しs3 backendを利用しています)
hkak03key/advent-calendar-sample-code//terraform-2022-root-dir
解説
外部ファイルを利用した変数設定と、その制約
Terraformを利用したことがあれば、 「実行時に外部から変数を注入したい」 という気持ちに駆られたことがあるかと思います。
これは、 variable
を適宜定義し terraform apply -var-file=${FILE_PATH}
で可能です。
この流れで 「外部から変数注入可能なら、backendについても変数で制御したい」 と思ったことがあると思います。
そして、こんなコードを書くわけです:
terraform {
backend "s3" {
bucket = "${var.account_name}-${var.env}-terraform-backend"
key = "terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "${var.account_name}-${var.env}-terraform-backend"
}
}
このときのTerraform Initの実行結果はこちら:
$ terraform init
Initializing the backend...
╷
│ Error: Variables not allowed
│
│ on state.tf line 3, in terraform:
│ 3: bucket = "${var.account_name}-${var.env}-terraform-backend"
│
│ Variables may not be used here.
...
そして 「はーーーーーマジかーーーーーーーーーーー」 ってなるところまでお約束だと思っています。
このように、Backendの設定には変数を利用できないという悲しい現実があります。
そして、「Production環境とStaging環境はディレクトリで分けよう」といったノウハウに繋がっていきました。(私が携わった環境もそうなってるものが大半です)
-backend-config
optionの活用による、 backendに対しての外部ファイルを利用した変数設定
しかし、Production環境とStaging環境でディレクトリが分かれているのは、正直あまり嬉しくはありません。
そして、ドキュメントを読むと、 -backend-config
なるoptionが存在します。
これを利用して、外部からbackendの設定を与えることが可能です。
利用方法を以下に示します:
state.tf
の定義
まず、 ${TERRAFORM_ROOT}/state.tf
にはbackendとして何を利用するかのみ記述します。
backendのパラメータは記述しないことに注意してください:
terraform {
backend "s3" {
# 本section内に記述する設定は .tfbackend ファイルに記載
# initは以下のコマンドで実行する必要がある:
# `terraform init -backend-config={{.tfbackend ファイルパス}}`
}
}
${ENV}.tfbackend
の定義
次に、 ${TERRAFORM_ROOT}/envs/${ENV}.tfbackend
に、hcl形式でbackendのパラメータを記述します。
ここではprd環境を想定します:
bucket = "some-product-prd-terraform-backend"
key = "terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "some-product-prd-terraform-backend"
terraform init
の実行
最後に、コマンド terraform init -backend-config=envs/${ENV}.tfbackend
を実行します。
cd ${TERRAFORM_ROOT}
terraform init -backend-config=envs/prd.tfbackend
コマンドが完了すれば成功です。
──
stg環境のbackendを設定したい場合は、 ${TERRAFORM_ROOT}/envs/stg.tfbackend
を準備し実行します。
このとき、既に異なる環境で terraform init
されている場合は -reconfigure
optionが必要になるので注意してください。
cd ${TERRAFORM_ROOT}
# 既に terraform init した環境と異なる環境について terraform init する場合は -reconfigure optionを与える
terraform init -backend-config=envs/stg.tfbackend -reconfigure
まとめ
単一のTerraform Rootディレクトリで、複数環境の terraform init
が可能であることを示しました。
そして、 terraform init
時に -backend-config
optionを、 terraform apply
時に -var-file
optionを利用することで、単一のTerraform Rootディレクトリで複数環境のDeployが可能です。
一方で、課題もいくつかあります:
- 設定ファイルが
.tfbackend
.tfvars
の2種類がどうしても必要- どうしようもないけどダサい
- Route53のような、 「保持する環境すべての中で唯一であるべきリソース」 を管理する場合は、単一のTerraform Rootディレクトリではかえって都合が悪い
- こういうものについてはディレクトリを分けて対応するべき
そもそも、 Terragrunt のようなツールも出ており(Advent Calenderでも取り上げられていました: Terragrunt 導入で Terraform コードを DRY にしてみた)、まだ完全に検証は終わってないのですが恐らくいい感じにしてくれそうなので 「素のTerraformでここまで頑張るのか?」 というのは 「それは、そう」 という感じかもしれません。
しかし、「素のTerraformで頑張るとこんな感じになるよ」ということは心の片隅にあっても良いと思っており、Terraformのディレクトリ構成を決定する上での一つのヒントになれば幸いです。
──
僕らのTerraformのディレクトリ構成の旅はまだまだ続く。
宣伝
その1: YouTube出ました
データ分析系のサービスの中でも特に激アツな Snowflake のコミュニティである Snowflake Japanユーザーグループ のYouTubeに、DevOps回でお呼ばれしたので出演してきました!
DevOpsということでTerraformのお話も盛り上がってるので、是非ご覧ください!
https://www.youtube.com/watch?v=Hd4WWHmjjDw
その2: お仕事のご相談など受け付けております
個人事業主を副業でやってるので、Terraformの活用やデータ分析に関する技術支援、その他何かご用命があればご相談ください!