Terraformのprovider等のバージョン制約と不整合について

# はじめに

どうも、@to-fmakです。入社5日目ですが、既存環境等のキャッチアップをしながら、2日ほど作業していました。
作業（Terraformコードを中心に見ていました）の際に見つけた課題ついてまとめてみました。

# 背景

- インフラ設定変更が必要なため、あるTerraformリポジトリ（直近あまり更新されていない）で作業をすることに
- terraform initの際に、aws providerのバージョン制約により、バージョンの不整合が起きた

# Terraform Providerバージョンの不整合について

※元々のソースコードやコンソール出力ではフルバージョンが記載されていますが、本記事ではマイナーバージョンをマスキングします。また、省略する部分は「...」とします。

## そもそも何が起きたのか

リポジトリの中身を覗いてみたら、.terraform.lock.hclが存在していました。

```:.terraform.lock.hcl
provider "registry.terraform.io/hashicorp/aws" {
  version     = "5.0.x"
  constraints = ">= 4.45.x"
  hashes = [
    ...
  ]
}
```

※.terraform.lock.hclは`Terraformの依存関係をロック`するためのファイルです。このファイルは、Terraformのプロバイダーやモジュールのバージョンを固定し、再現性のあるインフラストラクチャのデプロイを保証するために使用されます。

以下、この状態での`terraform init`の実行結果です。

```txt
│ Error: Failed to query available provider packages
│
│ Could not retrieve the list of available versions for provider hashicorp/aws: locked provider registry.terraform.io/hashicorp/aws 5.0.x does
│ not match configured version constraint >= 4.45.x, >= 5.27.x; must use terraform init -upgrade to allow selection of new versions

```

「version constraint >= 4.45.x, >= 5.27.x。うん？どういうこと？」
「さて、required_providersを覗いてみるか。」

```hcl:versions.tf
terraform {
  required_version = ">= 1.4.x"

  backend "xxx" {
    ...
  }

  required_providers {
    aws = {
      source                = "hashicorp/aws"
      version               = ">= 4.45.x"
      ...
    }
  }
}

```

「う〜ん、`>= 4.45.x`しか書いていないな、.terraform.lock.hclを参照して、`5.0.x`をとってくるんじゃないの？他の箇所にもバージョン指定の記載があったのか。」
と思いリポジトリ内で検索をかけてみてもヒットしませんでした。

「はい？5.27.xってどこから来た？」

結果、色々探してみたら、下記の通り、外部モジュールを参照する箇所がありました。

```hcl:s3.tf
module "s3_xx_xx" {
  source  = "terraform-aws-modules/s3-bucket/aws"
  version = ">= 3.8.x"

  ...
}
```

「ここか...」

## 起きたことのまとめ

.terraform.lock.hclが存在するため、該当ファイルに記載されたaws providerのバージョン（`5.0.x`）を使用することになります。

一方、s3.tfではs3バケットを作成するために、外部モジュールを参照しており、`>=`演算子でバージョンを指定しています。これにより、`3.8.x`より最新のバージョンを使用することになります。

2024/8時点では該当モジュールの最新バージョンが`4.1`になっており、必要とされるaws providerバージョンが
`5.27`以上のバージョンとなっています。

[https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/blob/8a0b697adfbc673e6135c70246cff7f8052ad95a/versions.tf#L7](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/blob/8a0b697adfbc673e6135c70246cff7f8052ad95a/versions.tf#L7)

そのため、.terraform.lock.hclに記載された`5.0.x`のバージョンが、「`5.27`以上のバージョン」という制約を満たさなくなり、エラーが表示されたわけです。

:::note info
エラーメッセージやログに、同一providerで`複数のversion constraint`が表示され不整合が起きた際に、providerバージョンを管理するtfファイル（通常はversions.tf）だけでなく、外部モジュール等の依存関係で別のバージョンを指定していないかどうかも確認してみると良いかもしれません。
:::

# バージョン指定演算子について

さて、バージョン指定演算子のおさらいをしましょう。

- 指定バージョンと等しい: `=`
- 指定バージョンと等しくない: `!=`
- 指定のバージョンより大きい、以上、より小さい、以下: `>`, `>=`, `<`, `<=`
- 一番右のバージョン要素が、指定の値以上: `~>`

# 結局何が良くないのか

私が考える今回の問題の根本的な原因は下記の通りです。

1. .terraform.lock.hcl とバージョン指定の不整合
2. 外部モジュールのバージョン管理の見落とし
3. 依存関係の管理の欠如

## .terraform.lock.hclの必要性について

今回のように複数の場所でバージョン指定が行われている場合、.terraform.lock.hclの効果が薄れることがあります。

## 今後どうしていくべきか

- 一貫したバージョン管理
- 定期的なアップデート
- 詳細な依存関係の確認

これらの対策を講じることで、今回のようなバージョンの不整合によるエラーを回避できるのではないかと考えています。

# 参考URL

- https://developer.hashicorp.com/terraform/language/v1.4.x/files/dependency-lock
- https://developer.hashicorp.com/terraform/language/v1.4.x/expressions/version-constraints
- https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master

## エンジニア募集

Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています！！
ぜひお気軽にカジュアル面談へお越しください！！

<https://gakken-leap.co.jp/recruit/>