tech.guitarrapc.cóm

Technical updates

tenvを使って任意のTerraformバージョンを実行する

Terraformを使い始めてしばらくすると出会う課題が、プロジェクトで使用するTerraformバージョンを制約しつつ、Terraform利用者のインストール手間を減らすことです。 Terraformはバージョンアップによって挙動が変わりえるため、プロジェクトで利用するバージョンはある程度固定したくなります。しかし1つのTerraformですべての環境をそろえるのは難しいでしょう。例えば横断的なやり取りのないプロジェクトでは異なるバージョンのTerraformを使っているでしょう1し、Terraformアップグレード時にそのブランチだけ異なるバージョンを使いたくなります。

このように「実行環境ごとに異なるバージョンのTerraformを利用している」時に、環境ごとに自動的にバージョンを切り替えるツールとしてtfenvtenvがあります。今回はtenvを使って、バージョンアップ時の手間を減らしつつ、環境ごとのTerraformバージョンを自動的に切り替える方法を紹介します。

tenvとは

tofuiutils/tenv | GitHub.com

tenvはTerraformのバージョン管理ツールです。tfenvと同様に、環境ごとに異なるTerraformバージョンを使いたいときに利用します。tfenvは2022年を最後にリリースが止まっており利用は避けたい状況です。tenvはtfenv同様に利用できつつも実装がGoであるため、Bashで作られていたtfenvと違ってWindowsを含めたマルチOS環境でネイティブに動作します。私自身がTerraformのヘビーユーザーですが、現時点でterraformを管理するツールはtenvが最もおすすめです。

tenvをインストールする

tenvのインストールは、バイナリ配置、パッケージマネージャー経由、go installなどいろんな方法があります。詳しくはREADMEを見るといいです。私は次の方法でインストールしています。

Linux

aquaを使って管理しています。

# aqua.yaml
registries:
  - type: standard
    ref: v4.219.0 # renovate: depName=aquaproj/aqua-registry
packages:
  - name: tofuutils/tenv@v4.1.0
aqua install

macOS

homebrewで管理しています。

brew install tenv

Windows

scoopで管理しています。

scoop install tenv

Terraformを実行したいときにtenvに自動インストールさせる

tenvには、そのTerraformディレクトリで必要なTerraforバージョンを示したファイルを配置することで、terraformコマンドを実行するときに自動的に指定されたTerraformバージョンをインストールしてする機能があります。これを使うと、プロジェクトごとに異なるバージョンのTerraformを使っていても透過的に切り替わるので、開発者にいちいちバージョンを切り替えてもらう手間を省けます。

これを利用するには、環境変数でTENV_AUTO_INSTALL=trueを指定しておく必要があります。.bashrcや.zshrc、profile.ps1などに設定しておくといいでしょう。

# Windows (cmd)
set TENV_AUTO_INSTALL=true

# Windows (PowerShell)
$env:TENV_AUTO_INSTALL = "true"

# Linux/macOS
export TENV_AUTO_INSTALL=true

これでterraformコマンドを実行ディレクトリに.terraform-versionファイルがあれば、自動的に指定バージョンをインストールして実行します。例えば、次のようなファイルを配置すると、実行時に1.10.3をインストールしします。

1.10.3

ここまでがtenvの基本的な使い方です。tenvは他にもいろいろな機能があるので、興味がある人はREADMEを見てください。

tenvを使ってterraformのrequired_versionに指定したバージョンを自動的に利用させる

よく見かけるのが、terraformのrequired_versionを固定指定2しつつ、.terraform-versionでもそのバージョンを記載する方法です。期待通り指定したバージョンだけで動作するのですが、二重定義しているのでアップグレード時に漏れる可能性があります。

設定箇所 設定する値
terraformのrequired_version = 1.10.3~> 1.10.0
.terraform-version 1.10.3
Terraform Cloudのバージョン 1.10.3
GitHub Actionsのバージョン 1.10.3

terraform

# versions.tf など
terraform {
  required_version = "= 1.10.3"
}

.terraform-version

# .terraform-version
1.10.3

Terraform Cloud

Terraform CloudのRemote Executionを使っている場合、Terraform Cloud側のバージョンとも一致しないといけないため3箇所に増えて手間がかかります。

image

GitHub Actions

CIを使っている場合、そのTerraformバージョンも合わせる必要があります。GitHub Actionsならsetup-terraformを使うことが多いでしょう。

- uses: hashicorp/setup-terraform@v3
  with:
    terraform_version: "1.10.3"
    cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}

バージョン指定を一箇所にまとめる

Terraformのバージョン更新をrenovateで管理するのもいいですが、バージョン指定を一箇所にまとめる方法もあります。tenvを使って.terraform-versionにはlatest-allowedを指定しておき、terraformのrequired_versionにはそのマイナーバージョンにおける最新パッチを使うように指定します。これにより、ファイル上のterraformのバージョンをrequired_version一箇所にまとめることができます。Terraform Cloudも1.10.xの間は変更不要です。

設定箇所 設定する値
terraformのrequired_version ~> 1.10.0
.terraform-version latest-allowed
Terraform Cloudのバージョン ~> 1.10.0 latest
GitHub Actionsのバージョン required_versionの値を自動設定

latest-allowedを指定する方法はtenvのREADMEにも書かれています。

The latest-allowed strategy rely on required_version from .tf or .tf.json files with a fallback to latest when no constraint are found. Moreover it is possible to add a default constraint with TFENV_TERRAFORM_DEFAULT_CONSTRAINT environment variable or ${TENV_ROOT}/Terraform/constraint file (can be written with tenv tf constraint). The default constraint is added while using latest-allowed, min-required or custom constraint. A default constraint with latest-allowed or min-required will avoid the fallback to latest when there is no .tf or .tf.json files.

terraform

# versions.tf など
terraform {
  required_version = "~> 1.10.0"
}

.terraform-version

# .terraform-version
latest-allowed

Terraform Cloud

1.10.0というマイナーバージョンの間は変更不要です。

image

GitHub Actions

terraformのrequired_versionを利用するように変更します。これで常にrequired_versionの値を利用します。

- name: Get terraform version from .terraform-version
  shell: bash
  id: terraform-version
  run: |
    required_version=$(grep -E 'required_version\s*=\s*"([^"]+)"' "versions.tf" | sed -n 's/.*required_version\s*=\s*"\([^"]*\)".*/\1/p')
    echo "value=$required_version" | tee -a "${GITHUB_OUTPUT}"
  working-directory: ${{ inputs.working-directory }}
- uses: hashicorp/setup-terraform@v3
  with:
    terraform_version: ${{ steps.terraform-version.outputs.value }}
    cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}

動作確認

動作確認をしてみましょう。required_verseionには1.9.0のマイナーバージョン以内を指定し、.terraform-versionにrequired_versionの制約で可能な最新を指定します。

$ cat ./versions.tf | grep required_version
  required_version = "~> 1.9.0"
$ cat .terraform-version
latest-allowed

Windows

環境変数を設定した状態でterraformを実行すると最新バージョンの1.9.8が自動的にインストールされています。

$ set TENV_AUTO_INSTALL=true
$ terraform init
Resolved version from D:\github\guitarrapc\Test\aws_test\.terraform-version : latest-allowed
Scan project to find IAC files
No compatible version found locally, search a remote one...
Fetching all releases information from https://releases.hashicorp.com/terraform/index.json
Found compatible version remotely : 1.9.8
Installing Terraform 1.9.8
Fetching release information from https://releases.hashicorp.com/terraform/1.9.8/index.json
Downloading https://releases.hashicorp.com/terraform/1.9.8/terraform_1.9.8_windows_amd64.zip
Downloading https://releases.hashicorp.com/terraform/1.9.8/terraform_1.9.8_SHA256SUMS
Downloading https://releases.hashicorp.com/terraform/1.9.8/terraform_1.9.8_SHA256SUMS.sig
Downloading https://www.hashicorp.com/.well-known/pgp-key.txt
Installation of Terraform 1.9.8 successful
Initializing HCP Terraform...

$ terraform --version
Terraform v1.9.8
on windows_amd64

Linux

環境変数を設定した状態でterraformを実行すると最新バージョンの1.9.8が自動的にインストールされています。

$ export TENV_AUTO_INSTALL=true
$ terraform init
Resolved version from /mnt/d/github/guitarrapc/Test/aws_test/.terraform-version : latest-allowed
Scan project to find IAC files
No compatible version found locally, search a remote one...
Fetching all releases information from https://releases.hashicorp.com/terraform/index.json
Found compatible version remotely : 1.9.8
Installing Terraform 1.9.8
Fetching release information from https://releases.hashicorp.com/terraform/1.9.8/index.json
Downloading https://releases.hashicorp.com/terraform/1.9.8/terraform_1.9.8_linux_amd64.zip
Downloading https://releases.hashicorp.com/terraform/1.9.8/terraform_1.9.8_SHA256SUMS
Downloading https://releases.hashicorp.com/terraform/1.9.8/terraform_1.9.8_SHA256SUMS.sig
Downloading https://www.hashicorp.com/.well-known/pgp-key.txt
Installation of Terraform 1.9.8 successful
Initializing HCP Terraform...

Windows、LinuxとOSが異なっても同じ使い勝手でTerraformのバージョンを自動的に切り替えてくれています。

まとめ

terraformのバージョン管理はtenvを使うと便利です。tenvで透過的にTerraformバージョンを利用させるには.terraform-versionlatest-allowedを指定すると楽になります。 CIやTerraform Cloudも含めてなるべくバージョン変更箇所を減らすようにすると、バージョンアップ時の手間を減らすことができます。小さな手間の積み重ねが大きな手間を減らすことにつながるのでやっていきましょう。

AIが勝手に更新してくれるようになるといいですね。Renovateもいい手段ですが、本記事のやり方も便利です。


  1. 横断的に関わりがないということはバージョンをそろえるインセンティブが働かないので、プロジェクトの開発者ごとに違うバージョン判断をすることでしょう
  2. 範囲指定でも同じです