Terraform 小技集
皆さん、こんにちは。技術開発グループのn-ozawanです。
最近、YouTubeでマーモットの動画が流れてきて癒されています。
本題です。
前回までの記事で、Terraformの基本的なことをお話ししました。今日はTerraformで環境を構築する際によく使いそうな便利な小技を紹介します。
目次
関数
小技集に入る前に関数についてお話しさせてください。Terraformには多くの組み込み関数が用意されています。以下は公式サイトに記載されている例です。max
関数は受け取った値の中から、最大値となる数値を返却します。
> max(5, 12, 9)
12
Terraformの関数は必ず必要なものではないのですが、Terraformでちょっとしたことをしたい場合にお世話になりますので、覚えといて損はありません。以下に紹介する小技では関数を利用したものになります。
小技集
jsonファイルを参照する方法
環境の情報などをハードコーディングせずに、jsonファイルなどに切り出したいことはあると思います。ここではTerraformでjsonファイルを参照する方法を紹介します。ファイルの内容を取得するにはfile関数を利用します。file関数はファイルの内容を文字列として返却するため、そのままではjsonの中身を扱えません。json形式の文字列からobjectに変換するにはjsondecodeという関数を利用します。
locals {
# sample.jsonの内容 → {"hello": "world"}
sample = jsondecode(file("${path.module}/sample.json"))
}
output "console" {
value = local.sample.hello # コンソールに"world"が出力される
}
モジュールの引数をチェックする方法
引数を受け取るにはvariableブロックを利用します。variableブロックでは受け取る値の型(StringやNumberなど)を指定することは出来ます。型に加えて、例えば特定の値だけを受け取り、それ以外の値が渡されたらエラーとしたい場合はvalidation
を使用します。
variable "az_type" {
description = "Availability Zone の種類"
type = string
validation {
condition = contains(["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"], var.az_type)
error_message = "Allowed values for az_type are \"ap-northeast-1a\", \"ap-northeast-1c\", or \"ap-northeast-1d\""
}
}
上記はAWSのAZ(アベイラビリティーゾーン)の種類を受け取るvariableです。東京リージョンのAZにはap-northeast-1a
、ap-northeast-1c
、ap-northeast-1d
の3つがあります。なので、引数として受け取るAZの種類は上記3つに限定して、それ以外はエラーとしています。
validation.condition
には、受け取った値の検証を行います。true
の場合はOKで、false
の場合はNGとしてコンソールにvalidation.error_message
の内容を表示して処理を停止します。
validation.condition
にて、containsという関数が使われています。第2引数の値が、第1引数のリストに存在する場合はtrue
、存在しない場合はfalse
を返却します。
モジュールの引数(配列)をチェックする方法
では、その引数が配列の場合はどうやってチェックするのでしょうか。答えは簡単でfor文で回せば出来ます。
variable "az_type" {
description = "Availability Zone の種類"
type = list(string)
validation {
condition = alltrue([
for az in var.az_type : contains(["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"], az)
])
error_message = "Allowed values for az_type are \"ap-northeast-1a\", \"ap-northeast-1c\", or \"ap-northeast-1d\""
}
}
for文で受け取った配列を回し、要素ごとにcontains関数でチェック、booleanの配列に変換します。alltrue関数は、引数の配列要素がすべてtrueの場合にtrueを返却します。1つでもfalseが含まれている場合はfalseを返却します。
複数リソースの特定の値を配列にまとめる方法
for_eachなどにより、リソースを複数作成することが出来ます。その作成された複数のリソースから、特定の値を配列として取得したいケースがあります。
例えばAWSでRDS(DB)を構築する際、配置先のSubnetを指定するためにDB Subnet Groupというリソースを作成します。RDSは複数のSubnetを跨いで配置※することが出来るため、SubnetのIDを配列で指定します。
※正確には、RDSを冗長化するためにAZを跨いで配置する、が正しいです。AZごとにPrivate Subnetを作成する必要があり、東京リージョンであれば最大3つのSubnetを作成することになります。
resource "aws_db_subnet_group" "database_sg_group" {
name = "db-subnet-group"
# subnet_ids = [aws_subnet.private["1a"].id, aws_subnet.private["1c"].id, aws_subnet.private["1d"].id]
subnet_ids = [for subnet in aws_subnet.private : subnet.id]
}
resource "aws_db_subnet_group"
のsubnet_ids
で、作成した複数のリソースをfor文で処理して、Subnet IDの配列に変換しています。コメント分はfor文を利用しなかった場合のやり方です。for文を利用した場合と比べ、記述内容が冗長であり、subnetの個数の変更に弱い記述となっています。特別な理由がない限りはfor文を利用した方がいいでしょう。
おわりに
いかがでしたでしょうか。Terraformの小技集を紹介しました。小技と言っても、実際にTerraformで環境を構築しようとすると、よく使うかと思います。
例えばAWS IAMではポリシーをJSON形式で指定しますので、ポリシーをtfファイルにハードコーディングするのではなくjsonファイルで管理するのも良いでしょう。Object型からList型への変換にfor文を利用する方法についても、可読性が上がるだけでなく、本番環境や検証環境などの違いにも柔軟に対処できます。
ではまた。