Переменные ввода и выходные значения в Terraform

Рейтинг: 55.2% · 12 голосов
Подробный курс по Terraform и OpenTofu на примерах Yandex Cloud: ресурсы и провайдеры, состояние и бэкенды, модули, циклы и условия HCL, секреты и Lockbox, тестирование, CI/CD и командная работа. С актуализацией на 2026 (Terraform 1.3-1.10, OpenTofu).
Ответить
Аватара пользователя
Vlad_DevOps
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Переменные ввода и выходные значения в Terraform

Сообщение Vlad_DevOps »

Оглавление курса (47)
  1. Что такое инфраструктура как код и зачем она нужна
  2. Категории инструментов IaC: чем отличаются Ansible, Packer, Kubernetes и Terraform
  3. Чем Terraform отличается от Ansible, Pulumi и CloudFormation
  4. Как работает Terraform под капотом и кто такой OpenTofu
  5. Установка Terraform и OpenTofu, подготовка Yandex Cloud
  6. Первый ресурс: разворачиваем виртуальную машину в Yandex Cloud
  7. Веб-сервер на ВМ: метаданные, user-data и группы безопасности
  8. Переменные ввода и выходные значения в Terraform (вы здесь)
  9. Кластер ВМ: группа экземпляров Yandex Compute Instance Group
  10. Балансировщик нагрузки: Application Load Balancer в Yandex Cloud
  11. Состояние Terraform: что такое tfstate и чем опасен локальный файл
  12. Удалённое хранилище состояния: бэкенд на Yandex Object Storage
  13. Изоляция состояния: рабочие области против раскладки по папкам
  14. Источники данных и terraform_remote_state: связываем компоненты
  15. Модули Terraform: переиспользуем инфраструктуру
  16. Входные, локальные и выходные переменные модуля
  17. Версионирование модулей и подводные камни
  18. Циклы в Terraform: параметр count
  19. Циклы в Terraform: for_each по множествам и картам
  20. Выражения for и строковые директивы
  21. Условная логика: count-трюк, for_each и директива if
  22. Встроенные функции, типы и выражения HCL
  23. Развёртывание без простоя: create_before_destroy
  24. Подводные камни Terraform и рефакторинг с блоком moved
  25. Управление секретами: основы и типы
  26. Инструменты управления секретами: Yandex Lockbox, Vault, SOPS
  27. Аутентификация провайдера и секреты: сервисные аккаунты и OIDC
  28. Секреты в ресурсах и состоянии, ephemeral-значения
  29. Провайдеры Terraform: установка, версии, required_providers
  30. Несколько копий одного провайдера: alias и мультизона
  31. Несколько провайдеров и аккаунтов: configuration_aliases
  32. Terraform, Docker и Kubernetes: Managed Kubernetes в Yandex Cloud
  33. Код Terraform промышленного уровня: почему это долго
  34. Мелкие компонуемые модули вместо монолита
  35. Тестируемые модули и проверки: validation, precondition, postcondition
  36. Версионирование, публикация модулей и Terragrunt
  37. Ручное тестирование Terraform и очистка ресурсов
  38. Автоматические тесты на Terratest: модульные тесты
  39. Интеграционные и сквозные тесты, пирамида тестирования
  40. Нативный terraform test и статический анализ
  41. Внедрение Terraform в команде: процессы и культура
  42. Конвейер развёртывания прикладного кода
  43. Конвейер инфраструктурного кода и золотое правило Terraform
  44. Стиль, ревью и CI/CD-инструменты: Atlantis, TACOS, policy as code
  45. Что нового в Terraform 1.3-1.10: моды, импорт, провайдер-функции, Stacks
  46. OpenTofu в 2026: чем живёт форк и как мигрировать
  47. Сертификация HashiCorp Terraform Associate и карьера
Представь конфиг, в котором имя виртуалки, зона, количество ядер, образ диска и публичный IP захардкожены прямо в ресурсе. Один файл - один сервер. Понадобилось поднять второй стенд для тестов - копируешь весь main.tf, правишь руками десяток мест, забываешь поменять одно имя и получаешь конфликт. Это классическая боль человека, который только что выучил, что такое инфраструктура как код, но ещё не научился делать её гибкой. Сегодня лечим: разбираем переменные ввода, выходные значения и локальные вычисления. После этого урока твой terraform yandex cloud конфиг станет настраиваемым шаблоном, а не одноразовой запиской.

Это седьмая глава, так что HCL ты уже читаешь, terraform plan и terraform apply запускал. Теперь добавим в этот скелет нервную систему - параметры, которые меняют поведение без переписывания тела.

Переменные ввода: variable

Переменная объявляется блоком variable. У него есть имя и набор аргументов, из которых тебе реально пригодятся пять: type, default, description, validation и sensitive.

Код: Выделить всё

variable "vm_name" {
  type        = string
  description = "Имя виртуальной машины в Yandex Cloud"
  default     = "web-1"
}

variable "cores" {
  type    = number
  default = 2
}

variable "preemptible" {
  type    = bool
  default = true
}
type говорит Terraform, что внутри. Базовые типы: string, number, bool. Есть составные: list (упорядоченный список одного типа), map (словарь ключ-значение), set (множество без дубликатов) и object (структура с именованными полями). Примеры:

Код: Выделить всё

variable "zones" {
  type    = list(string)
  default = ["ru-central1-a", "ru-central1-b"]
}

variable "labels" {
  type    = map(string)
  default = {
    env   = "dev"
    owner = "khovanskiy"
  }
}

variable "vm_spec" {
  type = object({
    cores  = number
    memory = number
  })
  default = {
    cores  = 2
    memory = 4
  }
}
Тип - это не формальность. Если объявил number, а передал "два", Terraform остановит тебя на этапе plan, а не уронит apply на середине создания ресурсов. Указывай тип всегда, даже когда лень.

default - значение по умолчанию. Если оно есть, переменная необязательная. Если default не задан, Terraform потребует значение при каждом запуске и спросит интерактивно, что в автоматизации обычно нежелательно.

description - человеческое описание. Кажется мелочью, но через месяц именно оно объяснит будущему тебе, зачем нужна эта переменная. В команде это вообще обязательный минимум вежливости.

validation - проверка значения своими правилами. Например, не дадим выставить меньше одного ядра:

Код: Выделить всё

variable "cores" {
  type        = number
  description = "Число vCPU"
  default     = 2

  validation {
    condition     = var.cores >= 1 && var.cores <= 32
    error_message = "Ядер должно быть от 1 до 32."
  }
}
condition должен вернуть true для валидного значения. Вернул false - Terraform печатает твой error_message и прекращает работу. Это дешёвая страховка от опечаток в духе 200 ядер.

sensitive = true помечает переменную как чувствительную. Пароль, токен, приватный ключ. Terraform перестанет печатать её значение в выводе plan и apply, показывая (sensitive value). Важно понимать: в файле состояния значение всё равно лежит в открытом виде, sensitive прячет его только из консоли и логов, а не из terraform state. Защита state - отдельная тема, тут лишь гигиена вывода.

Изображение

Как передать значения переменным

Объявить переменную мало, ей надо дать значение. Способов несколько, и у них есть приоритет - кто перебьёт кого.
  • default в блоке variable - самый слабый, базовый уровень.
  • Файлы *.tfvars - terraform.tfvars и любые *.auto.tfvars подхватываются автоматически, остальные подключаешь флагом -var-file. Это основной способ хранить наборы значений под разные окружения.
  • Переменные окружения вида TF_VAR_имя. Terraform читает TF_VAR_cores как значение переменной cores. Удобно для секретов в CI, чтобы не светить их в файлах.
  • Флаг -var в командной строке - точечное переопределение, перебивает почти всё.
Выглядит это так. Файл prod.tfvars:

Код: Выделить всё

vm_name     = "web-prod"
cores       = 4
preemptible = false
zones       = ["ru-central1-a", "ru-central1-d"]
Запуск с этим файлом и точечным переопределением одного значения:

Код: Выделить всё

export TF_VAR_folder_id="b1g***"
terraform plan -var-file="prod.tfvars" -var="cores=8"
Здесь cores станет 8 (флаг -var сильнее файла), folder_id придёт из окружения, остальное - из prod.tfvars. Запомни направление: чем ближе источник к моменту запуска команды, тем он сильнее.

Интерполяция и ссылки на переменные

Внутри конфигурации к переменной обращаешься через var.имя. Раньше любую подстановку оборачивали в синтаксис интерполяции ${...}, сегодня в чистых выражениях он не нужен - пишешь var.vm_name напрямую. Конструкция ${} осталась нужна только когда вставляешь значение внутрь строки:

Код: Выделить всё

metadata = {
  hostname = "${var.vm_name}.internal"
}
Везде, где значение - это всё выражение целиком, скобки лишние: name = var.vm_name. Внутри строки с текстом вокруг - нужны: "web-${var.env}". Это частый источник недопонимания у новичков, так что держи правило в голове.

Выходные значения: output

Apply отработал, ресурсы созданы. Но как узнать публичный IP машины, не лазая в веб-консоль? Для этого есть output - значения, которые Terraform печатает после apply и хранит в состоянии.

Код: Выделить всё

output "external_ip" {
  description = "Публичный IP веб-сервера"
  value       = yandex_compute_instance.web.network_interface[0].nat_ip_address
}

output "fqdn" {
  value = yandex_compute_instance.web.fqdn
}
Атрибут fqdn у yandex_compute_instance read-only - его значение Terraform узнаёт только после создания машины, и через output ты вытащишь полное доменное имя. Публичный адрес лежит в блоке network_interface, поэтому индексируем network_interface[0] и берём nat_ip_address. Получить любой output потом можно командой terraform output external_ip - удобно скармливать в скрипты деплоя.

Если output отдаёт секрет, помечай его sensitive = true, иначе Terraform напечатает его прямым текстом в конце apply:

Код: Выделить всё

output "db_password" {
  value     = random_password.db.result
  sensitive = true
}
Помеченный output не покажется в общем выводе, но достать его явно командой terraform output db_password всё ещё можно - это осознанное действие, а не случайная утечка в лог CI.

Локальные значения: locals

Иногда нужно промежуточное вычисление, которое не должно настраиваться снаружи. Для этого есть locals - именованные выражения внутри конфига. Ссылаешься на них через local.имя (без s, в отличие от блока locals).

Код: Выделить всё

locals {
  name_prefix = "${var.project}-${var.env}"
  common_labels = {
    project = var.project
    env     = var.env
    managed = "terraform"
  }
}
Главное отличие от переменной: variable - вход снаружи, его задаёт пользователь; local - вычисление внутри, его задаёт автор конфига. Не заводи local там, где значение используется один раз - смысла нет. Заводи, когда одна и та же формула повторяется в нескольких местах и её удобно поправить в одной точке.

Практика: рефакторим веб-сервер на переменные

Соберём всё вместе на нашей знакомой ВМ из прошлых глав. Было захардкожено - стало настраиваемо.

Код: Выделить всё

variable "project"  { type = string, default = "cyberlake" }
variable "env"      { type = string, default = "dev" }
variable "zone"     { type = string, default = "ru-central1-a" }
variable "image_id" { type = string }

variable "vm_spec" {
  type = object({
    cores  = number
    memory = number
  })
  default = { cores = 2, memory = 2 }
}

locals {
  vm_name = "${var.project}-web-${var.env}"
}

resource "yandex_compute_instance" "web" {
  name        = local.vm_name
  platform_id = "standard-v3"
  zone        = var.zone

  resources {
    cores  = var.vm_spec.cores
    memory = var.vm_spec.memory
  }

  boot_disk {
    initialize_params {
      image_id = var.image_id
      size     = 10
    }
  }

  network_interface {
    subnet_id = yandex_vpc_subnet.web.id
    nat       = true
  }

  labels = {
    project = var.project
    env     = var.env
  }
}

output "web_external_ip" {
  value = yandex_compute_instance.web.network_interface[0].nat_ip_address
}

output "web_fqdn" {
  value = yandex_compute_instance.web.fqdn
}
Теперь один и тот же код поднимает dev и prod - меняется только tfvars. Имена ресурсов и атрибуты тут реальные из провайдера: platform_id, resources с cores и memory, boot_disk с блоком initialize_params и image_id, network_interface с nat и subnet_id. Это рабочий каркас, а не псевдокод. Такой подход - основа того, как устроены модули terraform: модуль это и есть набор ресурсов с входами variable и выходами output.

Типичные грабли
  • Секрет в default. Не клади пароль или токен в default переменной и не коммить tfvars с секретами. *.tfvars сразу в .gitignore, секреты - через TF_VAR_ в CI.
  • Думаешь, sensitive шифрует. Нет. Он лишь прячет значение из вывода консоли. В terraform state оно лежит как есть, защищай state отдельно (удалённый бекенд, шифрование).
  • Перепутал var и local. var.x - переменная ввода, local.x - локальное значение. Блок называется locals, а ссылка - local в единственном числе. Классическая опечатка.
  • Лишние ${} вокруг всего выражения. name = "${var.vm_name}" работает, но это лишний шум. Пиши name = var.vm_name, скобки только для подстановки внутрь строки.
  • Список вместо одного значения. network_interface это блок, у атрибутов обращайся через индекс: network_interface[0].nat_ip_address, а не просто .nat_ip_address.
Кстати, всё описанное работает один в один и в OpenTofu - синтаксис variable, output и locals у форка идентичен Terraform, переучиваться не придётся.

Мини-лаба

Повтори руками за 15 минут:
  • Вынеси из своего конфига ВМ имя, зону и количество ядер в три переменные с type и description.
  • Добавь validation на cores: разреши только значения от 1 до 8.
  • Создай dev.tfvars и prod.tfvars с разными значениями, прогони terraform plan с каждым через -var-file и сравни план.
  • Добавь два output: внешний IP и fqdn. Сделай apply (или хотя бы plan) и убедись, что значения видны.
  • Заведи один local name_prefix и собери из него имя ВМ.
Контрольные вопросы
  • Чем variable отличается от local и когда выбираешь каждый?
  • Какой источник значения переменной сильнее: default, файл *.tfvars или флаг -var?
  • Что на самом деле делает sensitive = true и от чего он НЕ защищает?
  • Когда конструкция ${} обязательна, а когда её надо убрать?
Итог: что запомнить

Переменные ввода превращают жёсткий конфиг в настраиваемый шаблон - база гибкого iac. variable - вход снаружи с type, default, description, validation и sensitive. Значения летят из default, *.tfvars, TF_VAR_ и -var, и чем ближе источник к команде, тем он сильнее. output отдаёт результаты после apply - внешний IP, fqdn, секреты под sensitive. locals - промежуточные вычисления внутри конфига. К переменной обращаешься через var.имя, к локали через local.имя, ${} нужен только для подстановки в строку. Освоил это - считай, ты на шаг от полноценных модулей terraform.
👍1 ❤️2 🔥4 😄 🤔2
Аватара пользователя
blkhwk
Сообщения: 1
Зарегистрирован: 19 май 2026, 04:05

Re: Переменные ввода и выходные значения в Terraform

Сообщение blkhwk »

Спасибо, наконец дошло чем locals от variable отличается. До этого пихал все в переменные подряд и не понимал зачем local вообще нужен.
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
frogggy
Сообщения: 1
Зарегистрирован: 21 май 2026, 02:18

Re: Переменные ввода и выходные значения в Terraform

Сообщение frogggy »

А подскажите, если я положу секрет в TF_VAR_ в CI, он же все равно в state светится открытым? Получается sensitive больше для красоты вывода, а реальную защиту надо отдельно делать на бекенд?
👍3 ❤️1 🔥 😄 🤔
Ответить
← Предыдущая глава
Веб-сервер на ВМ: метаданные, user-data и группы безопасности
Следующая глава →
Кластер ВМ: группа экземпляров Yandex Compute Instance Group

Все главы курса «Terraform: инфраструктура как код на Yandex Cloud»

Поделиться темой: ✈ Telegram VK
Похожие запросы: terraform yandex cloud с чего начать новичкукак установить terraform и opentofu на linuxчто такое terraform state и tfstate простыми словамиудаленный backend terraform на object storage yandex cloudчто такое инфраструктура как код iac простыми словамиterraform plan и apply что делают и чем отличаются

Вернуться в «Terraform: инфраструктура как код на Yandex Cloud»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость