tfenvの.terraform-versionファイルにはバージョンベタ書きしなくてもOK

2024.05.28

tfenv とは

大抵のプログラミング言語に**envってありますよね。それのTerraform版です。つまり Terraformの バージョン管理ツールです。これを使えばバージョンの異なるTerraform root module間でのTerraform バージョンの切り替えが容易に行なえます。

.terraform-versionファイルに使いたいTerraform バージョンを書いて、root module(=terraform applyなどの各種Terraformコマンドを実行するディレクトリのこと)に置いておくと、Terraformコマンド実行時に自動的にそのバージョンのTerraformをインストールして、使ってくれます。

ちなみに anyenv経由でtfenvのインストールも可能です。

tfenvでちょっと面倒だったこと

Terraformのバージョンのアップグレード時です。.tfファイルのterraformブロック内のrequired_version値を書き換えるのに加えて、.terraform-versionファイルに書いているバージョンも書き換えないといけないことです。

まあ大した手間ではないのですが、たくさんのroot moduleを管理しているのでチリツモで面倒だなと感じていました。

実はバージョンベタ書きしなくてよかった

が、実はこの作業は別に必須ではありませんでした!.terraform-versionファイルには、具体的なTerraformのバージョンを書く以外にいくつかの別の書き方があり、min-requiredあるいはlatest-allowedを使うとrequired_version値に合致する適切なバージョンをインストール、使用してくれます。

この書き方を使えばバージョンのアップグレード時にもう.terraform-versionを修正する必要が無いですね。

min-required

required_version値に合致する最小のバージョンをインストールします。

1.5.5をインストールします

terraform {
  required_version = ">= 1.5.5"
}

1.5.3をインストールします

terraform {
  required_version = "~> 1.5.3"
}

latest-allowed

required_version値に合致する最大のバージョンをインストールします。

最大についての制限がないので、現在の最新版1.8.4をインストールします

terraform {
  required_version = ">= 1.5.5"
}

1.5.7(1.5系の最新バージョン)をインストールします

terraform {
  required_version = "~> 1.5.3"
}

min-required / latest-allowedどっちを使うべきか?

required_versionは以下いずれかの書き方を採用されている場合が多いのではないかと思います。

  1. =でバージョンを固定する
  2. ~>でパッチバージョンのアップグレードのみ許可する(例 ~> 1.8.0)

1の場合min-required / latest-allowedで差はありません。最小も最大もない、固定ですからね。

2の場合、latest-allowedだとタイミングによって使われるバージョン(パッチバージョン)が変わってしまいます。~> 1.8.0にした場合、今後1.8.5がリリースされれば1.8.5が使われる、といった感じです。これを許容できるかどうかがmin-required / latest-allowedの選定基準になると思います。個人的にはパッチバージョンとはいえ勝手に上がるのは嫌なので min-requiredを使いたいです。

注意点

required_versionに書かれているSemantic Versioning 2.0.0 をパースしているわけではなく、最初に見つかったバージョンを、最小限必要なバージョンの候補として使用する、とのことです。

つまりrequired_versionに複数個の条件を書いていても、2個目以降の条件は無視します。

例えば、.terraform-versionmin-requiredと書いていて、かつ以下の設定の場合は 1.7.0がインストールされます。

terraform {
  required_version = ">= 1.7.0, ~> 1.5.3"
}

一方、条件を逆にすると

terraform {
  required_version = "~> 1.5.3, >= 1.7.0"
}

この場合は 1.5.3がインストールされます。

child moduleのrequired_versionはチェックしない

required_versionはモジュールごとに書く事ができます。なのでchild moduleにも書いて、tfenvがそちらも読んで適切なバージョンをインストールしてくれるのか、調べてみました。

結論としては、tfenvはchild moduleのrequired_versionはチェックしないということがわかりました。

以下の方法で調査しました。

  • .terraform-versionmin-requiredと書く
  • root moduleのrequired_version>= 1.7.0と書く
  • child moduleのrequired_version>= 1.7.3と書く
  • → child modulerequired_versionもチェックしてくれるなら 1.7.3をインストールしてくれるはず
  • → 結果 「Unsupported Terraform Core version」になった (=root moduleのrequired_versionだけ見てバージョンを決めたうえで、terraformコマンドを実行してエラーになっている)
    Error: Unsupported Terraform Core version
    │ 
    │   on modules/test/main.tf line 2, in terraform:
    │    2:   required_version = "~> 1.7.3"
    │ 
    │ Module module.test (from ./modules/test) does not support Terraform version
    │ 1.7.0. To proceed, either choose another supported Terraform version or update
    │ this version constraint. Version constraints are normally set for good reason,
    │ so updating the constraint may lead to other errors or unexpected behavior.

参考情報