# Version constraints в Terraform: required_version и провайдеры _Основы Terraform · TerraformLab Knowledge Base_ **TL;DR:** required_version фиксирует, какие версии terraform запускают этот код. required_providers.version, то же для провайдеров. Pessimistic оператор ~> 5.60, стандарт, разрешает минорные апдейты, запрещает мажорные. ## Зачем фиксировать версии Без явных ограничений terraform скачает «последнее», а это значит, что через полгода у соседа может быть другая мажорная версия и другой план на том же коде. Это нарушение детерминизма, который и есть главная фича IaC. Поэтому в HCL принято писать два constraint'а: ```hcl terraform { required_version = ">= 1.5, < 2.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.60" } } } ``` - `required_version`, какие версии **самой утилиты terraform** могут запускать этот код. - `required_providers..version`, какие версии провайдера. Оба ограничения проверяются на старте любой команды (`init`, `plan`, `apply`). Если не подходит, terraform отказывается работать с понятным сообщением. ## Операторы | Запись | Что значит | Когда применять | |--------|------------|-----------------| | `1.9.5` или `= 1.9.5` | точное соответствие | редко, только когда баг в конкретной версии | | `>= 1.5` | не меньше | прим. Для `required_version`, открытый верх | | `<= 5.60` | не больше | редко | | `~> 5.60` | 5.60.x, 5.61.x, ..., но не 6.x | стандарт для провайдеров | | `~> 5.60.0` | только 5.60.x | очень строго, обычно избыточно | | `>= 1.5, < 2.0` | составное | стандарт для `required_version` | | `!= 5.55.0` | исключить | редко, при известных багах | Несколько ограничений склеиваются запятой и работают как логическое И. ## Pessimistic constraint `~>` Самый частый оператор. `~> X.Y` означает «X.Y или новее, но не больше чем X+1.0». Конкретно: - `~> 5.60` → `>= 5.60, < 6.0`. Подойдут 5.60.x, 5.61.x, 5.99.999; не подойдёт 6.0.0. - `~> 5.60.0` → `>= 5.60.0, < 5.61.0`. Подойдут только патчи внутри 5.60. Стандарт для провайдеров, `~> X.Y`. Это разрешает баг-фиксы и новые ресурсы, но защищает от мажоров с breaking changes. Стандарт для `required_version`, `>= X.Y, < X+1`. SemVer terraform-утилиты соблюдается строже, чем у провайдеров, поэтому верхняя граница ставится по мажору. ## `required_version`: на что влияет - Запретит запуск на слишком старой версии (нет фич, на которые рассчитан HCL). - Запретит запуск на слишком новой (если ты ограничил верх). Хорошая практика: ставить `>= X.Y, < X+1.0`, где X.Y, версия, на которой реально написан код. Не открытый верх (`>= 1.5` без ограничения): это пускает в проект terraform 2.x с потенциально ломающими изменениями. ## Где константы версий хранятся между запусками - `required_*` блоки, в `.tf`-файлах, ты их пишешь руками. - Конкретные установленные версии, в [[tf-lockfile|lockfile]] (`.terraform.lock.hcl`). - Кеш бинарников провайдера, в `.terraform/providers/`. Lockfile фиксирует точную версию в рамках constraint'а. Constraint определяет, в каком интервале terraform будет искать новую версию при `init -upgrade`. ## Как переходить на новую мажорную версию Положим, в коде `aws ~> 5.60`, а AWS-провайдер выпустил 6.0: 1. Прочитай changelog между 5.x и 6.0. Там перечислены breaking changes. 2. Поправь HCL под новые имена атрибутов/ресурсов. 3. Поменяй в коде `version = "~> 6.0"`. 4. Запусти `terraform init -upgrade`, lockfile обновится. 5. `terraform plan`, проверь, что diff соответствует ожиданиям (только запланированные изменения, без сюрпризов). 6. Только после этого `apply`. Никогда не делай шаг 4 без шага 1. ## Подводные камни - **Открытые верхние границы, мина.** `>= 5.0` без верха автоматически пустит мажор. Через пол года это превращается в срочный hotfix в пятницу. - **`~> X.Y` с двух числовыми сегментами !== `~> X.Y.Z`.** Это легко запутать. Запомни простое правило: точка справа от `~>`, «свобода внутри», слева, «верхняя граница». - **`required_version` иногда забывают.** Без него код запускается на любом terraform, в том числе на сильно устаревшем. Минимум пиши `required_version = ">= 1.5"`. - **`required_providers` без `version` тоже валидно.** Это значит «любая». Не делай так, это сразу отказ от детерминизма. - **`required_providers` записывается внутри блока `terraform {}`.** Внутри `provider "..." {}` поле `version`, deprecated. Часто встречается в старом коде, переноси наверх. См. [tf-provider-block](/terraform/kb/tf-provider-block.md). ## Команды ```bash terraform version ``` Текущая версия terraform и установленные плагины. Сравни с required_version в HCL. ```bash terraform init -upgrade ``` Поднять провайдеры до новых, разрешённых текущим constraint'ом. ```bash terraform providers ``` Дерево провайдеров и их версий: включая транзитивные. ## См. также - [terraform init: первая команда в любом проекте](/terraform/kb/tf-init.md) - [.terraform.lock.hcl: фиксация версий провайдеров](/terraform/kb/tf-lockfile.md) - [Блок provider: кому Terraform будет звонить](/terraform/kb/tf-provider-block.md) - [HCL: язык, на котором пишут Terraform](/terraform/kb/hcl-syntax.md)