はじめに
仕事で Terraform を使った Azure のリソース管理をしていた経験を元に、Terraform を触りだす前に知っていたらよかったなと思う点をまとめます。
なお、説明のため、実際に書いたコードをかなり簡略化しています。
(前提としての)ディレクトリ構成
module は1階層にしてネットワークとかストレージ等のリソースの種類毎にざっくり設計しました。
.
├── main.tf
├── variable.tf
├── output.tf
└── modules
├── storage
│ ├── main.tf
│ ├── variable.tf
│ └── output.tf
└── compute
├── main.tf
├── variable.tf
└── output.tf
リソース毎に設定をマップ化する
特に目新しくはないですが、各 module で使う設定値は最初から variable.tf
でマップ化しておくとよいです。最初はあまり変更する気がなくても、結局後から変更することが多いからです。マップのキーは、呼び出し側の属性名をそのまま使うとわかりやすいです。
variable "ubuntu_setting" {
default = {
size = "Standard_D4_v3",
source_image_reference = {
publisher = "Canonical",
offer = "UbuntuServer",
sku = "18.04-LTS",
version = "latest",
},
os_disk = {
storage_account_type = "StandardSSD_LRS",
disk_size_gb = 128,
},
}
}
呼び出し側は、変数の中身を気にすることなく、変数名も variable.tf
を参照することなく書けます。
resource "azurerm_linux_virtual_machine" "vm" {
name = var.vm_name
size = var.vm_setting.size
source_image_reference {
publisher = var.vm_setting.source_image_reference.publisher
offer = var.vm_setting.source_image_reference.offer
sku = var.vm_setting.source_image_reference.sku
version = var.vm_setting.source_image_reference.version
}
os_disk {
name = "${var.vm_name}-disk-os"
storage_account_type = var.vm_setting.os_disk.storage_account_type
disk_size_gb = var.vm_setting.os_disk.disk_size_gb
caching = "ReadWrite"
write_accelerator_enabled = false
}
// etc.
}
module の output をマップ化する
今度は variable.tf
でのマップ化ではなく、output のマップ化です。
Terraform を触りたての頃は module の output をバラして書いていました。
output "name" {
value = azurerm_storage_account.sa.name
}
output "object_id" {
value = azurerm_storage_account.sa.id
}
output "primary_blob_endpoint" {
value = azurerm_storage_account.sa.primary_blob_endpoint
}
output "primary_access_key" {
value = azurerm_storage_account.sa.primary_access_key
}
こうすると main.tf
で別の module に変数を渡すときに縦に長くなってしまいます。
module "compute" {
source = "./modules/compute"
storage_name = module.storage.name
storage_object_id = module.storage.object_id
primary_blob_endpoint = module.storage.primary_blob_endpoint
primary_access_key = module.storage.primary_access_key
}
今はどうしているかと言うと、module の output を profile というマップにまとめて返すようにしています。
output "profile" {
value = {
name = azurerm_storage_account.sa.name,
object_id = azurerm_storage_account.sa.id,
primary_blob_endpoint = azurerm_storage_account.sa.primary_blob_endpoint,
primary_access_key = azurerm_storage_account.sa.primary_access_key,
}
}
こうすると main.tf
で別の module に変数を渡すときに1行しか書く必要がなくなります。また、profile の中身が増えても main.tf
側は変更不要になります。
module "compute" {
source = "./modules/compute"
storage = module.storage.profile
}
modules/compute/main.tf
で呼び出すときは var.storage.name
等と書くだけです。
複数行テキストを output する
Terraform の実行ディレクトリ直下のファイルに output を書くと terraform apply
の実行終了時に output の内容が標準出力されますが、変数名と値しか出力しないと、何を出力しているのか第三者に伝わりづらいですし、なぜ出力しているのかも伝わりづらいことがあります。
readme.md
で丁寧に説明することもできますが、私の場合、output を複数行にして説明を日本語で書くようにしています。
output "output" {
value = <<-EOT
管理者のユーザー名とパスワードを利用者に渡してください。
ユーザー名: ${var.admin_name}
パスワード : ${random_string.admin_pass.result}
EOT
}
フラグで ON/OFF を切り替える
Terraform のコードは、一度書いてしまえばかなりの程度、別用途に流用できます。とはいえ環境が変われば必要なリソースも当然変わります。そんなときは boolean 型のフラグを使います。
variable "is_target_module" {
default = {
storage = true,
compute = false,
}
}
count
で実行回数をコントロールできます。var.is_target_module.compute
が true
の場合に1回実行させるには、下記のようにします。
module "compute" {
count = var.is_target_module.compute ? 1 : 0
source = "./modules/compute"
}
ちなみに、count
とそれ以外の変数は同じインデントで書かれる方が多いみたいです。私の場合は、for 文のような制御構文と見なして、count
以下はインデントを1レベル下げるようにしています。
リストと繰り返し構文で ON/OFF を切り替える
同じ module を2回実行して同種のリソースを2つ構築したいが、片方には一部不要なリソースがある場合、変数にフラグを追加することでも対応できますが、そのために変数が増えるのは嫌なので、私の場合、不要なリソースの設定をリスト化しています。
例えば Azure Storage を2つ構築したいが、File Share は片方にしか要らない場合を考えます。まず main.tf
で module に File Share の設定をリストで渡します。
# ストレージ(「ファイル共有」なし)
module "storage01" {
source = "./modules/storage"
storage_account_name = "numshstorage01"
file_share_setting = []
}
# ストレージ(「ファイル共有」あり)
module "storage02" {
source = "./modules/storage"
storage_account_name = "numshstorage02"
file_share_setting = [{
name = "fileshare01",
quota = 4,
}]
}
module 側は、繰り返し構文で File Share 構築の ON/OFF を切り替えます。count
で実行回数をコントロールできます。
resource "azurerm_storage_share" "ss" {
count = length(var.smb_setting)
storage_account_name = azurerm_storage_account.sa.name
name = var.smb_setting[count.index].name
quota = var.smb_setting[count.index].quota
}
なお、フラグを使うなら count = var.is_file_share ? 1 : 0
みないな書き方になります。
以上