Data-источники: чтение существующего
Data-источник (data) — это окно в мир, которым Terraform не управляет: он читает уже существующие ресурсы и внешние данные, чтобы использовать их в своём конфиге.
Resource создаёт и владеет. Data только смотрит и не владеет. Если вы хотите подключиться к чужой VPC, найти свежий образ или прочитать аккаунт — это работа для data-источника.
Иногда нужно сослаться на то, что создано не вами: общая сеть от другой команды, актуальный AMI-образ от вендора, текущий регион. Создавать такие ресурсы вы не должны — но прочитать их атрибуты нужно. Для этого и существует data: это read-only запрос к API провайдера.
Resource против data
# data: ПРОЧИТАТЬ свежий образ Ubuntu
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu/images/*-22.04-*"]
}
}
# resource: ИСПОЛЬЗОВАТЬ прочитанное
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id # data.<type>.<name>.<attr>
instance_type = "t2.micro"
}
Адрес data-источника начинается с data.: data.aws_ami.ubuntu.id. Терраформ выполняет запрос на этапе plan, подставляя результат в зависимые ресурсы. Если данные зависят от ещё не созданного ресурса, чтение откладывается до apply.
Как работает под капотом
Data-источник с фильтрами работает как запрос к базе: провайдер возвращает список, фильтры его сужают, а most_recent выбирает свежайший. Смоделируем выбор AMI:
all_amis = [
{"id": "ami-001", "name": "ubuntu-22.04-2024-01", "owner": "099720109477"},
{"id": "ami-002", "name": "ubuntu-22.04-2024-06", "owner": "099720109477"},
{"id": "ami-003", "name": "debian-12-2024-06", "owner": "136693071363"},
]
def query(images, owners, name_prefix, most_recent=True):
found = [i for i in images
if i["owner"] in owners and i["name"].startswith(name_prefix)]
if not found:
raise ValueError("data.aws_ami: ничего не найдено!")
if most_recent:
found.sort(key=lambda i: i["name"], reverse=True)
return found[0]
ami = query(all_amis, ["099720109477"], "ubuntu-22.04")
print("Выбран AMI:", ami["id"], "-", ami["name"])
«Попробуй сам ▶» — фильтр по владельцу и префиксу + сортировка по дате дают свежий образ. Если ничего не нашлось — ошибка (частая боль на практике).
Частые ошибки
- Путать data и resource.
dataничего не создаёт; если написатьdata "aws_instance", ожидая создания сервера, — сервера не будет. - Фильтр без результата. Если
dataничего не нашёл, apply падает. Особенно коварно для образов, которые удаляют со временем. - Несколько совпадений без
most_recent. Если фильтр вернул много объектов, Terraform не знает, какой брать, и выдаёт ошибку.
Best practices
- Используйте data для всего, чем вы не владеете: чужие сети, общие образы, текущий аккаунт/регион.
- Делайте фильтры точными (
owners+ конкретный префикс), чтобы не поймать чужой объект. - Для образов, меняющихся со временем, фиксируйте конкретную версию там, где важна воспроизводимость.
Разбор глубже
Момент, когда data-источник читает данные, важнее, чем кажется. Если все его аргументы известны заранее, Terraform выполняет запрос на этапе plan — и результат сразу виден в плане. Но если data-источник зависит от атрибута ресурса, который ещё не создан, чтение откладывается до apply, и в плане на его месте будет (known after apply). Это объясняет загадочные ситуации, когда план не может показать финальные значения: он просто ещё не знает результата отложенного чтения. Понимание этой механики снимает массу вопросов на практике.
Особый и очень частый data-источник — это «информация о себе»: aws_caller_identity отдаёт ID текущего аккаунта, aws_region — текущий регион, aws_availability_zones — список доступных зон. Их используют, чтобы не хардкодить такие значения, а вычислять динамически: код, написанный через эти data-источники, автоматически адаптируется к тому аккаунту и региону, в котором его запускают. Это делает один и тот же модуль по-настоящему переносимым между средами без правок.
Стоит выработать привычку делать фильтры data-источников максимально строгими. Слишком широкий фильтр опасен вдвойне: он может вернуть несколько объектов (и Terraform упадёт с требованием уточнить), а может молча подцепить чужой ресурс — например, образ другой команды с похожим именем. Указание точного владельца, конкретного префикса и, где уместно, тегов превращает запрос из «найди что-нибудь похожее» в «найди ровно то, что я имею в виду». А для критичных к воспроизводимости мест свежий образ через most_recent иногда сознательно заменяют на жёстко зафиксированный ID, чтобы план был стабилен от запуска к запуску.
Итог: data — read-only мост к существующей инфраструктуре и внешним данным; он читает, но не владеет. Дальше — центральная тема Terraform: state.