環境が増えてきたときはもちろん、リソース間の影響度を減らすためにstateを分割するというのはTerraformを利用しているとよくあることだと思います。
このstateが増えたときの問題に対処するため、state管理の方法をまとめてみました。ぜひ参考にしてみてください![]()
stateが増えると起きること
まず、そもそも何が起きるねんという方もいるかと思うので、そこから解説します。
例えば環境を複数作る場合、moduleを使えばmain.tfは共通化できますが、provider.tf、backend.tf、terraform.tfなどの設定は、stateを持つ環境ごとに用意する必要があります。
結論
結論から書きます。
管理方法はタイトルの通り、modules、backend-config、workspaces、Terragruntの4つで比較してみました。
上記4つの比較結果、基本はmodulesのみの運用でいいと思いました。その上で環境が大量に増えることと、環境差分がある程度見込めるのであれば、Terragruntを導入してもいいだろうというのが私の結論です。
backend-configやworkspacesは使えないということはないものの、利用シーンはかなり限定されるかなと思います。
比較表
作ってみました。
- root共通化:root moduleでいかに同じコードを書かない(DRY)で済むか
- コード量:純粋なコード量が少なく済んでいるか
- 自由度:共通化することで失われる自由度 / またはその自由度を利用するための手間
| 項目 | modules | backend-config | workspaces | Terragrunt |
|---|---|---|---|---|
| root共通化 | × | △ | ◯ | ◯ |
| コード量 | × | △ | ◯ | △ |
| 自由度 | ◯ | × | △ | △ |
管理方法
では実際に4つの管理方法である、modules、backend-config、workspaces、Terragruntを確認していきましょう。
今回使ったコードはこちらのリポジトリで確認できます。
modules
まずはmodulesからです。これは管理方法というかすべての基準になる、デフォルトみたいなものだと思ってください。後述の管理方法がイメージしやすくなるようにあえて書いておきます。
ディレクトリ構成
.
├── env1
│ ├── main.tf
│ ├── provider.tf
│ ├── terraform.tf
│ └── terraform.tfstate
├── env2
│ ├── main.tf
│ ├── provider.tf
│ ├── terraform.tf
│ └── terraform.tfstate
└── modules
└── s3-bucket
├── main.tf
└── variables.tf
「stateが増えると起きること」で解説した通り、いくつかのディレクトリが重複してしまっています。またこれらは中身がまったく同じファイルです。実際にはenv配下に.terraformがあってそこに大容量のproviderのファイルが存在します。
backend-config
次はbackend-configです。これはinitすればstateを自由に切り替えることができる機能です。
ディレクトリ
.
├── backend.tf
├── backends
│ ├── bucket_1.backend
│ └── bucket_2.backend
├── main.tf
├── provider.tf
├── terraform.tf
├── terraform.tfstate.d
├── tfstate
│ ├── bucket_1.tfstate
│ └── bucket_2.tfstate
├── tfvars
│ ├── bucket_1.tfvars
│ └── bucket_2.tfvars
└── variables.tf
コマンド
terraform init -backend-config=backends/bucket_1.backend
terraform apply -var-file=tfvars/bucket_1.tfvars
tfvarsを持つとファイルを2つ作らないといけないし、コマンド内でもファイル指定が必要になるのであまりいいとは言えなさそうです。逆に言えば変数を持たない完全同一の環境を複製したりするのであれば、使ってもよさそうです。
workspaces
前提として、環境をきっちり分けたい用途には向かないので、ライトに使うものだと考えましょう。
重要:ワークスペースは、システムの分解や、個別の認証情報とアクセス制御を必要とするデプロイメントには適していません。詳細と推奨される代替手段については、Terraform CLI ドキュメントの「ユースケース」を参照してください。
ディレクトリ
.
├── backend.tf
├── main.tf
├── provider.tf
├── terraform.tf
├── terraform.tfstate.d
│ ├── 3
│ │ └── terraform.tfstate
│ └── 4
│ └── terraform.tfstate
├── tfvars
│ ├── bucket_3.tfvars
│ └── bucket_4.tfvars
└── variables.tf
コマンド
terraform init
terraform workspace new 3
terraform workspace select 3
terraform apply -var-file=tfvars/bucket_3.tfvars
ディレクトリやコマンドは、わかりやすくて綺麗なだけに惜しいですね。使い勝手自体はよさそうなので、個人で使ったり、サービスとして運用しないものなどには使っていいかと思います。
Terragrunt
Terragruntは他の管理方法とは少し毛色が違っていて、まずインストールが必要です。また記述の仕方も独特なものになっているので、その理解も必要になります。
ディレクトリ
.
├── bucket_5
│ └── terragrunt.hcl
├── bucket_6
│ └── terragrunt.hcl
├── modules
│ └── s3-bucket
│ ├── main.tf
│ └── variables.tf
└── root.hcl
コマンド
# 環境単体
terragrunt init
terragrunt apply
# 環境全体
terragrunt run-all init
terragrunt run-all apply
Terragruntも構成やコマンドはシンプルです。共通化されたものはroot.hcl、固有の変数などはterragrunt.hclに書いています。また、run-allで環境一括操作もできたりします。
ただ、コードの中身が少し独特なので実際にみてみましょう。
remote_state {
backend = "local"
config = {
path = "${path_relative_to_include()}/terraform.tfstate"
}
}
# プロバイダーキャッシュの共有設定
terraform {
extra_arguments "plugin_cache" {
commands = [
"init",
"plan",
"apply",
"destroy",
]
env_vars = {
TF_PLUGIN_CACHE_DIR = "${get_parent_terragrunt_dir()}/.terraform-plugin-cache"
}
}
}
generate "versions" {
path = "versions.tf"
if_exists = "overwrite"
contents = <<-EOT
terraform {
required_version = "= 1.14.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "6.23.0"
}
}
backend "local" {}
}
EOT
}
generate "provider" {
path = "provider.tf"
if_exists = "overwrite"
contents = <<-EOT
provider "aws" {
region = "ap-northeast-1"
profile = "test-profile"
}
EOT
}
include "root" {
path = find_in_parent_folders("root.hcl")
}
terraform {
source = "../modules/s3-bucket"
}
inputs = {
name = "5"
}
おわかりいただけたでしょうか。EOTがあったりして少しクセがあります。また、providerバイナリの共有には、コメントアウトの# プロバイダーキャッシュの共有設定箇所の記述が必要でした。
以上です!結論は冒頭に記述したのでここまで読んだら、改めて結論を読んでいただければと思います。
本記事で記載した管理方法を理解して、自分の環境に適切なstate管理方法を選択しましょう![]()
※ 補足 / Terraform Stacks
HCP Terraformであれば、Terraform Stacksというのもあります。参考までに。