Terraformでインフラを管理していると、設定ファイルの内容を環境によって変えたいケースが頻繁に発生します。templatefile関数でローカルファイルをテンプレートとして使う方法は広く知られていますが、S3やAPIから取得したリモートのテンプレート文字列を使いたい場合はどうすれば良いのでしょうか。
Terraform v1.5で追加されたtemplatestring関数が、まさにこのユースケースのために設計された関数です。
templatestring関数とは
templatestringは、モジュール内の変数・データソース・ローカル値として参照できる文字列をTerraformテンプレートとして評価する関数です。
templatefileとの根本的な違いはテンプレートの取得元です:
templatefile→ ローカルファイルを読み込むtemplatestring→ モジュール内オブジェクト(データソース等)が持つ文字列をテンプレートとして使う
この違いにより、templatestringはS3・SSM Parameter Store・外部APIから取得した動的なテンプレートを処理できます。
構文
templatestring(ARG1, ARG2)
| 引数 | 必須 | 説明 |
|---|---|---|
| ARG1 | ✅ | モジュール内オブジェクトへの参照(直接リテラル文字列は不可) |
| ARG2 | ✅ | テンプレート変数を格納したオブジェクト |
重要な制約: 第1引数には必ずモジュール内のオブジェクト参照(data.xxx.yyy、local.xxx、var.xxx等)を指定します。テンプレート文字列を直接リテラルとして渡すことはできません。
なぜこの制約があるのか? Terraformはプランフェーズで式の評価順序を決定する必要があります。リテラルを直接渡すと評価サイクルの管理が複雑になるため、必ず参照を経由する設計になっています。
テンプレート構文
第2引数で渡した変数は、通常のTerraformテンプレート式と同じ構文で参照できます。
${変数名} # 変数の展開
%{ for item in list ~} # forループ
%{ if 条件 ~} # 条件分岐
%{ endif ~}
基本的な使用例
S3から取得したテンプレートをレンダリング
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-northeast-1"
}
variable "environment" {
description = "デプロイ環境"
type = string
default = "dev"
}
variable "app_name" {
description = "アプリケーション名"
type = string
}
# S3からテンプレートファイルを取得
data "aws_s3_object" "config_template" {
bucket = "my-templates-bucket"
key = "app-config.tmpl"
}
# テンプレートをレンダリングしてSSMパラメータに保存
resource "aws_ssm_parameter" "app_config" {
name = "/${var.environment}/${var.app_name}/config"
type = "String"
value = templatestring(data.aws_s3_object.config_template.body, {
app_name = var.app_name
environment = var.environment
region = "ap-northeast-1"
})
tags = {
Name = "${var.app_name}-config"
Environment = var.environment
ManagedBy = "terraform"
}
}
output "rendered_config" {
description = "レンダリングされた設定内容"
value = templatestring(data.aws_s3_object.config_template.body, {
app_name = var.app_name
environment = var.environment
region = "ap-northeast-1"
})
}
S3バケット内のapp-config.tmplがこのような内容の場合:
APP_NAME=${app_name}
ENVIRONMENT=${environment}
AWS_REGION=${region}
rendered_configの出力は次のようになります:
APP_NAME=myapp
ENVIRONMENT=dev
AWS_REGION=ap-northeast-1
これは公式ドキュメントのExample use caseパターンに対応しています。
ローカル値を使った動的テンプレート構築
ローカル値でテンプレートを組み立て、それをtemplatestringに渡す応用パターンです。
variable "services" {
description = "サービス名のリスト"
type = list(string)
default = ["web", "api", "worker"]
}
variable "environment" {
description = "デプロイ環境"
type = string
default = "dev"
}
locals {
# テンプレートを動的に構築
nginx_template = <<-EOT
%{ for service in services ~}
upstream ${service} {
server ${service}.${environment}.internal:8080;
}
%{ endfor ~}
EOT
}
output "nginx_config" {
description = "生成されたNginx設定"
value = templatestring(local.nginx_template, {
services = var.services
environment = var.environment
})
}
注意: 公式ドキュメントでは、ローカル値でテンプレートを動的構築する方法は「他に代替手段がない場合のみ」と位置づけられています。理由は2点あります: 1. 結果が複雑になり保守が難しくなる 2. 外部入力に依存する場合、Terraformが実行されるシステム上の任意ファイルを読み込むテンプレートが生成されるリスクがある 可能な限り
templatefileや通常の文字列補間で代替することを検討してください。
templatefileとの比較
| 特徴 | templatestring | templatefile |
|---|---|---|
| テンプレートソース | モジュール内オブジェクト参照 | ローカルファイルパス |
| リモートテンプレート | ✅ 対応(データソース経由) | ❌ 非対応 |
| ローカルファイル | ❌ 直接不可 | ✅ 対応 |
| 動的テンプレート構築 | ✅ locals経由で可能 | ❌ 不可 |
| Terraform最小バージョン | v1.5以降 | v0.12以降 |
よくある間違いと対処法
❌ 第1引数にリテラル文字列を渡す
# エラー: 第1引数にリテラルは渡せない
output "bad" {
value = templatestring("Hello, ${name}!", { name = "World" })
}
# エラーメッセージ例:
# Error: Invalid function argument
# The first argument to "templatestring" must be a reference to a named object
リテラル文字列は通常の文字列テンプレート式で処理できます:
# 正しい方法:変数を直接補間
output "good" {
value = "Hello, ${var.name}!"
}
❌ v1.5未満で使用する
templatestringはTerraform v1.5で追加された関数です。古いバージョンでは使用できません。required_version = ">= 1.5.0"を必ず指定しましょう。
まとめ
templatestringは、リモートから取得したテンプレート文字列をTerraformの設定内で動的にレンダリングするための関数です。
- 第1引数: モジュール内オブジェクトへの参照(必須制約)
- 主な用途: S3等から取得したテンプレートのレンダリング
- 注意: 動的テンプレート構築(locals経由)はリスクがあるため慎重に
templatefileがローカルの静的テンプレートに最適なのに対し、templatestringはリモートの動的テンプレートに最適です。用途に応じて使い分けることで、より柔軟なインフラ設定管理が実現できます。