# Источники модулей: local, git, registry, archive, S3 _Модули · TerraformLab Knowledge Base_ **TL;DR:** `source` определяет откуда terraform берёт код модуля. Пять основных типов: локальный путь (`./modules/x`), git-репо (`git::https://...`), Terraform Registry (`hashicorp/consul/aws`), архив (`https://.../v1.0.zip`), S3-объект (`s3::https://...`). Local, для своего репо. Registry, для публичных модулей. Git, для приватных. ## Пять типов source | Тип | Пример | Когда | |---|---|---| | Local | `./modules/s3-bucket` | Модуль живёт в этом же репо | | Terraform Registry | `terraform-aws-modules/vpc/aws` | Публичный module, версионирование semver | | Git | `git::https://github.com/org/repo.git//modules/x?ref=v1.2.3` | Приватный модуль в git | | HTTP archive | `https://example.com/modules/x-v1.zip//x` | CDN, артефакт-сторадж | | S3 | `s3::https://s3.amazonaws.com/bucket/x.zip` | Внутренний S3 как реестр | Type определяется по форме строки, не по отдельному полю. Terraform сам угадывает. ## Local ```hcl module "logs" { source = "./modules/s3-bucket" name = "..." } ``` - Путь относительно `.tf` файла, в котором написан `module` блок. - `terraform init` создаст symlink в `.terraform/modules/logs/`. - Любые правки HCL модуля видны сразу, это просто файлы в репо. - **Нет версионирования**. Это часть твоего репо, версия = текущий HEAD git. Используй для модулей которые живут вместе с root'ом. Не пытайся через local-path ссылаться на «соседний» проект, будет ад с относительными путями. ## Terraform Registry ```hcl module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "5.7.0" name = "main" cidr = "10.0.0.0/16" # ... } ``` Формат: `//`. Три сегмента, без `https://`. - Реестр, registry.terraform.io (публичный) или приватный (HCP Terraform, Spacelift, и т.п.). - `version`, semver constraint: `"5.7.0"`, `"~> 5.7"`, `">= 5.0, < 6.0"`. См. [tf-module-versioning](/terraform/kb/tf-module-versioning.md). - **Не указал version → берётся максимум**. В CI это бомба замедленного действия: завтра выйдет 6.0 с breaking changes, и сборка ломается без единого коммита. Всегда фиксируй version. Публичные модули AWS (`terraform-aws-modules/vpc/aws`, `.../eks/aws`, `.../alb/aws`): это де-факто стандарт. Они огромные, параметризованы под все edge-case'ы. Подходят, когда твои требования ничем не отличаются от стандарта. Если отличаются, модуль легче написать свой, чем разбираться какой из 40 input'ов нужно нажать. ## Git ```hcl # SSH module "billing" { source = "git::ssh://git@github.com/myorg/terraform-modules.git//billing?ref=v1.2.3" } # HTTPS module "billing" { source = "git::https://github.com/myorg/terraform-modules.git//billing?ref=v1.2.3" } ``` Формат: `git:://<подпуть>?ref=`. - **`//`** перед подпутём, это разделитель Terraform, не часть git-URL. - **`ref`**, branch, tag или commit-SHA. Для воспроизводимости, **только tag или SHA**, не branch. Иначе сегодня `init` скачает один commit, завтра , другой. - Аутентификация, стандартная git: SSH-ключ, HTTPS basic, токен через `GIT_TERMINAL_PROMPT` / credential helper. - В корпоративных репозиториях обычно делают **один** git-репо с подкаталогами для модулей. Это удобно для версионирования: один tag `v1.2.3` фиксирует всё. ## HTTP archive ```hcl module "x" { source = "https://example.com/modules/x-v1.0.tar.gz//x" } ``` Terraform скачивает архив, распаковывает, заходит в подпуть `//x`. Поддерживаются: `.zip`, `.tar.gz`, `.tar.bz2`, `.tar.xz`. Полезно когда модули публикуются в CDN или артефакт-сторадж (Artifactory, Nexus). Версионирование, через имя файла или header. ## S3 ```hcl module "x" { source = "s3::https://s3-eu-west-1.amazonaws.com/my-bucket/modules/x-v1.zip" } ``` Префикс `s3::` подсказывает terraform использовать AWS-credentials для доступа (из той же credentials chain, что AWS-провайдер). Это компромисс между «свой git» и «свой Registry»: дёшево, частный, не требует дополнительного сервиса. Минус, нет встроенного семвера, версионирование руками через имена файлов. ## Кэширование и init При `terraform init` Terraform скачивает все модули в `.terraform/modules/`: ``` .terraform/modules/ ├── modules.json # mapping: имя в HCL → путь ├── vpc/ # скачанный код vpc-модуля └── billing/ # скачанный код billing-модуля ``` Эта папка, кэш. Меняешь HCL модуля (для local): видно сразу. Меняешь `source = "git::...?ref=v2.0.0"`. Нужно `terraform init -upgrade`, иначе используется старая закэшированная копия. ## Подводные камни - **Source интерполировать нельзя.** Никаких `source = "git::...?ref=${var.v}"`. Source разрешается на этапе init, до переменных. Версия модуля, статическое значение. Если нужно «динамически переключать версии», держи их в separate root-модулях или используй Terragrunt. - **Branch вместо tag, мина.** `?ref=main` означает «текущий main». Завтра кто-то смержит в main breaking change → твой `terraform init` скачает его, plan покажет destroy+create. Всегда tag или SHA. - **Registry-модули могут тянуть Registry-модули.** Большие AWS-модули внутри используют десятки subdependencies. Один `module "vpc"` → `.terraform/modules/` пухнет на 30+ модулей. Это норма, не баг. - **`source = "./modules/x"` после миграции репо ломается.** Перенёс модули в подпапку, relative path сломан. Лечится bulk-grep'ом по repo, но больно. Чем глубже структура, тем чаще будет. - **Не используй HTTP без HTTPS.** `source = "http://..."` отключает проверку TLS. Это путь для атаки «подменили модуль на машине билда». - **Авторизация для приватных git, через credential helper, не в URL.** Не пиши `git::https://user:token@github.com/...`, токен попадёт в лог и `.terraform/modules/modules.json`. Используй `git config --global credential.helper store` локально и secrets-механизм в CI. ## Команды ```bash terraform init ``` Скачать все модули в .terraform/modules/. ```bash terraform init -upgrade ``` Перечитать source, скачать заново. Нужно после смены version или ref. ```bash cat .terraform/modules/modules.json | jq ``` Какие модули скачаны и куда. Полезно при дебаге 'почему берётся не тот код'. ```bash terraform get -update ``` Только модули (без провайдеров). Подкомманда внутри init. Редко нужна руками. ## См. также - [Как terraform init подтягивает модули](/terraform/kb/tf-init-modules.md) - [.terraform.lock.hcl: фиксация версий провайдеров](/terraform/kb/tf-lockfile.md)