# Блок resource: главный кирпич Terraform _Ресурсы и data-источники · TerraformLab Knowledge Base_ **TL;DR:** resource, это блок, который говорит Terraform «создай мне такую штуку в облаке». У него три части: тип ресурса (что это), имя (как зовём внутри), и аргументы (как настроить). 90% времени в Terraform, это написание таких блоков. ## Анатомия resource-блока ```hcl resource "aws_s3_bucket" "demo" { bucket = "my-bucket-12345" tags = { Owner = "student" } } ``` Здесь четыре важные штуки: 1. **Ключевое слово `resource`**, говорим Terraform «это создаваемая сущность». 2. **Тип ресурса** `"aws_s3_bucket"`, что именно. Тип определяется провайдером. У AWS-провайдера их 800+: `aws_s3_bucket`, `aws_instance`, `aws_iam_role` и так далее. 3. **Имя ресурса** `"demo"`, наше внутреннее имя. Используем чтобы ссылаться на этот ресурс из других мест HCL: `aws_s3_bucket.demo.id`. 4. **Тело блока**, аргументы. Что-то обязательно (`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)`. ## Адрес ресурса Любой ресурс имеет уникальный адрес внутри проекта: `тип.имя`. ```hcl aws_s3_bucket.demo # один ресурс aws_s3_bucket.demo.bucket # его атрибут "bucket" aws_s3_bucket.demo.arn # его атрибут "arn" ``` Адрес стабилен между запусками. Если переименуете `"demo"` в `"main"`, для Terraform это будет «удалить старый, создать новый», даже если в облаке ресурс не изменился. Чтобы избежать пересоздания при переименовании, используйте блок `moved {}` (advanced). ## Ссылки между ресурсами Самое полезное, связывать ресурсы между собой: ```hcl 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](/terraform/kb/tf-depends-on.md). ## Несколько одинаковых ресурсов Если нужно три похожих бакета, есть два способа: ```hcl # Способ 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](/terraform/kb/tf-count-for-each.md), там детали про когда что. ## Подводные камни - **Имя ресурса не равно 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](/terraform/kb/tf-resource-lifecycle.md): `prevent_destroy = true` запрещает удаление, `ignore_changes` игнорирует drift по конкретным атрибутам. ## Команды ```bash terraform state list ``` Показать все ресурсы которые сейчас в state: со своими адресами. ```bash terraform state show aws_s3_bucket.demo ``` Показать все атрибуты конкретного ресурса (включая те, которые вы не задавали). ```bash terraform plan -target=aws_s3_bucket.demo ``` Показать план только для одного ресурса. Полезно если plan большого проекта медленный. ## См. также - [HCL: язык, на котором пишут Terraform](/terraform/kb/hcl-syntax.md) - [data-блок: читаем то, что уже есть в облаке](/terraform/kb/tf-data-source.md) - [lifecycle: управляем поведением resource](/terraform/kb/tf-resource-lifecycle.md) - [Зависимости ресурсов: явные и неявные](/terraform/kb/tf-depends-on.md) - [Ссылки в HCL: как читать aws_s3_bucket.demo.bucket](/terraform/kb/tf-references.md) - [terraform apply: применить план в реальном облаке](/terraform/kb/tf-apply.md)