祝GA! Terraform 0.13 新機能を使ってみた

2020.08.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

2020/08/10にTerrform 0.13がGA(一般提供開始)しました。

このエントリでは0.13の新機能をレポートします。

moduleでcountやfor_eachが可能に

0.13より前のバージョンでは、これまではmoduleブロックにcountやfor_eachを使うとエラーになりました。当然使えるのかなーと思って書いてみたらエラーになった記憶があります。

0.13からは使えるようになります。たとえばAWSだと、複数アカウントを使っている場合の管制塔アカウント内のIAMユーザーから、AssumeRoleできるIAMロールを人数分作成する処理を、iam-assumable-roleというmoduleでfor_eachすることで簡潔に書くことができます。

locals {
  iam_assumable_role_settings = {
    kazue  = {username = "kazue-masaki"},
    yamada = {username = "yamada-taro"}
    //ここを人数分書いていく
  }
}

module iam_assumable_role {
  source  = "terraform-aws-modules/iam/aws//modules/iam-assumable-role"
  version = "~> 2.0"

  for_each = local.iam_assumable_role_settings

  trusted_role_arns       = ["arn:aws:iam::123456789012:user/${each.value.username}"]
  create_role             = true
  role_name               = "${each.value.username}-assumable-role"
  role_requires_mfa       = true
  custom_role_policy_arns = ["arn:aws:iam::aws:policy/AdministratorAccess"]
}

もちろん自前のmoduleに対しても使えます。とはいえ、for_eachを多用すると読みにくいコードになる(ことが多い)と思いますので、どこまで使うかは慎重に見極めたほうが良いかと思います。

countについては、従来より存在するテクニックがあります。それは、同じTerraformコードで複数環境(本番、テスト、開発など)を構築したい、さらに、あるリソースを特定の環境にだけ作成したいといった要件がある場合、count=0とするとそのリソースが作成されないことを利用したものです。このテクニックがmoduleレベルで使えるようになるのが大きいかなと思います。(for_eachでも空リストを定義すれば同じことができます。)

moduleでdepends_onが可能に

moduleに対してもdepends_onが書けるようになりました。とはいえTerraformはdepends_onを書かなくても通常は依存関係を勝手に解釈して実行してくれるので、積極的に書くものでは無いかと思います。ぱっと使い所を思い浮かべることができませんでした。入り組んだコードを書いているとたまにdepends_onが必要になる場合があるので、地味に嬉しいアップデートではあります。

3rd Party Provider自動インストール

これまでHashiCorp製のProviderしか使ってこなかったので私はあまり恩恵を感じないのですが、Community製Provider、つまり このProvider一覧の左列のFILTERでCommunityに該当するようなProviderを使う場合に、そのインストールが簡単になりました。

例としてこの GitというCommunity Providerを使う場合を考えます。

0.13より前のバージョンでは、こういったProviderを使う場合、GitHubの Releaseページから自分の環境に合うzipファイルをダウンロードしてきて展開し、その中の実行ファイルをTerraformコマンドを実行するディレクトリから見て ./.terraform.d/plugins/($OS_$ARCH)に配置してから、provider git {}をtfファイルに書き、 terraform init する必要がありました。この実行ファイルの配置をしないと以下のようなエラーになります。

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...

Provider "git" not available for installation.

A provider named "git" could not be found in the Terraform Registry.

This may result from mistyping the provider name, or the given provider may
be a third-party provider that cannot be installed automatically.

In the latter case, the plugin must be installed manually by locating and
downloading a suitable distribution package and placing the plugin's executable
file in the following directory:
    terraform.d/plugins/darwin_amd64

Terraform detects necessary plugins by inspecting the configuration and state.
To view the provider versions requested by each module, run
"terraform providers".


Error: no provider exists with the given name

0.13で実行ファイル配置なしに provider git {}をtfファイルに書き、 terraform initすると、違うエラー内容になります。

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/git...

Error: Failed to install provider

Error while installing hashicorp/git: provider registry registry.terraform.io
does not have a provider named registry.terraform.io/hashicorp/git

このエラーは terraform ブロック内に以下のように required_providers ブロックを書くと解消できます。

  terraform {
    required_version = "~> 0.13.1"
+   required_providers {
+     git = {
+       source = "innovationnorway/git"
+       version = "0.1.3"
+     }
+   }
  }

これは先程のGit Providerページ右上Use Providerボタンをクリックして表示することができます。

このrequired_providersを書けば、手動で実行ファイルを配置する必要なく、Terraform側が自動で実行ファイルをダウンロードしてくれます。

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding innovationnorway/git versions matching "0.1.3"...
- Installing innovationnorway/git v0.1.3...
- Installed innovationnorway/git v0.1.3 (self-signed, key ID 0DECE6FC440E04DE)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/plugins/signing.html

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

required_providersのsourceについて説明します。この値は [hostname]/[namespace]/typeという形式で書きます。

  • typeはproviderの名前です。この例だとgitですね。 AWSのproviderだとawsです。
  • hostnameは任意項目です。スキップした場合はregistry.terraform.ioが使われます。つまり Terraform Registryにあるものの中からtype値が一致するものを探してインストールします。
  • namespaceも任意項目です。が、hostnameを設定した際は必須になります。スキップした場合はhashicorpが使われます。つまり、Official Providerの中からtypeに一致するものを探してインストールします。
  • Official Providerの場合はこのrequired_providersを書かなくても、今まで通り providerブロックだけでもインストールできます。

変数のカスタムバリデーション

variableブロック内にvalidationブロックを書き、その中にconditionとerror_messageを書けます。 conditionに一致しない値が渡ってきた場合、error_messageをコンソールに表示します。

以下はami-idのvariableなので、ami-から始まる値にしてね、というコードです。

variable "ami_id" {
  type = string

  validation {
    condition     = can(regex("^ami-", var.example))
    error_message = "Must be an AMI id, starting with \"ami-\"."
  }
}

一人で使うTerraformコードならあまり必要ないかもしれませんが、複数人で使うコードや、Moduleとして広く公開する予定のコードであれば、これを記述しておいたほうが親切ではと思います。

その他

詳細な変更点は以下CHANGELOGをご確認ください。

感想

0.13の新機能についてお伝えしました。正直 0.12のアップデートのときほど劇的な変化は無いと感じましたが、moduleに対してfor_eachが使えるようになったのはとてもありがたいです。