Что делает ${...}
Внутри строки ${...}, это шаблон. Внутри фигурных скобок может быть любое выражение HCL: переменная, ссылка на ресурс, функция, условие.
bucket = "myapp-${var.env}"# = "myapp-dev" если var.env = "dev"
tags = { Name = "${local.prefix}-bucket-${count.index}"# = "myapp-dev-bucket-0", "myapp-dev-bucket-1", ...
}
user_data = <<EOF
#!/bin/bash
echo "Environment: ${var.env}"echo "Region: ${data.aws_region.current.name}"EOF
Если есть необычные требования к строке, внутри ${...} можно вызывать функции:
bucket = "${var.app}-${upper(var.env)}-${formatdate("YYYY", timestamp())}"Когда ${...} обязательны, когда нет
В старом HCL (Terraform до 0.12) ${...} нужны были везде:
count = "${var.instance_count}" # старый стильami = "${data.aws_ami.ubuntu.id}" # старый стильВ современном HCL, ${...} нужны только если значение, часть большей строки:
# часть строки → ${...} обязательныbucket = "myapp-${var.env}-logs"# вся строка = одно выражение → ${...} НЕ нужны и не рекомендуютсяcount = var.instance_count
ami = data.aws_ami.ubuntu.id
region = "us-east-1" # литерал, кавычки нужны, ${...} нетterraform fmt уберёт лишние ${...} автоматически. А terraform validate выдаст warning на устаревший стиль.
Heredoc для многострочных строк
Если нужна многострочная строка с подстановками:
user_data = <<EOT
#!/bin/bash
set -e
echo "Hello from ${var.env}!"apt-get update
apt-get install -y nginx
EOT
<<EOT ... EOT (любой маркер вместо EOT) сохраняет всё между ними как строку. Внутри работают ${...}.
Heredoc с дефисом, обрезает лидирующие пробелы:
config = <<-EOT
key = "value"
another = "thing"
EOT
# = "key = \"value\"\nanother = \"thing\"\n", без отступов
Без дефиса, отступы остаются как есть. С дефисом. Terraform убирает наименьший общий отступ.
Спецсимволы внутри ${...}
Если внутри ${...} нужны фигурные скобки или знак доллара буквально, экранируйте:
# ${{var}}. Terraform увидит ${{var}} как «начало interpolation, потом литерал {var}»# Это ошибка. Правильно, экранирование:
literal = "$${not_interpolation}"▸"$ {not_interpolation}", в выходной строке без подстановки
literal_dollar = "%%{also_not}"▸"%{also_not}", % сам по себе не interpolation, но если был бы %{, он начинает шаблон-блок
Знаки $$ и %%, экранирование для interpolation и template-блока соответственно. В обычной работе они нужны редко.
Шаблон-блоки %{...}
Не путать с ${...} (значение): это %{...} (управляющие конструкции):
user_data = <<-EOT
#!/bin/bash
%{ if var.env == "prod" }echo "Production setup"
systemctl enable monitoring
%{ else }echo "Non-prod setup"
%{ endif }hostnames:
%{ for name in var.hostnames }- ${name}%{ endfor }EOT
Это нужно когда в строке нужна логика. Используется редко, но удобно для cloud-init и user_data скриптов.
Подводные камни
-
${...}без кавычек, невалидно.${var.x}без обвязки в строку, ошибка. Если хотите выражение без интерполяции, не оборачивайте в строку:count = var.x. -
Старый стиль
"${var.x}"для одного значения, устарел. Работает, но warning. Лучшеcount = var.x. -
Внутри
${...}нельзя многострочно. Это однострочное выражение. Многострочные конструкции, через heredoc. -
${...}не делает интерполяцию в state. State хранит уже подставленные значения. Если вы поменялиvar.env. Terraform увидит, чтоbucketтеперь должен быть другим, и предложит изменение. -
Переменная типа list/map в interpolation = ошибка.
bucket = "myapp-${var.tags}"гдеtags, map, упадёт. Только примитивы внутри строк. Для других, отдельные присваивания. -
Heredoc backtick'и работают по-разному в Windows vs Unix. Если HCL генерируется кросс-платформенно, будьте осторожны с line endings внутри heredoc.