Зачем фиксировать версии
Без явных ограничений terraform скачает «последнее», а это значит, что через полгода у соседа может быть другая мажорная версия и другой план на том же коде. Это нарушение детерминизма, который и есть главная фича IaC.
Поэтому в HCL принято писать два constraint'а:
terraform {required_version = ">= 1.5, < 2.0"
required_providers { aws = {source = "hashicorp/aws"
version = "~> 5.60"
}
}
}
required_version, какие версии самой утилиты terraform могут запускать этот код.required_providers.<name>.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:
- Прочитай changelog между 5.x и 6.0. Там перечислены breaking changes.
- Поправь HCL под новые имена атрибутов/ресурсов.
- Поменяй в коде
version = "~> 6.0". - Запусти
terraform init -upgrade, lockfile обновится. terraform plan, проверь, что diff соответствует ожиданиям (только запланированные изменения, без сюрпризов).- Только после этого
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.