【Terraformでの変数と参照方法を徹底解説】基本構文から便利な応用テクニックまで

terraform

Terraform では、インフラ構成をコードで管理 (Infrastructure as Code) するにあたって、各リソースや設定の値を動的に扱うための複数の仕組みが用意されています。たとえば AWS CloudFormation でいう !Ref!Sub と同等の機能を、Terraform では入力変数リソース属性ローカル値文字列操作などを組み合わせて実現します。本記事では、それら機能をわかりやすく解説しながら、実際のコード例も交えて紹介します。


1. 入力変数 (Input Variables)

入力変数とは?

Terraform における入力変数は、モジュール外から値を受け取る仕組みです。再利用性や環境ごとの設定切り替えを簡単にするために用いられます。これにより、変数の値を外部から注入できるため、Terraform コードの可読性と柔軟性が向上します。

記述方法

  1. 変数の定義 (例: variable "<name>" { ... })
  2. 使用 (例: var.<name>)

サンプルコード

# variable "region" を定義
variable "region" {
  default = "ap-northeast-1"
}

# 変数を参照して使用
resource "aws_subnet" "example" {
  availability_zone = "${var.region}a"
}

上記では variable "region"region という変数を宣言し、デフォルト値に ap-northeast-1 を設定しています。aws_subnet リソースでは availability_zone${var.region}a と記述することで、region 変数の値に “a” を付加して AZ を指定しています。


2. リソース属性 (Resource Attributes)

リソース属性とは?

Terraform の各リソース (例: aws_vpc, aws_subnet など) は、作成された後に複数の属性値を持ちます。Terraform がリソースを作成すると、たとえば VPC の ID や Subnet の ID などを取得可能になります。これらの属性を他のリソースで参照することが可能です。

記述方法

  1. リソースの定義 (例: resource "<resource_type>" "<name>" { ... })
  2. 使用 (例: <resource_type>.<name>.<attribute>)

サンプルコード

# VPC を作成
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

# VPC リソースの属性 aws_vpc.main.id を Subnet 作成時に利用
resource "aws_subnet" "example" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"
}

ここでは、aws_vpc.main が持つ id 属性を aws_subnet.example リソースの vpc_id パラメータとして参照しています。これにより、Terraform が VPC の作成後、その ID を元に Subnet を自動的に関連付けることができます。


3. ローカル値 (Local Values)

ローカル値とは?

ローカル値 (locals) は、複雑な式や繰り返し使用する値をまとめて置くための仕組みです。変数定義と異なり、あくまで同一モジュール内でのみ有効なスコープを持ちます。複雑な式をローカル値に抽象化しておくことで、コードの可読性や保守性が上がります。

サンプルコード

locals {
  az_suffix = "a"
}

resource "aws_subnet" "example" {
  availability_zone = "${var.region}${local.az_suffix}"
}

上記では、local.az_suffix に “a” を割り当てています。var.region は先ほど同様に “ap-northeast-1” などと想定すると、実際の availability_zone は “ap-northeast-1a” になります。


4. 文字列操作のさまざまな手法

Terraform では、AWS CloudFormation の !Sub のような文字列置換・結合機能を複数の手段で実現できます。以下では、代表的な手法を紹介します。

4.1. 基本的な補間構文 ${ }

もっとも基本となるのが、${ } の中に変数や式を書いて文字列に埋め込む補間構文です。

サンプルコード

resource "aws_s3_bucket" "example" {
  bucket = "${var.project_name}-${random_id.suffix.hex}"
}

ここでは var.project_namerandom_id.suffix.hex を文字列に連結しています。random_id.suffix はランダムな ID の作成を行うリソースで、.hex という属性で文字列形式のランダム値を取得できます。


4.2. format 関数

Terraform には format 関数が用意されており、Go 言語の fmt スタイルのように、位置指定子 (%s など) を使った文字列補間が可能です。

サンプルコード

output "endpoint" {
  value = format("https://%s.%s", var.service_name, aws_route53_zone.main.name)
}

この例では "https://%s.%s" という書式に対して、var.service_name および aws_route53_zone.main.name の2つの値を順番に当てはめています。


4.3. join 関数

リスト (list) 型の値を結合したい場合には、join 関数を使います。文字列だけでなく、リスト同士の操作にも応用が可能です。

サンプルコード

resource "aws_iam_policy_document" "example" {
  statement {
    actions = ["s3:GetObject"]
    resources = [join("", ["arn:aws:s3:::", var.bucket_name, "/*"])]
  }
}

["arn:aws:s3:::", var.bucket_name, "/*"] というリストを、区切り文字 (ここでは "") で結合して "arn:aws:s3:::<bucket_name>/*" という文字列を作っています。


4.4. テンプレートファイル (Template File)

Terraform には外部ファイルをテンプレートとして取り込み、変数を埋め込むことができるテンプレートエンジンが存在します。より複雑なスクリプトや設定ファイル (例: user_data など) を生成したい場合に便利です。

サンプルコード

data "template_file" "user_data" {
  template = file("${path.module}/user_data.sh.tpl")
  vars = {
    db_endpoint = aws_db_instance.main.endpoint
  }
}

ここで user_data.sh.tpl 内に ${db_endpoint} という形で変数が記述されていれば、vars で与えた値に置き換えられた状態の最終的な文字列が生成されます。


5. まとめ:Terraform における変数と文字列操作のベストプラクティス

  1. 再利用性向上のためには入力変数
    環境ごとの違い (region, instance_type など) は入力変数に切り出して管理すると、再利用性が高まるだけでなく、チーム全体の構成管理がシンプルになります。
  2. リソース属性の活用
    リソース同士の依存関係を明示的にするため、関連するリソースの属性を活用しましょう。Terraform が依存関係を自動で把握し、正しい順序でリソースを構築してくれます。
  3. ローカル値で複雑なロジックを抽象化
    頻繁に使うパターンや複雑な式は locals に定義することで、コードの可読性が向上し、メンテナンスしやすくなります。
  4. 文字列操作を適切に使い分ける
    • 基本的な埋め込みは ${ }
    • 位置指定フォーマットには format
    • リストの結合には join
    • 複雑なテンプレート生成は template_file
      と使い分けることで、目的に応じたわかりやすいコードを記述できます。

Terraform の強力な変数管理・文字列操作機能を使いこなすことで、より柔軟性が高く、メンテナンスしやすいインフラ構成を実現できます。ぜひプロジェクトの規模や要件に合わせて、これらの機能を活用してみてください。

コメント

タイトルとURLをコピーしました