Зачем нужны переменные
Без переменных каждое окружение требует свой HCL-файл. С переменными, один HCL и три набора значений.
Плохо:
resource "aws_s3_bucket" "demo" {bucket = "my-app-prod-logs" # хардкод
}
Хорошо:
variable "env" {type = string
default = "dev"
}
resource "aws_s3_bucket" "demo" { bucket = "my-app-${var.env}-logs"}
Теперь один и тот же HCL можно запустить с -var="env=prod" для прода, без правки кода.
Минимальная переменная
variable "bucket_name" {}Это валидная переменная. Тип не объявлен (будет any), description не задан, default не задан → значит, обязательно передать значение снаружи. Если не передал, apply упадёт с вопросом.
Все поля variable
variable "bucket_name" {type = string # ожидаемый тип (см. Ниже)
description = "Имя S3-бакета. Должно быть глобально уникальным."
default = "my-default-bucket-12345" # если не задано снаружи
nullable = false # запрет на null (default true)
sensitive = false # маркер «не светить в логах»
ephemeral = false # только в памяти, не в state (1.10+)
validation {condition = length(var.bucket_name) >= 3 && length(var.bucket_name) <= 63
error_message = "Имя бакета должно быть длиной 3-63 символа."
}
validation { condition = can(regex("^[a-z0-9][a-z0-9.-]*[a-z0-9]$", var.bucket_name))error_message = "Имя бакета: только нижний регистр, цифры, точки и дефисы."
}
}
Не все поля обязательны. Достаточно type и (если нет default): передачи снаружи.
Типы переменных
Можно простые типы и сложные:
# примитивы
variable "region" { type = string }variable "count" { type = number }variable "enabled" { type = bool }# коллекции
variable "tags" { type = map(string) }variable "azs" { type = list(string) }variable "values" { type = set(string) } # уникальные, неупорядоченные# объект (как map, но с фиксированной структурой)
variable "db" { type = object({instance_class = string
allocated_storage = number
multi_az = bool
})
}
# без типа, всё подходит (плохая практика для прода)
variable "anything" {}Если значение не подходит по типу. Terraform упадёт с понятной ошибкой. См. hcl-types.
Validation, проверки на корректность
Условия, которые проверяются перед использованием переменной:
variable "env" {type = string
description = "Окружение (dev/staging/prod)"
validation {condition = contains(["dev", "staging", "prod"], var.env)
error_message = "env должен быть один из: dev, staging, prod."
}
}
Validation выполняется при plan. Если condition вернёт false, apply не запустится, и пользователь увидит error_message.
Можно несколько validation-блоков для одной переменной. Все проверяются.
sensitive, защита от логирования
variable "db_password" {type = string
sensitive = true
}
Сейчас:
- В
planиapplyзначение маскируется на(sensitive value). - В output, который ссылается на эту переменную, тоже маскируется (если только output не помечен sensitive отдельно).
- В state-файле значение всё равно сохраняется в открытом виде. sensitive, это про лог-вывод, не про шифрование.
Для реальной секретности используйте Vault, AWS Secrets Manager, или хотя бы зашифрованный remote state с ограниченным доступом.
Использование
variable "env" {type = string
default = "dev"
}
resource "aws_s3_bucket" "demo" { bucket = "my-app-${var.env}-bucket" tags = {Environment = var.env
}
}
Префикс var., обязателен. Без него Terraform решит, что это resource или data.
Подводные камни
-
type объявляйте всегда. «Без типа» работает, но любая ошибка проявится поздно. Тип ловит проблему на стадии валидации.
-
default не означает «значение по умолчанию». Это значение если не задано снаружи. Если задано, default игнорируется.
-
sensitive не равно шифрованию. Маскирует только в выводе CLI. В state, открытым текстом.
-
Переменные нельзя ссылаться друг на друга.
variable "b" { default = var.a }, невалидно. Для зависимых выражений используйте tf-locals. -
validation работает только на этап plan. Если значение получено из data-источника и оно "known after apply", validation может пропустить ошибку.
-
Переменные глобальны на конфигурацию. Нельзя «локальные» переменные внутри блока. Если нужна локальная переменная, это
locals { ... }.