Terraform v0.8からTerraform v0.9へのアップグレード S3の状態管理ファイルを移行方法

Terraformをアップグレードした際にS3に保存していた状態管理ファイルも移行する必要が
あったのでその作業メモです。

# Terraformのアップグレード

https://www.terraform.io/downloads.html から環境に適したファイルを
ダウンロードして、解凍して作成されるterraformファイルをパスの通ったところに
配置します。
例えば以下のようにパスを通しておきます。

```bash:bash_profile
export PATH=$PATH:${HOME}/.terraform_0.9.3_darwin_amd64
```

# 状態管理ファイルの移行

Terraformのアップグレード自体は数分で終了しますが、planコマンドを実行すると以下の
メッセージが表示されます。

```
$ terraform plan
Deprecation warning: This environment is configured to use legacy remote state.
Remote state changed significantly in Terraform 0.9. Please update your remote
state configuration to use the new 'backend' settings. For now, Terraform
will continue to use your existing settings. Legacy remote state support
will be removed in Terraform 0.11.

You can find a guide for upgrading here:

https://www.terraform.io/docs/backends/legacy-0-8.html

There are warnings related to your configuration. If no errors occurred,
Terraform will continue despite these warnings. It is a good idea to resolve
these warnings in the near future.
```

どうやら、Terraformがv0.9になったタイミングで状態管理ファイルの管理方法が変更になったようです。
メッセージを見る限りではv0.11までは変更しなくても使えそうな感じですが、
https://www.terraform.io/docs/backends/legacy-0-8.html ではv0.10になったタイミングで
移行作業が必要になりそうなので、上記URLの手順に沿って新しい状態管理ファイルに移行してみます。

### 既存の状態管理ファイルの取得
最新の状態管理ファイルをremoteから取得します。

```
$terraform remote pull
```

### ローカルの状態管理ファイルのバックアップ
.terraform/terraform.tfstateファイルをterraformのプロジェクトの外に置きます。

```
$cp .terraform/terraform.tfstate /tmp/
```

### backendの設定の追加
backendの設定ファイルを作成します。
今までもS3に状態管理ファイルを置いていたので以下のURLを参考にしながら
backend.tfファイルを作成しました。
https://www.terraform.io/docs/backends/types/s3.html

```backend.tf
terraform {
  backend "s3" {
    bucket = "terraform-state"
    key    = "tf"
    region = "ap-northeast-1"
  }
}
```

### initコマンドの実行
backendの初期化コマンドを実行します。

```
$ terraform init -backend=true -force-copy  -lock=false
Initializing the backend...
New backend configuration detected with legacy remote state!

Terraform has detected that you're attempting to configure a new backend.
At the same time, legacy remote state configuration was found. Terraform will
first configure the new backend, and then ask if you'd like to migrate
your remote state to the new backend.




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

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 environment. If you forget, other
commands will detect it and remind you to do so if necessary.
```

上記のようなメッセージが表示され、移行が無事に行われたようです。


### terraform planで動作確認
最後にterraform planで動作確認をしてみます。
Deprecation warningが消えて通常の状態に戻りました。

```
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
...
```

# 追記：Amazon DynamoDBによる状態ロック設定の追加
Terraform v0.9から状態管理ファイルをロック機能が追加されました。
https://www.terraform.io/docs/backends/state.html
S3に状態管理ファイルを保存している場合は、DynamoDBを使うことで、
ロック機能を使うことができます。

[ここ](https://github.com/hashicorp/terraform/issues/12877)を参考に状態ロックに有効な状態にしてみます。

```state_lock_table.tf
resource "aws_dynamodb_table" "terraform_statelock" {
  name           = "terraform-state-lock"
  read_capacity  = 20
  write_capacity = 20
  hash_key       = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}
```

上記のようなtfファイルを作成してterraform applyで状態ロックに必要なDynamoDBのテーブルを
作成します。
DynamoDBのテーブルを作成したあとは、backendの設定ファイルを修正します。

```backend.tf
terraform {
  backend "s3" {
    bucket = "terraform-state"
    key    = "tf"
    region = "ap-northeast-1"
    lock_table = "terraform-state-lock"
  }
}
```

この状態でterraform planをしてみると以下のようなメッセージが表示されます。

```
$ terraform plan
Backend reinitialization required. Please run "terraform init".
Reason: Backend configuration changed for "s3"

The "backend" is the interface that Terraform uses to store state,
perform operations, etc. If this message is showing up, it means that the
Terraform configuration you're using is using a custom configuration for
the Terraform backend.

Changes to backend configurations require reinitialization. This allows
Terraform to setup the new configuration, copy existing state, etc. This is
only done during "terraform init". Please run that command now then try again.

If the change reason above is incorrect, please verify your configuration
hasn't changed and try again. At this point, no changes to your existing
configuration or state have been made.

Failed to load backend: Initialization required. Please see the error message above.
```
backendの設定ファイルを変更した際はterraform initを実行しなさいとのことなので、
それに従ってterraform initを実行します。

```
$ terraform init
Initializing the backend...
Backend configuration changed!

Terraform has detected that the configuration specified for the backend
has changed. Terraform will now reconfigure for this backend. If you didn't
intend to reconfigure your backend please undo any changes to the "backend"
section in your Terraform configuration.


Do you want to copy the state from "s3"?
  Would you like to copy the state from your prior backend "s3" to the
  newly configured "s3" backend? If you're reconfiguring the same backend,
  answering "yes" or "no" shouldn't make a difference. Please answer exactly
  "yes" or "no".

  Enter a value: yes



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

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 environment. If you forget, other
commands will detect it and remind you to do so if necessary.
```

以上でDynamoDBを使った状態ロックの有効化は完了です。