1. Структура проекта Terraform: организация модулей, переменных и стандарты именования
Структура проекта Terraform: организация модулей, переменных и стандарты именования
Представьте, что вы строите современный жилой комплекс. Если каждый строитель будет использовать свои чертежи, хранить инструменты в случайных местах и называть кирпичи «штуками», проект превратится в катастрофу еще на этапе фундамента. В мире Infrastructure as Code (IaC) ситуация идентична: когда конфигурация Terraform разрастается до сотен ресурсов, отсутствие четкой структуры превращает поддержку облака в «разминирование» кода. Ошибка в именовании или жестко прописанный (hardcoded) идентификатор подсети может привести к простою всей 3-tier архитектуры.
Архитектура кода как фундамент масштабируемости
При проектировании трехзвенной (3-tier) архитектуры в AWS — с публичным слоем презентации, приватным слоем приложений и изолированным слоем данных — мы сталкиваемся с высокой связностью компонентов. Балансировщик нагрузки должен «знать» об экземплярах приложений, а те, в свою очередь, должны иметь доступ к базе данных.
Если поместить все описание ресурсов в один файл main.tf, вы быстро столкнетесь с проблемами:
terraform apply потенциально затрагивает всю инфраструктуру сразу.Правильная организация проекта начинается с перехода от монолитной структуры к модульной и иерархической.
Анатомия стандартного модуля
В Terraform модуль — это просто директория с набором файлов .tf. Однако для профессиональной разработки принят стандарт «минимального набора файлов», который обеспечивает предсказуемость кода.
* main.tf: Здесь описываются основные ресурсы (Resources) и источники данных (Data Sources). Это «двигатель» модуля.
* variables.tf: Объявление входных параметров. Здесь задаются типы данных, значения по умолчанию и описания.
* outputs.tf: Экспорт данных. Модуль должен возвращать идентификаторы (ID) или ARN созданных ресурсов, чтобы другие части системы могли их использовать.
* providers.tf: Определение необходимых провайдеров (AWS, Azure, Google) и их версий.
* versions.tf: Ограничения версий самого Terraform и провайдеров для предотвращения конфликтов при работе в команде.
* README.md: Документация, сгенерированная автоматически (например, через terraform-docs) или написанная вручную.
> «Программы должны писаться для того, чтобы их читали люди, и лишь во вторую очередь — для того, чтобы их исполняли машины». > > Структура и интерпретация компьютерных программ (SICP)
Этот принцип Гарольда Абельсона идеально ложится на IaC. Ваш Terraform-код — это документация вашей сети.
Иерархия каталогов для 3-tier проекта
Для проекта средней и высокой сложности рекомендуется разделять «определение модулей» и «вызов модулей». Это позволяет обновлять логику работы сети в одном месте, не затрагивая конфигурацию конкретных окружений.
Рассмотрим оптимальную структуру каталогов:
В такой структуре папка modules содержит «чертежи», а папка live — реальные инсталляции. Если нам нужно изменить параметры шифрования во всех базах данных RDS во всех окружениях, мы правим код в modules/rds/. Если нам нужно добавить памяти только в prod, мы меняем переменную в live/prod/data/.
Стандарты именования: борьба с хаосом
Именование ресурсов — это не вопрос вкуса, а вопрос навигации. В AWS тысячи ресурсов, и консоль управления быстро превращается в свалку, если объекты называются my-server-1 или test-db.
Правила для имен внутри Terraform (Local Names)
Локальное имя ресурса (то, что идет сразу после типа ресурса) должно быть лаконичным и отражать роль, а не тип.
❌ Плохо:
Здесь тип aws_instance дублируется в имени. Это избыточно.
✅ Хорошо:
В коде вы будете обращаться к нему как aws_instance.web.id. Это читаемо и понятно.
Правила для имен ресурсов в облаке (Tags & Name)
Для физических имен ресурсов в AWS (тег Name) используйте формат:
[Проект]-[Окружение]-[Компонент]-[Регион]
Пример: skyline-prod-alb-eu-central-1.
Такой подход позволяет:
Работа с переменными: типизация и валидация
Переменные превращают статический конфиг в гибкий инструмент. В Terraform переменные — это не просто подстановка строк, это полноценная система типов.
Описание и типы
Никогда не оставляйте переменную без описания (description) и типа (type). Это единственный способ заставить Terraform выдать понятную ошибку до того, как начнется создание ресурсов.
Использование блока validation позволяет внедрять «полицейские функции» прямо в код. Например, вы можете запретить использование слишком широких масок подсетей или ограничить выбор типов инстансов только разрешенными в вашей компании (например, только семейство t3).
Входные переменные vs Локальные значения
Частая ошибка — использование variable для констант. Если значение не должно меняться пользователем модуля, используйте locals.
Локальные значения (locals) вычисляются внутри модуля и не видны снаружи. Это идеальное место для формирования сложных имен или объединения наборов тегов.
Проектирование Output-значений
Outputs — это API вашего модуля. Когда вы создаете VPC, другим модулям (например, базе данных) не нужен весь объект VPC, им нужны конкретные ID подсетей.
Правило хорошего тона: возвращайте не только ID, но и полные объекты, если это упрощает интеграцию.
При использовании 3-tier архитектуры, выходные данные уровня VPC становятся входными данными для уровня App, а те — для уровня Data. Это формирует цепочку зависимостей, которую Terraform выстраивает в виде направленного ациклического графа (DAG).
Модульность и принцип DRY
DRY (Don't Repeat Yourself) в Terraform реализуется через вызов модулей с разными параметрами. Однако здесь кроется ловушка «чрезмерной абстракции».
Если вы создаете модуль, который просто оборачивает один ресурс AWS (например, «модуль для S3 бакета», где внутри только один aws_s3_bucket), вы создаете лишнюю работу. Модуль имеет смысл тогда, когда он инкапсулирует логическую группу ресурсов.
Для нашей 3-tier архитектуры логичными модулями будут:
Управление версиями и зависимости
В профессиональной среде модули часто выносятся в отдельные Git-репозитории. Это позволяет версионировать инфраструктуру так же, как программный код.
Использование тегов (?ref=v2.4.0) критически важно. Без фиксации версии выполнение terraform init на новом компьютере может подтянуть последние (breaking) изменения из мастер-ветки модуля, что сломает ваш продакшн.
Безопасность на уровне структуры
Организация кода также влияет на безопасность.
* Чувствительные данные: Никогда не храните пароли или ключи доступа в variables.tf или файлах .tfvars. Используйте интеграцию с AWS Secrets Manager или переменные окружения. Для переменных с секретами всегда ставьте флаг sensitive = true.
* Принцип наименьших привилегий: Разделение стейта (State) между слоями (Network, App, Data) позволяет ограничить доступ. Инженер, работающий над фронтендом, не должен иметь прав на изменение сетевого фундамента или удаление базы данных.
Практический пример: Передача данных между слоями
Рассмотрим, как структура проекта помогает связать слои. Допустим, модуль сети отдал нам список приватных подсетей.
В корневом файле main.tf (в папке live/prod) это будет выглядеть так:
Здесь module.network.private_subnet_ids — это мост между двумя независимыми компонентами. Если мы решим изменить количество подсетей в модуле network, Terraform автоматически поймет, что модуль application тоже требует обновления, так как его входные данные изменились.
Оптимизация рабочего процесса
Для поддержания чистоты структуры в команде рекомендуется использовать инструменты автоматизации:
Соблюдение этих правил на старте может показаться избыточным для создания одной виртуальной машины. Но когда ваша 3-tier архитектура начнет масштабироваться на несколько регионов, а количество микросервисов перевалит за десяток, именно строгая структура и стандарты именования спасут проект от технологического долга и неконтролируемого хаоса.
Правильно структурированный проект Terraform — это не просто набор файлов, это живая карта вашей системы, где каждый ресурс находится на своем месте, имеет понятное имя и предсказуемое поведение. Это позволяет инженерам фокусироваться на развитии продукта, а не на борьбе с инфраструктурными «загадками».