Источники данных и terraform_remote_state: связываем компоненты

Рейтинг: 61% · 6 голосов
Подробный курс по Terraform и OpenTofu на примерах Yandex Cloud: ресурсы и провайдеры, состояние и бэкенды, модули, циклы и условия HCL, секреты и Lockbox, тестирование, CI/CD и командная работа. С актуализацией на 2026 (Terraform 1.3-1.10, OpenTofu).
Ответить
Аватара пользователя
Vlad_DevOps
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Источники данных и terraform_remote_state: связываем компоненты

Сообщение Vlad_DevOps »

Оглавление курса (47)
  1. Что такое инфраструктура как код и зачем она нужна
  2. Категории инструментов IaC: чем отличаются Ansible, Packer, Kubernetes и Terraform
  3. Чем Terraform отличается от Ansible, Pulumi и CloudFormation
  4. Как работает Terraform под капотом и кто такой OpenTofu
  5. Установка Terraform и OpenTofu, подготовка Yandex Cloud
  6. Первый ресурс: разворачиваем виртуальную машину в Yandex Cloud
  7. Веб-сервер на ВМ: метаданные, user-data и группы безопасности
  8. Переменные ввода и выходные значения в Terraform
  9. Кластер ВМ: группа экземпляров Yandex Compute Instance Group
  10. Балансировщик нагрузки: Application Load Balancer в Yandex Cloud
  11. Состояние Terraform: что такое tfstate и чем опасен локальный файл
  12. Удалённое хранилище состояния: бэкенд на Yandex Object Storage
  13. Изоляция состояния: рабочие области против раскладки по папкам
  14. Источники данных и terraform_remote_state: связываем компоненты (вы здесь)
  15. Модули Terraform: переиспользуем инфраструктуру
  16. Входные, локальные и выходные переменные модуля
  17. Версионирование модулей и подводные камни
  18. Циклы в Terraform: параметр count
  19. Циклы в Terraform: for_each по множествам и картам
  20. Выражения for и строковые директивы
  21. Условная логика: count-трюк, for_each и директива if
  22. Встроенные функции, типы и выражения HCL
  23. Развёртывание без простоя: create_before_destroy
  24. Подводные камни Terraform и рефакторинг с блоком moved
  25. Управление секретами: основы и типы
  26. Инструменты управления секретами: Yandex Lockbox, Vault, SOPS
  27. Аутентификация провайдера и секреты: сервисные аккаунты и OIDC
  28. Секреты в ресурсах и состоянии, ephemeral-значения
  29. Провайдеры Terraform: установка, версии, required_providers
  30. Несколько копий одного провайдера: alias и мультизона
  31. Несколько провайдеров и аккаунтов: configuration_aliases
  32. Terraform, Docker и Kubernetes: Managed Kubernetes в Yandex Cloud
  33. Код Terraform промышленного уровня: почему это долго
  34. Мелкие компонуемые модули вместо монолита
  35. Тестируемые модули и проверки: validation, precondition, postcondition
  36. Версионирование, публикация модулей и Terragrunt
  37. Ручное тестирование Terraform и очистка ресурсов
  38. Автоматические тесты на Terratest: модульные тесты
  39. Интеграционные и сквозные тесты, пирамида тестирования
  40. Нативный terraform test и статический анализ
  41. Внедрение Terraform в команде: процессы и культура
  42. Конвейер развёртывания прикладного кода
  43. Конвейер инфраструктурного кода и золотое правило Terraform
  44. Стиль, ревью и CI/CD-инструменты: Atlantis, TACOS, policy as code
  45. Что нового в Terraform 1.3-1.10: моды, импорт, провайдер-функции, Stacks
  46. OpenTofu в 2026: чем живёт форк и как мигрировать
  47. Сертификация HashiCorp Terraform Associate и карьера
Представь ситуацию. Сеть в Yandex Cloud у тебя уже создана - кто-то поднял VPC, подсети, маршруты полгода назад, и оно живёт. А ты сегодня пишешь terraform для нового приложения и тебе нужен subnet_id, чтобы воткнуть туда виртуалку. Что делают новички? Лезут в консоль, копируют ID подсети, вставляют строкой прямо в код. Через месяц подсеть пересоздали, ID поменялся, а у тебя в конфиге зашит мёртвый идентификатор. terraform plan apply отрабатывает, а виртуалка не поднимается. Знакомо?

Эта боль решается двумя инструментами: источниками данных (data sources) и чтением чужого состояния через terraform_remote_state. Оба про одно и то же - перестать хардкодить и начать ссылаться на реальные ресурсы. В этом уроке разберём, как инфраструктура как код перестаёт быть монолитом и распадается на слабо связанные компоненты, которые умеют читать данные друг у друга. Тема одинаково актуальна и для terraform, и для opentofu - синтаксис идентичен.

Data source: читаем, а не создаём

Ресурс (resource) - это то, что terraform создаёт и чем владеет. Источник данных (data source) - это запрос на чтение того, что уже существует. Ты ничего не создаёшь, ничего не удаляешь, просто на этапе terraform plan провайдер идёт в API Yandex Cloud, спрашивает "а дай-ка мне вот это" и возвращает атрибуты. Дальше ты используешь их как обычные значения.

Самый частый и самый полезный пример - найти ID последнего образа Ubuntu. Образы в YC лежат в публичной папке standard-images и регулярно обновляются: вышел свежий патч ядра - появился новый image_id. Хардкодить конкретный ID - значит обречь себя на устаревшее ядро навсегда. Вместо этого мы спрашиваем образ по семейству (family), и провайдер сам отдаёт самый свежий в этом семействе.

Код: Выделить всё

data "yandex_compute_image" "ubuntu" {
  family = "ubuntu-2204-lts"
}

output "image_id" {
  value = data.yandex_compute_image.ubuntu.id
}
Обрати внимание на пару деталей из документации провайдера. Если ты указываешь family без folder_id, поиск идёт именно в папке standard-images - то, что нам и нужно. Должно быть задано одно из трёх: image_id, family или name. У результата куча полезных атрибутов: id, min_disk_size, os_type, product_ids, size, status. Особенно ценен min_disk_size - его можно подставить в размер загрузочного диска, чтобы не угадывать вручную.

Теперь подключим подсеть, которую создал не ты. Источник yandex_vpc_subnet ищет подсеть по subnet_id или по name:

Код: Выделить всё

data "yandex_vpc_subnet" "app" {
  name = "app-subnet-ru-central1-a"
}

data "yandex_compute_image" "ubuntu" {
  family = "ubuntu-2204-lts"
}

resource "yandex_compute_instance" "app" {
  name        = "app-01"
  platform_id = "standard-v3"
  zone        = data.yandex_vpc_subnet.app.zone

  resources {
    cores  = 2
    memory = 2
  }

  boot_disk {
    initialize_params {
      image_id = data.yandex_compute_image.ubuntu.id
      size     = data.yandex_compute_image.ubuntu.min_disk_size
    }
  }

  network_interface {
    subnet_id = data.yandex_vpc_subnet.app.id
    nat       = true
  }
}
Смотри, как красиво всё сцепилось. Зону мы взяли из подсети (атрибут zone есть в data source), subnet_id - из неё же, image_id и размер диска - из образа. Ни одного захардкоженного идентификатора. Пересоздадут подсеть, выйдет новый Ubuntu - terraform сам подхватит актуальные значения при следующем plan.

Есть ещё один служебный, но крайне удобный источник - yandex_client_config. Он отдаёт то, чем сконфигурирован сам провайдер: cloud_id, folder_id, zone и короткоживущий iam_token. Вызывается вообще без аргументов:

Код: Выделить всё

data "yandex_client_config" "client" {}

output "current_folder" {
  value = data.yandex_client_config.client.folder_id
}
iam_token из него обычно скармливают провайдеру kubernetes, чтобы не хранить статичный токен в коде. А folder_id удобно использовать в выводах и тегах, чтобы конфиг не зависел от того, в какой папке его запускают.

Изображение

terraform_remote_state: один пишет, другой читает

Data source хорош, когда ресурс существует "где-то в облаке" и ты просто ищешь его по имени. Но часто бывает иначе: сеть тоже описана в terraform, просто в другом проекте, со своим terraform state. Команда сети владеет VPC, ты владеешь приложением. Как тебе достать ID подсети из их состояния, не лазая в консоль?

Тут выходит на сцену terraform_remote_state - источник данных, который читает не API облака, а чужой файл состояния напрямую. Механика простая и состоит из двух половинок.

Половинка первая - тот, кто публикует. Проект сети объявляет нужные значения через output. Всё, что попало в output, записывается в terraform state и становится доступным наружу:

Код: Выделить всё

# проект network/outputs.tf
output "subnet_app_id" {
  value = yandex_vpc_subnet.app.id
}

output "network_id" {
  value = yandex_vpc_network.main.id
}
Половинка вторая - тот, кто читает. Проект приложения подключает чужое состояние, указывая, где оно лежит. State сети хранится в Object Storage (S3-совместимый бэкенд YC), и мы даём ссылку на тот же бакет и ключ:

Код: Выделить всё

data "terraform_remote_state" "network" {
  backend = "s3"
  config = {
    bucket   = "tf-states-prod"
    key      = "network/terraform.tfstate"
    endpoints = { s3 = "https://storage.yandexcloud.net" }
    region   = "ru-central1"
    skip_region_validation      = true
    skip_credentials_validation = true
  }
}

resource "yandex_compute_instance" "app" {
  name = "app-01"
  # ...
  network_interface {
    subnet_id = data.terraform_remote_state.network.outputs.subnet_app_id
    nat       = true
  }
}
Доступ к опубликованным значениям идёт через .outputs.имя. Подчёркиваю: читаются ТОЛЬКО outputs. Если значение не объявлено как output в проекте сети - ты его не увидишь, даже если оно есть в их state. Это и есть контракт между компонентами: сеть явно решает, что отдавать наружу, а что оставить внутренним делом.

Так рождается слабая связанность (loose coupling). Проект сети ничего не знает о приложении. Проект приложения знает о сети ровно одно - имя бакета и набор её outputs. Меняешь внутренности сети как угодно, лишь бы контракт outputs оставался прежним - и приложение даже не заметит. Это та же идея, что интерфейсы в коде, только для инфраструктуры.

Что выбрать: remote_state или прямой data source

Часто одну и ту же задачу можно решить обоими способами, и новички путаются. Возьмём наш subnet_id.

Через terraform_remote_state ты читаешь его из чужого состояния по контракту outputs. Через прямой data source yandex_vpc_subnet ты читаешь подсеть из API облака по имени - вообще не зная и не интересуясь, кто и каким terraform её создал.

Когда что брать? Если у компонентов общий владелец и общий процесс - связка через remote_state чище: явный контракт, видно зависимости, никакой магии с именами. Если же ресурс создан кем угодно (другой командой, кликами в консоли, вообще не terraform) - прямой data source надёжнее, он не требует доступа к чужому state и не ломается, если соседи переименовали output. Грубое правило: remote_state - для своих модулей terraform внутри одной экосистемы, data source - для всего внешнего. Кстати, модули terraform тут ни при чём - это про разбиение кода внутри одного state, а мы говорим про связь между разными state.

Типичные грабли
  • Думают, что data source создаёт ресурс. Нет. Удалишь блок data - в облаке ничего не пропадёт. Это чтение, а не владение.
  • Виртуалки пересоздаются на ровном месте. Образ Ubuntu обновился, image_id изменился, и terraform хочет пересоздать VM, чтобы поменять диск. Если это не нужно - добавь в ресурс

    Код: Выделить всё

    lifecycle { ignore_changes = [boot_disk[0].initialize_params[0].image_id] }
    . Тогда уже поднятые машины останутся на старом образе, а новые будут стартовать со свежего.
  • Пытаются прочитать значение, которое не объявлено как output. terraform_remote_state видит только outputs. Нет output - нет значения, хоть оно сто раз в чужом state лежит.
  • Циклическая зависимость. Проект A читает remote_state B, а B читает remote_state A. terraform на это справедливо ругается. Разрывай цикл, направляй зависимости в одну сторону.
  • Хардкод вместо data source. Скопировать ID из консоли быстрее на 10 секунд сегодня и дороже на час отладки через месяц. Не делай так.
Мини-лаба

Повтори руками, без этого в голове не уляжется:
  • Напиши data "yandex_compute_image" по family "ubuntu-2204-lts" и выведи через output его id и min_disk_size. Запусти terraform plan, посмотри, какой реальный image_id подставился.
  • Добавь data "yandex_vpc_subnet" по имени существующей подсети и подними yandex_compute_instance, взяв subnet_id и zone из этого источника. Проверь, что ни одного ID руками ты не вписал.
  • Сделай второй проект: в нём через output опубликуй любое значение, примени, а потом из первого проекта прочитай его через terraform_remote_state с бэкендом s3 на Object Storage.
  • Удали один из data-блоков и запусти plan. Убедись, что в облаке ничего не удаляется - меняется только то, что на этот источник ссылалось.
Контрольные вопросы
  • Чем data source отличается от resource и что произойдёт с облаком, если удалить блок data?
  • Почему поиск образа по family предпочтительнее, чем захардкоженный image_id, и какой атрибут отдаёт самый свежий образ семейства?
  • Какие именно значения видит terraform_remote_state в чужом состоянии и что нужно сделать в проекте-источнике, чтобы значение стало доступным?
  • В каком случае ты выберешь прямой data source yandex_vpc_subnet, а не чтение через terraform_remote_state?
Итог

Запомни три вещи. Первое: data source - это чтение существующего, а не создание; через него мы достаём из API Yandex Cloud актуальный image_id последнего Ubuntu, нужную подсеть и параметры клиента, не зашивая идентификаторы в код. Второе: terraform_remote_state читает чужой terraform state и видит только то, что сосед явно отдал через output - это контракт между компонентами. Третье: всё это про слабую связанность - инфраструктура как код перестаёт быть одним комом и превращается в набор компонентов, которые аккуратно ссылаются друг на друга, а не копируют ID из консоли. Перестань хардкодить - и половина ночных инцидентов отвалится сама.
👍5 ❤️3 🔥3 😄 🤔
Аватара пользователя
Vsal1en
Сообщения: 1
Зарегистрирован: 11 май 2026, 02:29

Re: Источники данных и terraform_remote_state: связываем компоненты

Сообщение Vsal1en »

Спасибо, наконец понял разницу между data и resource. До этого реально копировал image_id руками из консоли и удивлялся почему ядро старое.
👍1 ❤️1 🔥 😄 🤔
Аватара пользователя
mihanyt5
Сообщения: 1
Зарегистрирован: 19 май 2026, 21:56

Re: Источники данных и terraform_remote_state: связываем компоненты

Сообщение mihanyt5 »

А правило про ignore_changes на image_id норм работает в проде? боюсь что виртуалки сами пересоздадутся ночью когда новый ubuntu выйдет
👍 ❤️1 🔥 😄 🤔
Ответить
← Предыдущая глава
Изоляция состояния: рабочие области против раскладки по папкам
Следующая глава →
Модули Terraform: переиспользуем инфраструктуру

Все главы курса «Terraform: инфраструктура как код на Yandex Cloud»

Поделиться темой: ✈ Telegram VK
Похожие запросы: terraform yandex cloud с чего начать новичкукак установить terraform и opentofu на linuxчто такое terraform state и tfstate простыми словамиудаленный backend terraform на object storage yandex cloudчто такое инфраструктура как код iac простыми словамиterraform plan и apply что делают и чем отличаются

Вернуться в «Terraform: инфраструктура как код на Yandex Cloud»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость