1. ホーム
  2. 記事一覧
  3. Terraformのinput変数の基本的な定義方法 Variableとは

2023.07.28

Terraformのinput変数の基本的な定義方法 Variableとは

出典: HashiCorp Brand https://www.hashicorp.com/brand

こちらの記事では、Terraformにおけるinput変数、Variableについて解説します。Terraformとは、IaC(Infrastructure as Code)を実現するための構成管理ツールの一つです。

Terraformの変数にはinput、local、outputの3つの種類があります。今回はこの3つの変数のうちの一つ、input変数の基本的な定義方法を解説していきます。

IaCについては以下の記事で解説しています。

https://envader.plus/article/136

Terraformを実際に触ってみたい方は、以下の記事でハンズオンを解説しています。

https://envader.plus/article/162

input変数とは?

Terraformのinput変数とは、外部ファイル(異なる.tfファイルなど)から値を入力するために使用する変数です。この変数を定義することで、各リソースなどに設定する値を直接書くことを防ぐことができ、再利用性を高めた運用ができるというメリットがあります。

公式ドキュメントでも表現されているように、input変数は関数定義の引数のようなものと言えます。

input変数はプロジェクトのルートディレクトリ(親モジュール)で定義すると、CLI、環境変数、.tfvarsファイルやデフォルト値を使って値を設定することができます。ルートディレクトリの下の階層(子モジュール)でinput変数を定義する場合には、呼び出し元(子モジュールを使う側)のモジュールブロックで値を渡す必要があります。

input変数の定義

Terraformでinput変数を定義するには、variableブロックを使用して変数を定義します。

variable "region" {
  description = "The region where resources should be created"
  type        = string
  default     = "ap-northeast-1"
}

variable "subnet_ids" {
  description = "List of subnet IDs to deploy resources into"
  type        = list(string)
  default     = []
}

variableの後のダブルクウォートで囲まれている部分が変数名になり、input変数を参照する場合にはこの変数名を使用します。この変数名は同じモジュール内の変数の中で一意(一つだけ)にする必要があります。

また、変数名には予約されているsource、version、providers、count、for_each、lifecycle、depends_on、locals以外を使用するようにしなければならないため注意が必要です。

input変数の引数(設定値)

input変数を定義する際、引数として変数名の後のカッコの中に設定値を記述することができます。以下に公式を元に解説します。

defaut

変数宣言にデフォルト値を設定することで、ユーザーがその変数を明示的に記述しなかった場合には設定したデフォルト値が使用されます。input変数で定義した変数にはCLIや環境変数、.tfvarsファイルなどで値を渡す必要がありますが、この値を渡す作業が省略された場合にはデフォルト値が適用されるということです。

また、仕様としてデフォルト値には変数を設定することはできません。

variable "region" {
  default     = "ap-northeast-1"
}

# 変数はデフォルト値に設定できない
variable "region" {
  default     = var.region_name
}

type

変数の値の型を指定することができます。こちらはオプションのため省略することが可能で、省略した場合はどんな型の値でも渡すことが可能です。ただし、型を指定することで開発者にとっての注意喚起や、想定していた型とは違う値を渡した場合にはエラーを返してくれるため、公式では指定することが推奨されています。

どのような型が存在するのかは後述します。

# 文字列型の例
variable "region" {
   type        = string
 }

description

input変数の説明を記述することができます。説明を簡潔に記述しておくことで、共同で開発していく場合にも変数がどのような役割を持っているのかなどを共有することができます。

variable "region" {
  description = "The region where resources should be created"
 }

validation

validationを設定することで、変数の値が設定した条件に合っているかどうか検証することが可能になります。

conditionでは真偽値を返す必要があり、falseになった場合にはerror_messageで設定したメッセージを返します。

variable "environment" {
  description = "Deployment environment"
  type        = string

  validation {
    condition     = contains(["prod", "staging", "dev"], var.environment)
    error_message = "The environment must be 'prod', 'staging', or 'dev'."
  }
}

以下にエラー表示の例を示します。

# environment変数へstgという値を設定した例
# error_messageで設定した値が出力されている

Error: Invalid value for variable
on variables.tf line 5:
5: variable "environment" {
│     ├────────────────
│     │ var.environment is "stg"
│ The environment must be 'prod', 'staging', or 'dev'.
│ This was checked by the validation rule at variables.tf:8,3-13.

sensitive

sensitiveをtrueに設定することで、terraform planやapplyを実行した際に設定した値を画面に出力されるのを防ぐことができます。この設定は、主に機密情報を含む可能性がある場合に使用されます。

DBのパスワードを想定した変数があった場合、sensitiveをtrueにしておくことで、planやapply実行時に値が出力されることを防ぎます。

variable "db_password" {
  description = "The password for the database"
  type        = string
  sensitive   = true
}

ただし、公式にもあるとおり画面には出力されないものの、.tfstateファイル(Terraformによって管理されているインフラストラクチャの現在の状態を保存し、追跡するためのファイル)には平文で保存されるため、必ずしも安全とは限りません。

参照リンク: Sensitive Data in State

nullable

nullableは変数にnull値を許可するかどうかを制御するものです。nullable = falseを設定すると、その変数がnullになることを防ぐことができます。デフォルトではtrueに設定されているため、変数の値としてnullを渡しても有効な値として扱われます。

variable "password" {
  type     = string
  nullable = false
}

参照リンク: Terraform Arguments

input変数の型(Primitive Types)

ここからは、Terraformを利用する上で一番の基本となる型を見ていきます。プリミティブ型と呼ばれる型が基本となり、文字列型、数値型、真偽値型の3つに分類されます。

string

string型は最も基本的なもので、変数の値には文字列を渡すことができます。表現を変えると、この変数には文字列の値を受け取ることをTerraformに伝えているとも言えます。

値を渡す際にはダブルクウォートで文字列を囲む必要があります。

# デフォルト値としてt3.microを渡す場合
variable "instance_type" {
  description = "The type of instance to start."
  type        = string
  default     = "t3.micro"
}

number

number型では15のような整数値、1.234などの少数も受け取ることができます。

variable "max_instances" {
  description = "The maximum number of instances to launch."
  type        = number
  default     = 5
}

bool

bool型では、trueまたはfalseの値を受け取ることができます。

variable "enable_logging" {
  description = "Enable or disable logging."
  type        = bool
  default     = true
}

公式ではプリミティブ型の場合、受け取った値が自動的に適切な型へ変換される可能性があることを説明しています。bool型で指定した場合にも、場合によって文字列型へ変換される場合などです。

参照リンク: Terraform Conversion of Primitive Types

少しわかりにくいため、以下に例を示します。例では数値型と真偽値型の変数を定義しています。

variable "example_number" {
  description = "An example number."
  type        = number
  default     = 15
}

variable "example_bool" {
  description = "An example boolean."
  type        = bool
  default     = true
}

次に、S3バケットのタグを指定する場面を例に示します。

resource "aws_s3_bucket" "example" {
  bucket = "my-bucket"
  acl    = "private"

  tags = {
    number_as_string = var.example_number → 15"15"へ変換される
    bool_as_string   = var.example_bool   → true"true"へ変換される
  }
}

この例では、S3バケットのタグに数値型とbool型の変数を指定しています。しかし、S3のタグの値は文字列型でなければならないため、ここで自動的に変数のデフォルトで指定した15やtrueの値が文字列型へ変換されます。

また、自動的に変換される条件として値が有効な文字列や数値を含んでいる必要があります。

# 文字列が数値を表さない場合は変換されない
"abc"
"123abc"

# 文字列が真偽値を表さない場合も変換されない
"yes"
"no"
"1"

参照リンク: Terraform Primitive Types

Collection Types(コレクション型)

コレクション型は、複合型という複数の値を一つの変数に格納することができる型の種類の一つになります。複合型にはコレクション型の他に、Structural Types(構造型)が存在します。

以下にコレクション型のlist、map、setについて解説します。

list

listでは、格納される値が同じ型の配列を受け取ることができます。list(受け取りたい型)とすることで、受け取りたい型の配列を指定できます。

# 文字列の配列を受け取りたい場合
variable "example_list" {
  type    = list(string)
  default = ["apple", "banana", "cherry"]
}

# 数値の配列を受け取りたい場合
variable "example_list" {
  type    = list(number)
  default = [1, 2, 3]
}

# 以下は数値と文字列が混同しているためエラーになる
variable "example_list" {
  type    = list(number)
  default = [1, "two", 3]
}

map

mapはキーと値で構成された配列です。map(受け取りたい型)とすることで作成することができます。

キーはユニークな値(他と重複しない)である必要があり、通常キーと値はダブルクウォートで囲む必要があります。

variable "example_map" {
  type = map(string)
  default = {
    "key1" = "value1"
    "key2" = "value2"
  }
}

ただし、キーが数字で始まらない場合には、ダブルクウォートを省略することも可能です。

variable "example_map" {
  type = map(string)
  default = {
    key1 = "value1"  # OK: キーが数字で始まっていない
    key2 = "value2"  # OK: キーが数字で始まっていない
  }
}

set

listと似ていますが、setは値にアクセスする際にindexで参照することができません。また、値が重複していてはいけないということ、要素の型は同じでなければならないという条件があります。

# setの正しい例
variable "example_set" {
  type    = set(string)
  default = ["apple", "banana", "cherry"]
}

# 値が重複しているためエラーになる
variable "example_set" {
  type    = set(string)
  default = ["apple", "apple", "cherry"]
}

# エラー:文字列と数値が混在
variable "example_set" {
  type    = set(string)
  default = ["apple", 123, "cherry"]
}

setはTerraformでループ処理を行う際のfor_eachで使用する場面が出てきます。

参照リンク: The for_each Meta-Argument

コレクション型(list、map、set)に関しては、要素の型はすべて同じでなければならないという点に注意が必要です。

参照リンク: Terraform Collection Types

Structural Types(構造型)

構造型(structural types)はコレクション型とは違い、異なる型を持つ複数の要素を1つの値としてまとめることができます。構造型には、object型とtuple型の2つがあります。

object

object型では、一つ一つの要素に対して<キー = 型>と記述し、型を指定することができます。これにより、stringとnumberなど異なる型を一つの変数内で扱うことができるようになります

variable "employee" {
  type = object({
    name   = string
    age    = number
    active = bool
  })
  default = {
    name   = "John Doe"
    age    = 32
    active = true
  }
}

tuple

tupleは、異なる型の値を一定の順序で格納するためのデータ型です。

variable "person_info" {
  type = tuple([string, number, bool])
  default = ["Alice", 30, true]
}

tupleの値は順序が重要とされており、型と要素の順番が異なる場合にはエラーが発生するため注意が必要になります。

variable "sample_tuple" {
  type = tuple([string, number, bool])
  default = [30, "Alice", true] // 順序が変わったため、型の定義と合わなくなってしまいエラーになります
}

参照リンク: Terraform Structural Types

まとめ

この記事では、Terraformにおけるinput変数(Variable)の定義方法について解説しました。

コレクション型では要素の型は同じでなければいけないこと、構造型では異なる要素の型を定義すすることができることなど、それぞれの型に応じて違いがあることを理解して変数を定義する必要があります。

今回の記事がTerraformを学ぶ方の一助になれば幸いです。

【番外編】USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話

IT未経験者必見 USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話

プログラミング塾に半年通えば、一人前になれると思っているあなた。それ、勘違いですよ。「なぜ間違いなの?」「正しい勉強法とは何なの?」ITを学び始める全ての人に知って欲しい。そう思って書きました。是非読んでみてください。

「フリーランスエンジニア」

近年やっと世間に浸透した言葉だ。ひと昔まえ、終身雇用は当たり前で、大企業に就職することは一種のステータスだった。しかし、そんな時代も終わり「優秀な人材は転職する」ことが当たり前の時代となる。フリーランスエンジニアに高価値が付く現在、ネットを見ると「未経験でも年収400万以上」などと書いてある。これに釣られて、多くの人がフリーランスになろうとITの世界に入ってきている。私もその中の1人だ。数年前、USBも知らない状態からITの世界に没入し、そこから約2年間、毎日勉学を行なった。他人の何十倍も努力した。そして、企業研修やIT塾で数多くの受講生の指導経験も得た。そこで私は、伸びるエンジニアとそうでないエンジニアをたくさん見てきた。そして、稼げるエンジニア、稼げないエンジニアを見てきた。

「成功する人とそうでない人の違いは何か?」

私が出した答えは、「量産型エンジニアか否か」である。今のエンジニア市場には、量産型エンジニアが溢れている!!ここでの量産型エンジニアの定義は以下の通りである。

比較的簡単に学習可能なWebフレームワーク(WordPress, Rails)やPython等の知識はあるが、ITの基本概念を理解していないため、単調な作業しかこなすことができないエンジニアのこと。

多くの人がフリーランスエンジニアを目指す時代に中途半端な知識や技術力でこの世界に飛び込むと返って過酷な労働条件で働くことになる。そこで、エンジニアを目指すあなたがどう学習していくべきかを私の経験を交えて書こうと思った。続きはこちらから、、、、

note記事3000いいね超えの殿堂記事 今すぐ読む

エンベーダー編集部

エンベーダーは、ITスクールRareTECHのインフラ学習教材として誕生しました。 「遊びながらインフラエンジニアへ」をコンセプトに、インフラへの学習ハードルを下げるツールとして運営されています。

RareTECH 無料体験授業開催中! オンラインにて実施中! Top10%のエンジニアになる秘訣を伝授します! RareTECH講師への質疑応答可

関連記事