Terraform 0.12がリリースされたのでアップグレードしてみた

こんにちは佐伯です。本日待望のTerraform 0.12がリリースされました!

ということで、アップグレードガイドに沿ってTerraform 0.11からアップグレードしてみました。

アップグレードガイド

はじめに、アップグレードガイドは以下リンクです。アップグレードする前に読みましょう。

アップグレードプロセス

アップグレードの流れとしては以下の通りです。

  • Terraform 0.11.14へアップグレード
  • アップグレード前チェックリストの実行
  • Terraform 0.12へのアップグレード
  • Terraformコードの修正
  • モジュールのアップグレード

事前準備

Terraform stateファイルのバックアップ

Terraform stateファイルをRemote Backendで管理しており、Remote Bacckend側の機能(S3のバージョニング機能など)でバックアップできている場合は特にバックアップを取得する必要はありませんが、もしローカルで管理しているのであればバックアップを取得しましょう。

TerraformコードのGit管理

Terraform 0.12ではHCL(HashiCorp Configuration Language)の構文自体が変わっており、Terraform 0.11との完全な互換性はありません。アップグレードするにあたって色々変更が必要になります。もしかするとTerraform 0.11に戻したくなることもあるかもしれません。もしGitで管理していない場合は、その時のためにコードはGitで管理しておきましょう。

tfenvのインストール

必須ではないですがアップグレード作業中にTerraformバージョンを何度か切り替える必要があるので、tfenvをインストールしておくとバージョン切替が楽にできて便利です。

やってみた

Terraform 0.11.14へアップグレード

これまでTerraform 0.11を使用しているのであればそのままバージョンアップすることができると思います。それ以前のバージョンを利用している場合はバージョンに応じてアップグレードガイドを確認しながらTerraform 0.11までバージョンアップします。

Terraform 0.9→0.11まで変更点については以下エントリにもまとめています。

Terraform v0.9→v0.11までの変更点をまとめてみた

tfenvでは以下のコマンドを実行してTerraform 0.11.14に変更します。

$ tfenv install 0.11.14 # Terraform 0.11.14のダウンロード
$ tfenv use 0.11.14     # Terraform 0.11.14へスイッチ
$ terraform -v
Terraform v0.11.14

アップグレード前チェックリストの実行

Terraform 0.11.14では0.12checklistサブコマンドが追加されており、このコマンドを実行してTerraform 0.12にアップグレードする前に事前にチェックを行います。

terraform 0.12checklistコマンドを実行する前にterraform initで必要なプロバイダープラグインをインストール、terraform applyでTerraform stateファイルとコードに差異が無いかを確認します。

その後、terraform 0.12checklistコマンドでチェックを実施します。このコマンドを実行することで以下の項目がチェックされます。

  • Terraform 0.12と互換性のないプロバイダーバージョンを使用していないかチェック
  • Terraform 0.12では使用できなくなった数字で始まるリソース名やプロバイダエイリアス名がないかチェック
  • 外部モジュールが上記の項目に該当しないかチェック

特に問題なければ以下のメッセージが出力されます。

Looks good! We did not detect any problems that ought to be
addressed before upgrading to Terraform v0.12

This tool is not perfect though, so please check the v0.12 upgrade
guide for additional guidance, and for next steps:
    https://www.terraform.io/upgrade-guides/0-12.html

Terraform 0.12へのアップグレード

Terraform 0.12へアップグレードします。こちらも初回にterraform initを実行します。Terraform 0.12と互換性のないコードが存在している場合は、以下のメッセージが出力されるのでコードの変更が必要となります。

Terraform has initialized, but configuration upgrades may be needed.

Terraform found syntax errors in the configuration that prevented full
initialization. If you've recently upgraded to Terraform v0.12, this may be
because your configuration uses syntax constructs that are no longer valid,
and so must be updated before full initialization is possible.

Terraform has installed the required providers to support the configuration
upgrade process. To begin upgrading your configuration, run the following:
    terraform 0.12upgrade

To see the full set of errors that led to this message, run:
    terraform validate

Terraformコードの修正

Terraform 0.12には0.12upgradeサブコマンドが追加されており、このコマンドを実行することでTerraform 0.12の構文で置換が行われます。メッセージにもあるように作業中のワーキングツリーなどではなく、別途ブランチを作成するなどしましょう。

$ terraform 0.12upgrade

This command will rewrite the configuration files in the given directory so
that they use the new syntax features from Terraform v0.12, and will identify
any constructs that may need to be adjusted for correct operation with
Terraform v0.12.

We recommend using this command in a clean version control work tree, so that
you can easily see the proposed changes as a diff against the latest commit.
If you have uncommited changes already present, we recommend aborting this
command and dealing with them before running this command again.

Would you like to upgrade the module in the current directory?
  Only 'yes' will be accepted to confirm.

  Enter a value: yes

terraform 0.12upgradeコマンド実行後、以下メッセージ出力であれば置換が成功しています。

Upgrade complete!

The configuration files were upgraded successfully. Use your version control
system to review the proposed changes, make any necessary adjustments, and
then commit.

WARNINGメッセージが出力された場合は手動で修正する必要があります。terraform 0.12upgrade実行後のメッセージにも出力されますが、コード自体にTF-UPGRADE-TODO:といったコメント行が追記されます。git grep TF-UPGRADE-TODOコマンド等で該当箇所を検索し、メッセージを読んで修正します。

私が遭遇したパターンでは、アップグレードガイドにも記載のある変数の型制約で手動変更が必要でした。aws_waf_ipsetのip_set_descriptorsの値をlist of mapの形で変数に入れて設定していました。

variable "ipset" {
  type = "list"

  default = [
    { value = "1.1.1.1/32", type="IPV4" },
    { value = "2.2.2.2/32", type="IPV4" },
  ]
}

resource "aws_waf_ipset" "whitelist_ipset" {
  name = "WhitelistIpset"
  ip_set_descriptors = "${var.ipset}"
}

terraform 0.12upgrade実行後はfor_eachでループする形に自動的に変更されてました。しかし、コメントが追記されており変数の型がlistのため、キーを指定出来ていないようでした。

variable "ipset" {
  type = list(string)

  default = [
    { value = "1.1.1.1/32", type="IPV4" },
    { value = "2.2.2.2/32", type="IPV4" },
  ]
}

resource "aws_waf_ipset" "whitelist_ipset" {
  name = "WhitelistIpset"

  dynamic "ip_set_descriptors" {
    for_each = var.ipset
    content {
      # TF-UPGRADE-TODO: The automatic upgrade tool can't predict
      # which keys might be set in maps assigned here, so it has
      # produced a comprehensive set here. Consider simplifying
      # this after confirming which keys can be set in practice.

      type  = ip_set_descriptors.value.type
      value = ip_set_descriptors.value.value
    }
  }
}

変数のタイプをlist(object)に変更することでterraform planでエラーが発生しなくなりました。

variable "ipset" {
  type = list(object({
    value = string
    type  = string
  }))

  default = [
    { value = "1.1.1.1/32", type="IPV4" },
    { value = "2.2.2.2/32", type="IPV4" },
  ]
}

resource "aws_waf_ipset" "whitelist_ipset" {
  name = "WhitelistIpset"

  dynamic "ip_set_descriptors" {
    for_each = var.ipset
    content {
      type  = ip_set_descriptors.value.type
      value = ip_set_descriptors.value.value
    }
  }
}

と、このように手動で修正な箇所はコードによって様々な理由があります。それらについてもアップグレードガイドに記載がありますので確認ください。

モジュールのアップグレード

モジュールがTerraform 0.12に対応していない場合、モジュールの更新も必要です。Terraform Module RegistryやGitHubからダウンロードしている場合、PRを送るかTerraform 0.12への対応を待つしかないと思いますが、モジュールを自作している場合は同様にterraform 0.12upgradeの実行、terraform validateを行い正常に動作するか確認する必要があります。

最後に

今回はTerraform 0.12でどういった変更があったには触れていませんが、破壊的な変更はあるものの個人的には新しい構文はかなりスッキリ書けるようになった印象があります。リリースされたばかりなので細かな修正が発生する可能性はありますが、アップグレードを検討してみてはいかがでしょうか。