Terraform v0.13にアップグレード

## 概要
個人開発で利用しているTerraformをv0.13にアップグレードした際の対応方法をまとめました。
v0.12.24 -> v0.13.0

プロバイダーはTerraform AWS Providerを利用しています。

## 対象読者
- TerraformとAWSを運用レベルで利用している方

## ソースコード
実際にアップデートした際の変更内容は[こちら](https://github.com/nekochans/kimono-app-terraform/pull/28/commits/cbdca0aae5fbc6e9212a9bafe04a87991d67d396)。`terraform 0.13upgrade`コマンドによる変更です。
コマンドについては下記にて説明します。

## 事前準備

[Upgrading to Terraform v0.13 - Terraform by HashiCorp](https://www.terraform.io/upgrade-guides/0-13.html)に記載通りに事前準備を進めます。

### v0.11を利用している場合は、v0.12にアップグレード
v0.13では、v0.11からv0.12にアップグレードするための`terraform 0.12upgrade`コマンドが含まれなくなります。そのためv0.11以前を利用している場合は、先にv0.12へのアップグレードが必要です。

今回はv0.12.24からの変更だったので、この手順は実施していません。

v0.12へのアップグレードは下記に詳しく解説されています。
 [個人開発のTerraformをv0.12にアップグレードした](https://qiita.com/keitakn/items/70e50583581c00f56687)

## `terraform plan`を実行する
`terraform plan`を実行し、差分がない状態にしておきます。
ドキュメントに、v0.13にアップグレード後stateファイルを更新するために`terraform apply`を実行する必要があると記載されています。アップグレード後に問題が起きないように差分がない状態にしておくことが推奨されます。


## terraform required_versionを`>= 0.13`に変更
ここのバージョンがv0.12になっていると、後述の`terraform 0.13upgrade`の実行時にエラーとなります。

```bash
$ terraform 0.13upgrade -yes

Error: Unsupported Terraform Core version

  on versions.tf line 2, in terraform:
   2:   required_version = "0.12.24"

This configuration does not support Terraform version 0.13.0. To proceed,
either choose another supported Terraform version or update this version
constraint. Version constraints are normally set for good reason, so updating
the constraint may lead to other errors or unexpected behavior.
```

下記のようにバージョンを変更した場合はエラーは発生しませんでした。

```versions.tf
terraform {
  required_version = ">= 0.13"

  required_providers {
    aws = "~> 2.56"
  }
}
```

## v0.13にアップグレード
アップグレード用のコマンドをすることで、プロバイダーの設定箇所が変更されます。
stateファイルが管理されている下記のディレクトリで`terraform 0.13upgrade`を実行します。

```
- providers/aws/environments/prod/10-network
- providers/aws/environments/stg/10-network
- providers/aws/environments/stg/11-acm
- providers/aws/environments/stg/12-ecr
- providers/aws/environments/stg/13-ses
- providers/aws/environments/stg/14-cognito
- providers/aws/environments/stg/20-api
```

```bash
$ terraform 0.13upgrade

This command will update the configuration files in the given directory to use
the new provider source features from Terraform v0.13. It will also highlight
any providers for which the source cannot be detected, and advise how to
proceed.

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

-----------------------------------------------------------------------------

Upgrade complete!

Use your version control system to review the proposed changes, make any
necessary adjustments, and then commit.
```

アップグレードコマンドを実行することで、Providerの設定方法が変更されます。

```versions.tf
## terraform 0.13upgrade 実行前
terraform {
  required_version = ">= 0.13"

  required_providers {
    aws = "2.70.0"
  }
}

## terraform 0.13upgrade 実行後
terraform {
  required_version = ">= 0.13"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "2.70.0"
    }
  }
}
```

stateファイルを管理しているディレクトリが複数ある場合、下記を実行することで一度に変更することができます。

```
find . -name '*.tf' | xargs -n1 dirname | uniq | xargs -n1 terraform 0.13upgrade -yes
```

[Command: 0.13upgrade - Terraform by HashiCorp](https://www.terraform.io/docs/commands/0.13upgrade.html)に記載されている手順です。

## stateファイルのProviderの指定方法を変更
アップグレード後、動作確認のために`teraform init`と`terraform plan`を実行しようとしましたが、一部エラーとなってしまいました。試行錯誤して解決できたのでその手順を記載します。

### 問題1
`terraform init`を実行すると下記のエラーが発生しました。

```
terraform init
Initializing modules...

Initializing the backend...

Error: Failed to decode current backend config

The backend configuration created by the most recent run of "terraform init"
could not be decoded: unsupported attribute "lock_table". The configuration
may have been initialized by an earlier version that used an incompatible
configuration structure. Run "terraform init -reconfigure" to force
re-initialization of the backend.
```

### 問題1の解決策
`/.terraform`を削除してから再度`terraform init`すると成功します。

### 問題2
`terraform init`は出来るようになりましたが、`terraform init`を実行するとTerraform AWS Provider v3.3.0がインストールされます。

```
terraform init
Initializing modules...
- ap_northeast_1_acm in ../../../../../modules/aws/acm
- us_east_1_acm in ../../../../../modules/aws/acm

Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Finding hashicorp/aws versions matching "2.70.0"...
- Finding latest version of -/aws...
- Installing hashicorp/aws v2.70.0...
- Installed hashicorp/aws v2.70.0 (signed by HashiCorp)
- Installing -/aws v3.3.0...
- Installed -/aws v3.3.0 (signed by HashiCorp)

The following providers do not have any version constraints in configuration,
so the latest version was installed.
```

この状態で`terraform plan`を実行するとAWS Provider v3.3.0で実行されてしまい、一部のリソースでエラーが発生しました。

### 問題2の解決策
下記の方法を実行することでstateファイルのProviderの設定を更新します。この手順ではstateファイルが更新されます。

```bash
$ terraform state replace-provider 'registry.terraform.io/-/aws' 'registry.terraform.io/hashicorp/aws'
```

stateファイルの変更

```
# 変更前
"provider": "provider.aws",

# 変更後
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
```


## 補足
v0.13へのアップグレード前後の`.terraform`ディレクトリの構成です。

```
変更前

.
├── modules
│   └── modules.json
├── plugins
│   └── linux_amd64
│       ├── lock.json
│       └── terraform-provider-aws_v2.70.0_x4
└── terraform.tfstate


変更後

├── modules
│   └── modules.json
├── plugins
│   ├── registry.terraform.io
│   │   └── hashicorp
│   │       └── aws
│   │           └── 2.70.0
│   │               └── linux_amd64
│   │                   └── terraform-provider-aws_v2.70.0_x4
│   └── selections.json
└── terraform.tfstate
```

## その他の問題

### moduleが0.13に対応していない
Terraform Registryに登録されているmoduleを利用していますが、このmoduleがv0.13に対応していないためエラーとなりました。
module側をv0.13に対応させることでエラーが解消しました。

```bash
$ terraform init
Initializing modules...

Error: Unsupported Terraform Core version

  on .terraform/modules/vpc/terraform-aws-vpc-1.0.1/versions.tf line 2, in terraform:
   2:   required_version = "~> 0.12.24"

Module module.vpc (from nekochans/vpc/aws) does not support Terraform version
0.13.0. To proceed, either choose another supported Terraform version or
update this version constraint. Version constraints are normally set for good
reason, so updating the constraint may lead to other errors or unexpected
behavior.
```
 
### 一部差分が発生した

Data Sourceを利用している箇所で差分が発生しました。特に影響はないので、この部分は`terraform apply`を実行し変更しました。

```
/data/providers/aws/environments/stg/11-acm # terraform apply
  # module.ap_northeast_1_acm.data.aws_acm_certificate.main will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "main"  {
        arn         = "arn:aws:acm:ap-northeast-1:123456789012:certificate/xxxxx"
        domain      = "*.xxxxx.net"
      ~ id          = "2020-08-25 14:07:15.7532032 +0000 UTC" -> "2020-08-25 14:07:24.2474538 +0000 UTC"
        most_recent = false
        tags        = {}
    }

  # module.us_east_1_acm.data.aws_acm_certificate.main will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "main"  {
        arn         = "arn:aws:acm:us-east-1:123456789012:certificate/xxxxx"
        domain      = "*.xxxxx.net"
      ~ id          = "2020-08-25 14:07:17.7421785 +0000 UTC" -> "2020-08-25 14:07:26.2110586 +0000 UTC"
        most_recent = false
        tags        = {}
    }

Plan: 0 to add, 0 to change, 0 to destroy.
```

## 最後に
Terraform v0.12へのアップグレードに比べると、簡単にアップグレードを実施できました。
一部エラーになった箇所については、参考になれば幸いです。

v0.13で追加された機能については記載していませんが、参考に記載したHashiCorpのブログを見ていただければと思います。

## 参考
- [Announcing HashiCorp Terraform 0.13 General Availability](https://www.hashicorp.com/blog/announcing-hashicorp-terraform-0-13/)
- [Upgrading to Terraform v0.13 - Terraform by HashiCorp](https://www.terraform.io/upgrade-guides/0-13.html)