
Une contrainte de version encadre ce que Terraform accepte : sa propre
version (required_version), celle des providers (required_providers), celle
des modules. Bien posée, elle évite les montées de version cassantes ; mal
comprise, elle laisse deux machines résoudre des versions différentes le même
jour. Deux pièges dominent : le sens des opérateurs < et <=, et ce que
le lock file suit réellement.
Ce guide traite les opérateurs, le pessimiste ~>, le lock file (providers,
pas modules), l'intersection des contraintes de modules, ce que le bloc
terraform accepte, et la preuve par version -json. Les comportements ont été
vérifiés sur Terraform v1.15.4.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Les opérateurs, et le vrai sens de
<et<= - Le pessimiste
~>et ses deux formes - Ce que le lock file suit : les providers, pas les modules
- L'intersection des contraintes de modules enfants
- Ce que le bloc
terraformaccepte, et la preuve parversion -json
Prérequis
Section intitulée « Prérequis »- Providers et modules (providers Terraform)
- Terraform 1.15.x, la série stable courante
Les opérateurs, et le sens de < et <=
Section intitulée « Les opérateurs, et le sens de < et <= »Une contrainte est une suite de comparaisons. Le tableau officiel :
| Opérateur | Sens |
|---|---|
= (ou aucun) | exactement cette version ; ne se combine avec aucun autre |
!= | exclut une version |
> >= | borne inférieure (au moins cette version) |
< <= | borne supérieure (au plus cette version) |
~> | pessimiste (voir plus bas) |
Le piège le plus courant, et une erreur qu'on lit souvent : < et <= posent
une borne SUPÉRIEURE, ils excluent les versions plus récentes. L'exemple
canonique de la doc le montre :
version = ">= 1.2.0, < 2.0.0">= 1.2.0 est le plancher, < 2.0.0 le plafond. Confondre le sens de <
avec « une version plus récente » inverse toute la lecture d'une plage.
Le pessimiste ~>, et ses deux formes
Section intitulée « Le pessimiste ~>, et ses deux formes »~> autorise les incréments du dernier segment indiqué, jamais celui d'au
dessus. Sa portée change selon la précision :
~> 5.0autorise5.1,5.9,5.99, mais pas6.0;~> 5.0.2autorise5.0.3,5.0.10, mais pas5.1.0.
L'erreur fréquente est d'écrire ~> 1.0.0 en croyant autoriser les correctifs :
cela verrouille la mineure 1.0.x, alors qu'on voulait probablement
~> 1.0 (toute la série 1.x).
Terraform ne fait pas correspondre les pré-releases (-beta1, -rc1)
avec >, >=, <, <= ou ~> : une contrainte souple ne remonte jamais
d'elle même sur une pré-release.
Le lock file suit les providers, pas les modules
Section intitulée « Le lock file suit les providers, pas les modules »Voici le second piège, et il coûte cher. Le fichier .terraform.lock.hcl
verrouille les versions des providers, et seulement d'eux :
At present, the dependency lock file tracks only provider dependencies.
Il n'enregistre aucune version de module distant. Poser
version = "~> 5.0" sur un module et croire le lock file derrière soi est une
erreur : Terraform « will always select the newest available module version that
meets the specified version constraints ». D'une machine à l'autre, d'un jour à
l'autre, la version de module résolue peut différer, alors que celle d'un
provider est figée par le lock.
Le lock file se versionne (il se committe) : il « belongs to the
configuration as a whole ». Pour chaque provider, il enregistre la version
retenue, les contraintes considérées, et des empreintes sous deux schémas :
h1: (préféré, calculé sur le contenu du paquet) et zh: (hérité, hash du
.zip du registre).
Vérifier une contrainte : la preuve machine
Section intitulée « Vérifier une contrainte : la preuve machine »Ne devinez pas ce qu'une contrainte a produit, lisez-le.
terraform version -json expose provider_selections, l'adresse complète de
chaque provider vers la version réellement retenue :
terraform version -json | jq '.provider_selections'{ "registry.terraform.io/hashicorp/local": "2.9.0", "registry.terraform.io/hashicorp/random": "3.9.0"}Le lock file au quotidien : upgrade, plateformes, CI
Section intitulée « Le lock file au quotidien : upgrade, plateformes, CI »Trois commandes que le sujet impose et qu'on oublie souvent :
terraform init -upgradeest requis pour toute montée de version, même à contrainte inchangée : « If a particular provider already has a selection recorded in the lock file, Terraform will always re-select that version [...] even if a newer version has become available. »terraform providers lock -platform=linux_arm64 -platform=linux_amd64pré-remplit les empreintes de plusieurs plateformes d'un coup. Sans elle, un lock écrit sur macOS fait échouer une CI Linux.terraform init -lockfile=readonlyvérifie les empreintes sans réécrire le fichier : c'est le mode CI. Le modèle de confiance est le trust on first use : Terraform échoue si un paquet ne correspond à aucune empreinte déjà enregistrée (« doesn't match any of the checksums previously recorded »).
Contraintes de modules : elles s'additionnent
Section intitulée « Contraintes de modules : elles s'additionnent »Une configuration doit satisfaire toutes les contraintes, y compris celles déclarées dans les modules qu'elle appelle : « You must use a Terraform version that satisfies all version constraints associated with the configuration, including constraints defined in modules », faute de quoi Terraform « prints an error and exits ». Raisonner sur un seul niveau est une erreur : l'intersection des contraintes de tous les modules doit être non vide.
Deux précisions sur les modules :
required_versionne couvre que le CLI, pas les providers : « applies only to the version of Terraform CLI and not versions of provider plugins ».- L'argument
versiond'un blocmodulene fonctionne qu'avec une source de registre. Un module en chemin local, Git ou S3 ne l'accepte pas, et « local modules always share the same version as their caller ».
Le bloc terraform n'accepte que des constantes
Section intitulée « Le bloc terraform n'accepte que des constantes »Dernier point, source d'erreur au premier réflexe de « paramétrer » sa
contrainte : le bloc terraform ne peut référencer aucun objet nommé.
terraform { required_version = var.v # interdit}Error: Variables not allowedVérifié en 1.15.4 : une variable, un local ou un appel de fonction dans le bloc
terraform fait échouer init. La contrainte est forcément un littéral.
Dépannage
Section intitulée « Dépannage »Ces symptômes touchent aux opérateurs, au lock file ou au bloc terraform.
| Symptôme | Cause | Solution |
|---|---|---|
Une contrainte < 2.0.0 refuse une version attendue | < est une borne supérieure | Relire le sens : < exclut les versions plus récentes |
| Deux machines résolvent des modules différents | Le lock file ne suit pas les modules | Épingler le module avec =, ou vendoriser |
| Une nouvelle version de provider n'est pas prise | Le lock re-sélectionne la version enregistrée | terraform init -upgrade |
| Une CI Linux échoue sur un lock écrit sur macOS | Empreintes d'une seule plateforme | terraform providers lock -platform=... |
Variables not allowed dans le bloc terraform | Une variable ou fonction dans la contrainte | La remplacer par un littéral |
À retenir
Section intitulée « À retenir »<et<=sont des bornes SUPÉRIEURES ;>>=des bornes inférieures.=ne se combine avec rien ; les pré-releases ne matchent pas les opérateurs de plage.~> 5.0= toute la5.x;~> 5.0.2= la5.0.xseulement.- Le lock file suit les providers, pas les modules, et se committe.
terraform init -upgradeest requis pour toute montée ;-lockfile=readonlyvérifie en CI ;providers lock -platformcouvre plusieurs OS.- Les contraintes des modules s'additionnent ;
required_versionne couvre que le CLI. - Le bloc
terraformn'accepte que des constantes ;version -jsonprouve la sélection.
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Les questions ci-dessous reprennent les confusions les plus fréquentes sur les
contraintes de version : le sens de <, ce que suit le lock file, et le
pessimiste ~>.
Une borne supérieure
< et <= excluent les versions plus récentes. L'exemple canonique de la doc :version = ">= 1.2.0, < 2.0.0"
>= 1.2.0 est le plancher, < 2.0.0 le plafond.L'erreur fréquente
Lire< comme « une version plus récente » inverse tout : < et <= bornent vers le haut, > et >= vers le bas.Providers seulement
« At present, the dependency lock file tracks only provider dependencies. »Le lock file n'enregistre aucune version de module distant.La conséquence
Poserversion = "~> 5.0" sur un module ne le fige pas : Terraform « will always select the newest available module version that meets the specified version constraints ». D'une machine à l'autre, la version de module résolue peut différer, contrairement à celle d'un provider.Le pessimiste dépend de la précision
~> 5.0autorise5.1,5.9,5.99, mais pas6.0;~> 5.0.2autorise5.0.3,5.0.10, mais pas5.1.0.
Le piège
Écrire~> 1.0.0 en croyant autoriser les correctifs verrouille la mineure 1.0.x, alors qu'on voulait probablement ~> 1.0 (toute la série 1.x).= est exclusif
« Matches exactly one version; cannot combine with others. »= 1.2.0 fixe exactement cette version. L'associer à un autre opérateur est invalide :version = "= 1.2.0, < 2.0.0" # invalide
À noter
Les pré-releases (-beta1, -rc1) ne sont pas matchées par >, >=, <, <= ou ~> : une contrainte souple ne remonte jamais d'elle-même sur une pré-release.Des constantes seulement
terraform {
required_version = var.v # interdit
}
Error: Variables not allowed
Vérifié en 1.15.4 : une variable, un local ou une fonction dans le bloc terraform fait échouer init.Pourquoi
Le blocterraform est évalué très tôt, avant que les variables ne soient résolues. La contrainte doit être un littéral.Le lock re-sélectionne
« If a particular provider already has a selection recorded in the lock file, Terraform will always re-select that version for installation, even if a newer version has become available. »Conséquence
terraform init -upgrade est requis pour toute montée de version, y compris à contrainte inchangée. En CI, terraform init -lockfile=readonly vérifie les empreintes sans réécrire le fichier, et terraform providers lock -platform=... couvre plusieurs OS d'un coup.Le lock se committe
Le fichier « belongs to the configuration as a whole » : il se versionne.Ce qu'il contient
Pour chaque provider : la version retenue, les contraintes considérées, et des empreintes sous deux schémas :h1:: préféré, calculé sur le contenu du paquet ;zh:: hérité, hash du.zipdu registre.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Le style guide Terraform : La place du lock file et du .gitignore dans les conventions officielles.
- Quiz Écrire du code Terraform : Un contrôle des acquis sur les versions, les providers et les blocs du langage.
- Versionner ses modules Terraform : Les mêmes contraintes de version appliquées cette fois aux sources de modules.