Анатомия resource-блока
resource "aws_s3_bucket" "demo" {bucket = "my-bucket-12345"
tags = {Owner = "student"
}
}
Здесь четыре важные штуки:
- Ключевое слово
resource, говорим Terraform «это создаваемая сущность». - Тип ресурса
"aws_s3_bucket", что именно. Тип определяется провайдером. У AWS-провайдера их 800+:aws_s3_bucket,aws_instance,aws_iam_roleи так далее. - Имя ресурса
"demo", наше внутреннее имя. Используем чтобы ссылаться на этот ресурс из других мест HCL:aws_s3_bucket.demo.id. - Тело блока, аргументы. Что-то обязательно (
bucket), что-то опционально (tags).
Имя, это только внутри Terraform. В AWS бакет будет называться my-bucket-12345 (значение аргумента bucket). А demo, это просто как переменная в коде.
Аргументы vs атрибуты
Эти два слова легко перепутать.
- Аргументы (arguments), то, что вы пишете в HCL. Их вы задаёте:
bucket = "...",region = "...". - Атрибуты (attributes), то, что возвращает облако после создания. Их вы читаете:
aws_s3_bucket.demo.id,aws_s3_bucket.demo.arn.
Часть атрибутов известна сразу (то, что вы сами написали в аргументах). Часть, только после apply (например, id, arn, creation_date). До apply в плане они будут показаны как (known after apply).
Адрес ресурса
Любой ресурс имеет уникальный адрес внутри проекта: тип.имя.
aws_s3_bucket.demo # один ресурс
aws_s3_bucket.demo.bucket # его атрибут "bucket"
aws_s3_bucket.demo.arn # его атрибут "arn"
Адрес стабилен между запусками. Если переименуете "demo" в "main", для Terraform это будет «удалить старый, создать новый», даже если в облаке ресурс не изменился. Чтобы избежать пересоздания при переименовании, используйте блок moved {} (advanced).
Ссылки между ресурсами
Самое полезное, связывать ресурсы между собой:
resource "aws_s3_bucket" "demo" {bucket = "my-bucket-12345"
}
resource "aws_s3_bucket_versioning" "demo" {bucket = aws_s3_bucket.demo.id # ← ссылка на bucket выше
versioning_configuration {status = "Enabled"
}
}
Когда Terraform видит aws_s3_bucket.demo.id, он понимает: «сначала надо создать тот бакет, потом этот ресурс». Это автоматический граф зависимостей. См. tf-depends-on.
Несколько одинаковых ресурсов
Если нужно три похожих бакета, есть два способа:
# Способ 1: count, индексируется по числу
resource "aws_s3_bucket" "many" {count = 3
bucket = "bucket-${count.index}"}
# Способ 2: for_each, индексируется по ключу
resource "aws_s3_bucket" "regional" {for_each = toset(["us", "eu", "ap"])
bucket = "bucket-${each.key}"}
Адрес каждого:
aws_s3_bucket.many[0],aws_s3_bucket.many[1],aws_s3_bucket.many[2]aws_s3_bucket.regional["us"],aws_s3_bucket.regional["eu"], ...
См. tf-count-for-each, там детали про когда что.
Подводные камни
-
Имя ресурса не равно name в облаке. Поменяли HCL
"demo"→"main". Terraform пересоздаст ресурс (drop + create), даже если содержимое идентично. Если боитесь, используйтеmoved {}блок. -
Аргументы строго типизированы. Если
bucketожидает string, а вы напишете число,terraform validateупадёт. Это хорошо: ошибки ловятся до облака. -
(known after apply), нормально. Не пугайтесь увидев это в плане. Это просто значит «значение появится после создания». Например,idбакета: сам bucket name, и его Terraform знает сразу; аarn, только после ответа API. -
Не все аргументы поддерживают обновление. Некоторые атрибуты ресурса нельзя поменять без пересоздания (например, тип EC2-инстанса). Terraform в плане покажет
-/+ resource ..., это «снести и создать заново». Будьте осторожны: данные пропадают. -
lifecycle блок защищает от случайностей. См. tf-resource-lifecycle:
prevent_destroy = trueзапрещает удаление,ignore_changesигнорирует drift по конкретным атрибутам.