Передача значений: tfvars и приоритеты

Объявить переменную — половина дела. Вторая половина — передать ей значение, и способов несколько: флаг -var, файлы .tfvars, переменные окружения TF_VAR_. У них строгий порядок приоритета.

Запомните порядок приоритета — иначе однажды будете полчаса гадать, почему prod взял значение из staging. Побеждает самый «поздний» и явный источник.

Один и тот же конфиг прогоняется для разных окружений именно за счёт разных наборов значений. Для каждого окружения держат свой файл переменных: dev.tfvars, prod.tfvars, и применяют его флагом -var-file.

Источники значений

# 1. флаг командной строки (высший приоритет среди явных)
terraform apply -var="instance_type=t3.large"

# 2. конкретный файл переменных
terraform apply -var-file="prod.tfvars"

# 3. переменная окружения (префикс TF_VAR_)
export TF_VAR_db_password="secret123"
terraform apply

# terraform.tfvars и *.auto.tfvars подхватываются автоматически

Порядок приоритета (от низшего к высшему): значения по умолчанию → переменные окружения TF_VAR_terraform.tfvars*.auto.tfvars-var-file-var. Чем источник «правее» в этой цепочке, тем он сильнее.

ПРИОРИТЕТ (слабее -> сильнее):

default  ->  TF_VAR_env  ->  terraform.tfvars  ->  *.auto.tfvars  ->  -var-file  ->  -var
 слабее                                                                          сильнее

побеждает самый правый источник, задавший значение

Как работает под капотом

Terraform проходит источники в порядке приоритета и каждый следующий перезаписывает предыдущий. Смоделируем это слияние слоёв:

# слои в порядке возрастания приоритета
layers = [
    ("default",          {"region": "us-east-1", "size": "t2.micro", "env": "dev"}),
    ("TF_VAR_env",       {"region": "eu-west-1"}),
    ("terraform.tfvars", {"size": "t3.small"}),
    ("prod.tfvars",      {"env": "prod", "size": "t3.large"}),
    ("-var CLI",         {"size": "t3.xlarge"}),
]

final, source = {}, {}
for name, layer in layers:
    for k, v in layer.items():
        final[k] = v
        source[k] = name      # кто задал последним

for k in final:
    print(f"  {k:8} = {final[k]:12} (из {source[k]})")

«Попробуй сам ▶» — size прошёл через четыре слоя и победил CLI (t3.xlarge); env взялся из prod.tfvars. Так Terraform разрешает конфликты.

Частые ошибки

  • Секреты в *.auto.tfvars. Этот файл подхватывается автоматически и часто случайно попадает в git.
  • Путаница с приоритетом. Значение из -var перебивает файл — а инженер ждёт обратного.
  • Один terraform.tfvars на все окружения. Так легко применить dev-значения к prod. Держите отдельные файлы.

Best practices

  • На окружение — свой файл: terraform apply -var-file=prod.tfvars. Никаких «общих» значений.
  • Секреты — только через TF_VAR_ из менеджера секретов или CI, никогда в файлах git.
  • Добавьте *.tfvars в .gitignore, кроме явно безопасных примеров (example.tfvars).

Разбор глубже

Когда переменная объявлена без default и её значение не пришло ни из одного источника, поведение зависит от режима. В интерактивном запуске Terraform спросит значение в консоли, приостановив выполнение. В автоматическом режиме (CI с флагом -input=false) такой запрос превращается в ошибку — и это правильно: пайплайн не должен молча зависать в ожидании ввода. Поэтому в CI всегда передают -input=false, чтобы недостающая переменная честно роняла сборку, а не подвешивала её.

Полезная практика для команд — файл terraform.tfvars.example с безопасными примерами значений, который коммитится в git, тогда как реальные *.tfvars с секретами добавляют в .gitignore. Новый инженер копирует пример, подставляет свои значения локально — и не рискует случайно закоммитить чувствительные данные. Это тот же паттерн, что и .env.example в обычной разработке. А для окружений (dev/staging/prod) держат отдельные файлы переменных и применяют их явным флагом -var-file, что делает невозможной случайную подстановку dev-значений в прод.

Отдельно стоит держать в голове порядок диагностики, когда переменная «взяла не то значение». Сначала проверьте -var и -var-file в команде запуска — они сильнее всего. Затем загляните в автоматически подхватываемые *.auto.tfvars, про которые легко забыть. Потом — в переменные окружения TF_VAR_, особенно если запуск идёт в CI, где они задаются незаметно. И только в конце смотрите на default. Этот чеклист «сверху вниз по приоритету» экономит массу времени, потому что в девяти случаях из десяти неожиданное значение приходит из самого сильного, а не самого очевидного источника.

Итог: значения приходят из CLI, файлов и окружения с чётким приоритетом — побеждает самый явный источник. На окружение — свой tfvars, секреты — через окружение. Дальше — как вернуть данные наружу через outputs.

Проверьте себя
1. Какой источник значений переменной имеет наивысший приоритет?
Adefault в блоке variable
Bterraform.tfvars
CФлаг -var в командной строке
DTF_VAR_ переменная окружения
2. Почему секреты не стоит класть в *.auto.tfvars?
AФайл медленно читается
BОн подхватывается автоматически и легко попадает в git открытым текстом
CTerraform его игнорирует
DОн шифруется неправильно