RevComm Tech Blog

コミュニケーションを再発明し 人が人を想う社会を創る

初めてのTerraform開発でよく起きたトラブルとその解決方法

Terraformのロゴ

この記事は RevComm Advent Calendar 2022 の 9 日目の記事です。

はじめに

Hello World ! サーバーサイドエンジニアの矢島です。普段は MiiTel Analytics の開発を行っています。
2022年7月に入社してすぐに新機能の開発を任されて、実務で初めて Terraform を使った開発を経験しました。 この開発は、Terraform を使うのが初めてだったことに加えて以下のような要因も重なり、試行錯誤の連続でした。

  • しばらく変更されていないファイルが多々あったこと
  • M1チップの MacBookという、利用者があまり多くない環境だったこと

そこでこの記事では、初めての Terraform 開発で直面したトラブルとその解決方法をまとめました。M1 Mac でなくても発生しうる内容もありますので、特に僕のような Terraform ビギナーの方に有益な記事となれば嬉しいです。

初めてのTerraform 開発でよく起きたトラブルとその解決方法

M1 Mac で使えない provider が存在する

$ terraform init
Error: Failed to install provider

M1 Mac では、 arm64 という命令セットアーキテクチャが採用されており、Intel Mac と実行できるバイナリファイルが異なります。
そのため、更新されなくなった provider や古いバージョンの provider を使用する際は、マニュアルインストールが必要になります。

1.Go をインストール(anyenv の利用を前提とします)

$ anyenv install goenv
$ goenv install 1.18.4
$ go version
 go version go1.18.4 darwin/arm64

2.provider を clone, build

$ git clone git@github.com:hashicorp/terraform-provider-template.git
$ cd terraform-provider-template
$ make build

3.build されたファイルを配置

$ mkdir -p ~/.terraform.d/plugins/registry.terraform.io/hashicorp/template/2.2.0/darwin_arm64
$ cp ~/go/1.18.4/bin/terraform-provider-template ~/.terraform.d/plugins/registry.terraform.io/hashicorp/template/2.2.0/darwin_arm64

これで M1 Mac でも該当の provider が使えるようになり terraform init を実行できます。
Template provider に限らず、他の provider でも同様の方法で解決できます。

既存のコードが非推奨になっている

例えば、先に出てきた Template provider は、すでに非推奨となっています。 Terraform Registry

Terraform や provider は頻繁に更新されているため、既存コードが非推奨になっているケースに遭遇することもあるかと思います。余裕があれば、書き換えていくのがいいでしょう。書き換えた際には、リソース自体に差分がでていないことを確認します。

1.Template provider の記述を削除

data "template_file" "task_definitions" {
  template = file("./task_definitions.json")
  vars = {
    container_app_name  = "app"
    container_app_image = “XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/app"
  }
}

2.Templatefile function として追加

resource "aws_ecs_task_definition" "ecs_task_definition" {
  # 省略

  container_definitions = templatefile("./task_definitions.json",
    {
    container_app_name  = "app"
    container_app_image = “XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/app"
  })
}

3.差分を確認

$ terraform plan
No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

Lockファイルの checksum error が発生する

terraform init を実行したときに作成される lock ファイル(.terraform.lock.hcl)は下記のような形式になっています。h1 にローカルで使用しているプラットフォームのハッシュ値が、zh にprovider が配布するパッケージのハッシュ値が記録されています。

provider "registry.terraform.io/hashicorp/aws" {
  version     = "4.45.0"
  constraints = ">= 4.45.0
  hashes = [
    "h1:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "h1:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "zh:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "zh:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  ]
}

下記の checksum error はすでに lock ファイルがあり、これまで自分と同じプラットフォームの使用者がいなかった場合に発生します。
例えば M1 Mac で以下のエラーが発生した場合 darwin_arm64 が、これまでにないプラットフォームなので互換性がない状態です。

$ terraform init
Error while installing hashicorp/template v2.2.0: the local package for registry.terraform.io/hashicorp/template 2.2.0 doesn't match any of the checksums previously recorded in the dependency lock file (this might be because the available checksums are for
 packages targeting different platforms)

これを解消するには、lock ファイルを削除した後に再度 terraform init を実行する必要があります。
しかしそれだけだと、darwin_arm64 にしか互換性のない lock ファイルが生成されてしまい、その他のプラットフォームで terraform initできなくなってしまいます。

そこで以下のように、さまざまなプラットフォームに互換性のある lock ファイルを生成します。

$ terraform providers lock \
  -platform=windows_amd64 \
  -platform=linux_arm64 \
  -platform=linux_amd64  \
  -platform=darwin_amd64 \
  -platform=darwin_arm64

Command: providers lock | Terraform | HashiCorp Developer

万が一 terraform providers lock の後に terraform init をしても checksum error が発生する場合、以下を実行すると解消します。

  1. Lock ファイルを削除
  2. terraform init をして作られたlockファイルの h1 を退避
  3. Lock ファイルを削除後に terraform providers lock
  4. 生成された lock ファイルに退避していた h1 を追加

環境ごとに provider のバージョンに差が出る

前述の通り、Terraform や provider は頻繁に更新されているため terraform init-upgradeterraform providers lockをしたときに一気にバージョンが上がったり、他の環境とのバージョンの差が出てまうことがあります。
ローカルでこれらの操作をするときにバージョンを変えたくない場合は、required_providersの version を一時的に固定する方法があります。

terraform {
  # 省略
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = “4.45.0"
    }
  }
}

Provider Requirements - Configuration Language | Terraform | HashiCorp Developer

最後に

以上が初めての Terraform 開発で起きたトラブルとその解決方法でした。
Terraform 開発は tfstate 管理、IAM role やデプロイフローの設計、リモートとの差分発生の防止など、アプリケーションとは異なるチームでの開発・運用体制が求められると思います。RevComm ではスタートアップとしてアジリティが高くかつ安定した Terraform の開発・運用体制が作られており、開発体験がとてもよかったので、その辺りについても今後記事にできたらと思っています。

RevComm ではエンジニアを募集しています。このブログを読んで興味を持っていただいたら、ぜひ採用サイトをチェックしてみてください。

www.revcomm.co.jp