TL;DR
- Terraform のコードは
resource、data、variable、locals、module、outputの各ブロックで組み立てる。 - 同じ種類のリソースを複数作るには
countかfor_eachを使う。countは要素の削除で意図しない作り直しが起きやすい。
内容
resource
resource は、インフラを構成するリソースを定義する。リソース種別とリソース名を指定し、この組み合わせはステート内で一意でなければならない。
リソースそのものの設定ではなく、振る舞いを決める引数をメタ引数と呼ぶ。depends_on はリソース間の依存関係を明示する。lifecycle はリソースの作成・削除・変更時の挙動を変えるもので、削除を禁止する prevent_destroy、削除の前に新しいリソースを作る create_before_destroy、変更を無視する属性を並べる ignore_changes、再作成のきっかけになるリソースを並べる replace_triggered_by を指定できる。
provider は、使うプロバイダを指定する。aws_vpc のようなリソースを書けば AWS プロバイダが暗黙に使われ、リージョンなどの設定も暗黙に決まる。1 つのコードで複数のリージョンや AWS アカウントを操作するには、alias を付けたプロバイダを定義し、リソースごとに明示する。
provider "aws" {
alias = "ap_northeast_1"
region = "ap-northeast-1"
}
provider "aws" {
alias = "us_east_1"
region = "us-east-1"
}
resource "aws_vpc" "vpc_us_east_1" {
provider = aws.us_east_1
}data
data は、Terraform の外や別のステートで定義された情報を参照する。次のように書くと、data.aws_vpc.vpc.id のように VPC の設定を取得できる。
data "aws_vpc" "vpc" {
tags = {
ServiceName = "web"
Env = "prod"
}
}variable
variable は、resource や data に外から値を渡すための変数を定義する。値は -var=変数名=値 か、変数名=値 を並べたファイルを -var-file=ファイルパス で渡す。
型には、何でも代入できる any(基本的に使わない)、number、string、bool のほか、次の複合型がある。
object: 決められたキーと、それぞれ決められた型の値を持つmap: 任意のキーと、決められた型の値を持つlist: すべての要素が同じ型の配列tuple: 位置ごとに型が決まった配列
variable "personal_information" {
type = object({
name = string
age = number
address = string
})
}
variable "tags" {
type = map(string)
}
variable "lst" {
type = list(number) # lst = [1, 2, 3]
}
variable "tpl" {
type = tuple([string, number, bool]) # tpl = ["one", 2, true]
}locals
locals はローカル変数を定義する。リソースや変数、他のローカル変数の値から新しい値を作るときに使う。主な使い道は、複数のリソースで共通する値の定義と、外から渡された値やリソースの属性を加工した結果の保持である。後者はコードが難しくなりやすいので、その場合は構成そのものを見直したほうがよい。
locals {
tags = merge(var.essential_tags, var.additional_tags)
}
resource "a" "a" {
tags = local.tags
}module
module は、VPC とサブネットのように一緒に定義すると扱いやすいリソースをまとめたモジュールを呼び出す。Terraform Registry や GitHub で公開されているものも、ローカルに定義したものも使える。Registry のモジュールは version 引数でバージョンを指定できる。
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.19.0"
}
module "vpc_github" {
source = "[email protected]:Fufuhu/aws_vpc_terraform.git//modules/vpc?ref=v0.2.0"
}
module "vpc_local" {
source = "./modules/vpc"
}output
output は、モジュール内で作った値を外に公開する。使い道は、作ったリソースの値を apply 時に確認すること、モジュールの外で使うこと、リモートステートとして読み取ることの 3 つである。
output "vpc_id" {
value = aws_vpc.vpc.id
}count
count は、1 つの resource から同じ種類のリソースを複数作る。
locals {
bucket_settings = [
{ name_suffix = "ichi" },
{ name_suffix = "ni" },
{ name_suffix = "san" },
]
}
resource "aws_s3_bucket" "buckets" {
count = length(local.bucket_settings)
bucket = "sample-${local.bucket_settings[count.index].name_suffix}"
}ここで ni の要素を消して apply すると、buckets[1] は ni から san のバケットに変わる。S3 のバケット名は変更できないので、バケットは削除されて作り直され、buckets[2] は削除される。そのため count は、稼働中に変更できるリソースや、順序に意味があり末尾から削除されることが期待されるリソースだけに使うとよい。
for_each
for_each も 1 つの resource から複数のリソースを作るが、count と違ってマップや文字列のセットを渡せる。
locals {
files = {
"sample1.txt" = { content = "This is a sample file 1." }
"sample2.txt" = { content = "This is a sample file 2." }
}
}
resource "local_file" "files" {
for_each = local.files
filename = each.key
content = each.value.content
}for と条件式
for 式は、既存の配列から新しい配列を作る。for i, v in ... と書けば、インデックスと要素の両方を取り出せる。条件分岐には三項演算子を使う。
locals {
sports = ["football", "baseball", "rugby", "basketball"]
sentences = [for sport in local.sports : "${sport} is one of the major sports"]
num = 4
result = local.num == 4 ? "4です。" : "4ではありません。"
}