Что такое утилитарный провайдер
Большинство провайдеров (aws, kubernetes, github) представляют
внешнюю систему. API облака или сервиса. Утилитарные провайдеры,
это не API, а функциональность языка: генератор случайных значений,
таймер, триггер. Они дают то, чего нет в HCL встроено.
Все они official HashiCorp, версии стабильные, breaking-changes редкие.
random
Генерация значений, детерминированно в пределах state'а, случайно при создании.
terraform { required_providers { random = {source = "hashicorp/random"
version = "~> 3.6"
}
}
}
resource "random_id" "suffix" {byte_length = 4
}
resource "aws_s3_bucket" "demo" { bucket = "linuxlab-${random_id.suffix.hex}"}
random_id.suffix.hex, 8-символьный hex (4 байта * 2). Уникален при
создании, дальше зафиксирован в state. На каждый последующий plan,
тот же.
Подвиды
| Resource | Что генерирует | Главное use-case |
|---|---|---|
random_id | Bytes → hex/base64 | Уникальные суффиксы имён |
random_string | Строка из символов | Имена, пароли (не очень) |
random_password | Строка с минимумом классов | Реальные пароли (sensitive) |
random_pet | Пара слов «honest-zebra» | Человекочитаемые имена для лабы |
random_uuid | UUID v4 | Корреляция, request IDs |
random_integer | Число в диапазоне | Случайный порт, индекс |
random_shuffle | Перемешивает список | AZ-распределение |
keepers, перегенерация при изменении
resource "random_id" "suffix" {byte_length = 4
keepers = {bucket_name = var.bucket_name
}
}
Если var.bucket_name поменялся, random_id пересоздаётся → новый hex
→ новый бакет. Связка «при смене N → новый случай».
Без keepers значение никогда не меняется без явного taint /
-replace.
time
Манипуляции с временем в HCL.
terraform { required_providers { time = {source = "hashicorp/time"
version = "~> 0.12"
}
}
}
time_static, momentum при создании
resource "time_static" "created_at" {}resource "aws_s3_bucket" "demo" { bucket = "linuxlab-${formatdate("YYYYMMDD", time_static.created_at.rfc3339)}"}
Фиксирует timestamp в state при первом apply. Дальше, не меняется. Полезно для иммутабельных меток (имя бакета содержит дату создания).
time_sleep, задержка в apply
resource "aws_iam_role" "app" {name = "app"
# ...
}
resource "time_sleep" "wait_for_iam" {depends_on = [aws_iam_role.app]
create_duration = "30s"
}
resource "aws_eks_cluster" "demo" {depends_on = [time_sleep.wait_for_iam]
# ...
}
IAM-роль создана, но AWS eventually consistent, пока propagation, eks
не видит роль. time_sleep ждёт 30 секунд между ними.
Это обходной путь, не решение. Если можно увидеть готовность через data source, лучше так. Если нет, sleep. Но он есть.
time_rotating
resource "time_rotating" "cert" {rotation_days = 30
}
Атрибут id меняется каждые 30 дней. В связке с random_password
keepersдаёт «ротировать пароль раз в месяц». Редко полезно, обычно секрет-менеджеры (Vault) делают это лучше.
null_resource (устаревший)
Старый паттерн, «не-ресурс» из провайдера null, чтобы повесить
triggers и provisioner:
resource "null_resource" "bootstrap" { triggers = {version = var.script_version
}
provisioner "local-exec" {command = "./bootstrap.sh"
}
}
Работает до сих пор, но не используется в новом коде. Заменён на
terraform_data.
terraform_data (с TF 1.4+)
Встроен в Terraform, не нужен отдельный provider.
resource "terraform_data" "bootstrap" {input = var.script_version
triggers_replace = [var.script_version]
provisioner "local-exec" {command = "./bootstrap.sh"
}
}
Преимущества:
- Не требует
required_providers.null, встроен. - Может хранить значение (
input): становится доступен черезterraform_data.bootstrap.output. triggers_replace, список, при изменении любого → ресурс пересоздаётся.
terraform_data как «buffer» для значения
variable "image_tag" {type = string
default = "latest"
}
resource "terraform_data" "image_version" {input = var.image_tag
}
resource "aws_ecs_task_definition" "app" {# ...
container_definitions = jsonencode([{name = "app"
image = "myrepo/app:${terraform_data.image_version.output}"}])
lifecycle {replace_triggered_by = [terraform_data.image_version]
}
}
При смене tag, task definition пересоздаётся принудительно через
replace_triggered_by. Это паттерн «канарейка»: связать lifecycle
тяжёлого ресурса с лёгким индикатором.
Когда какой провайдер
| Нужно | Используй |
|---|---|
| Уникальный суффикс имени | random_id |
| Сильный пароль | random_password |
| Метка времени создания | time_static |
| Подождать пока AWS «дойдёт» | time_sleep |
| Триггер пересоздания при изменении X | terraform_data с triggers_replace |
Прогнать local-exec при изменении | terraform_data с provisioner |
| Хранить вычисленное значение между resources | terraform_data.input/output |
Подводные камни
-
random в LocalStack, тот же что в реальном AWS. Этот провайдер не зависит от облака. Тесты с LocalStack полноценны для random/time/terraform_data.
-
random_passwordНЕ безопаснееrandom_string. Оба используют crypto/rand. Ноrandom_passwordмаркирован sensitive, не печатается в логах. Для секретов всегдаrandom_password, чтобы пароль не утёк черезterraform output/ plan-логи. -
Значение
random_*ROTAТE'ится только через-replaceили keepers. Простоapplyего не меняет. Это фича, не баг: иначе на каждом apply бакет назвался бы иначе. -
time_sleepтратит реальное время apply. 30s на каждом apply, плохо для CI. Используй только когда альтернатива не работает. -
null_resourcedeprecated, не запрещён. Старый код можно не мигрировать; новый, пиши наterraform_data. Между ними нет разницы в поведении, есть в эстетике и интегрированности. -
provisionerнаterraform_data, last resort. Idempotency не гарантирована, errors сложно обрабатывать, sandboxing нулевой. Замена,local-execчерезexternalprovider data source (см. tf-archive-external-http). -
randomресурс попадает в state с открытым значением. Это очевидно дляrandom_id, ноrandom_passwordтоже в state в открытом виде, sensitive только в выводе. Защищай state.