variable vs locals vs output
Три родственных, но разных вещи:
- variable, вход. Значение приходит снаружи (CLI, .tfvars, env).
- locals, внутреннее. Вычисляется из других значений, видно только в этом HCL.
- output, выход. Значение видно после apply / другим модулям.
Если значение приходит извне, variable. Если вы его используете в нескольких местах после вычисления, locals. Если хотите показать наружу, output.
Базовый синтаксис
variable "env" {type = string
default = "dev"
}
variable "app_name" {type = string
default = "my-app"
}
locals { name_prefix = "${var.app_name}-${var.env}" common_tags = {Project = var.app_name
Environment = var.env
ManagedBy = "terraform"
}
}
resource "aws_s3_bucket" "logs" { bucket = "${local.name_prefix}-logs"tags = local.common_tags
}
resource "aws_s3_bucket" "data" { bucket = "${local.name_prefix}-data"tags = local.common_tags
}
Каждый ресурс использует общий префикс и общие теги, не повторяя себя.
Префикс, local.имя (без s!). Объявление, locals { ... } (со s).
Локалы могут ссылаться на другие локалы
locals { base_name = "${var.app_name}-${var.env}" bucket_name = "${local.base_name}-bucket" log_prefix = "${local.bucket_name}/logs/"}
Цепочка вычисляется автоматически. Terraform строит граф и разрешает зависимости.
Локалы могут содержать сложные выражения
locals {enable_https = var.env == "prod" || var.env == "staging"
azs = data.aws_availability_zones.available.names
instance_count = var.env == "prod" ? 3 : 1
subnet_cidrs = [
for i in range(local.instance_count) :
cidrsubnet(var.vpc_cidr, 8, i)
]
}
Можно условия, циклы, функции, всё что разрешено в HCL expressions. См. tf-conditional-expression и tf-functions-collection.
Несколько locals блоков, нормально
# general.tf
locals { name_prefix = "${var.app_name}-${var.env}"}
# tags.tf
locals { common_tags = {Project = var.app_name
Environment = var.env
}
}
# network.tf
locals {public_subnet_count = 3
}
В одном проекте может быть сколько угодно locals блоков. Terraform мерджит их в один namespace local.*. Это удобно для разделения по файлам.
Но: имена в разных locals блоках не должны пересекаться. local.foo = "a" в одном файле и local.foo = "b" в другом, ошибка валидации.
Когда использовать локалы
Хорошие случаи:
- Общий префикс имён.
${local.name_prefix}-bucket,${local.name_prefix}-role, и так далее. - Общие теги. Одна map с тегами проекта, прикладывается к каждому ресурсу.
- Вычисления из нескольких переменных. Из
envиregionслепить ARN, например. - Условная логика.
local.enable_https = var.env == "prod". - Преобразования.
local.azs = data.aws_availability_zones.available.names, короткое имя для длинного выражения.
Когда не надо:
- Если значение используется один раз, пишите inline.
- Если значение приходит снаружи, это variable.
Подводные камни
-
locals не для секретов. Они хранятся в state в открытом виде, без какого-либо
sensitive-маркера (sensitive есть только у variable и output). -
locals не могут ссылаться на сами себя.
local.x = local.x + 1, ошибка. Terraform, не язык программирования с итеративным состоянием. -
Не злоупотребляйте. Если в HCL половина файла, это блок
locals, кодcчитать сложнее. Это знак, что часть значений лучше вынести в variables. -
localvslocals, путаница. Объявление,locals { ... }(множественное). Использование,local.x(единственное, безs). Никакихlocal.xбезlocalпрефикса и никакихlocals.xсs. -
Локалы не доступны в .tfvars. В .tfvars пишутся только variables. Локалы вычисляются в HCL.
-
При переименовании local, появляется в diff? Нет. Локалы не хранятся в state, только в выражениях. Поменяли имя. Terraform пересчитает все ссылки, в облако ничего не уйдёт (если итоговое значение не поменялось).