はじめに
久々に触ったTerraformを v0.9
から v0.13
まで駆け足でバージョンアップしたので、どの辺にハマりどころがあったかメモとして残しておこうと思います。
実行環境について
-
tfenv
を使って.terraform-version
の書き換えによりバージョンアップする -
tflint
を使って記法をチェックする - tfファイル内のbackend設定は以下とし、
terraform init
時の引数でbackendのバケット名
、キー名
、リージョン名
を渡す
terraform {
backend "s3" {
dynamodb_table = "terraform-state-lock"
}
}
Terraformのバージョンアップに関するまとめ
Terraformのバージョンアップについて、こちらで簡単にまとめます。
v0.11
系までの段階的なバージョンアップについては過去に実績があったので、以下の通り段階的にバージョンアップを行ないました。
-
v0.9.8
→v0.9.11
- まず同バージョンの最新に上げる
- サクッと上げられる
-
v0.9.11
→v0.10.8
-
apply
方式に一部変更あり - サクッと上げられる
-
-
v0.10.8
→v0.11.14
-
apply
時、適用するか確認のメッセージが出力される様になる - サクッと上げられる
-
-
v0.11.14
→v0.12.28
-
HCL(HashiCorp Configuration Language)
の大幅な変更があるため、公式ドキュメントのUpgrading to Terraform v0.12に従いアップグレードを行う必要がある - 手動で直さないといけない部分もあるので、結構大変
-
-
v0.12.28
→v0.13.2
- サクッと上げられる
Terraformのバージョンアップについて
Terraform v0.9.8
から v0.9.11
へのバージョンアップ
v0.9.8
から v0.9.11
はすんなり上がりました。
$ cat .terraform-version
0.9.11
$ terraform init \
-backend-config=bucket=terraform.backend \
-backend-config=key=terraform.tfstate \
-backend-config=region=us-west-2 \
/home/username/my-terraform/tf
$ terraform plan \
-var-file=/home/username/my-terraform/conf/vars.tfvars \
-refresh=true
$ terraform apply \
-var-file=/home/username/my-terraform/conf/vars.tfvars \
-refresh=true
Terraform v0.9.11
から v0.10.8
へのバージョンアップ
v0.9.11
から v0.10.8
は一部 plan
apply
のやり方を変える必要がありました。
$ cat .terraform-version
0.10.8
$ terraform init \
-backend-config=bucket=terraform.backend \
-backend-config=key=terraform.tfstate \
-backend-config=region=us-west-2 \
/home/username/my-terraform/tf
$ terraform plan \
-var-file=/home/username/my-terraform/conf/vars.tfvars \
-refresh=true
ここまで実行したところ、以下のエラーとなりました。
Failed to load backend: Initialization required. Please see the error message above.
どうやら v0.9
系までは plan
apply
時に tf
ファイルのディレクトリを指定しなくとも動きましたが、 v0.10
系からは明示的に指定が必要になった様です。
以下の通り、引数で tf
ファイルのディレクトリを指定してやることで上手く動きました。
$ terraform plan \
-var-file=/home/username/my-terraform/conf/vars.tfvars \
-refresh=true \
/home/username/my-terraform/tf
$ terraform apply \
-var-file=/home/username/my-terraform/conf/vars.tfvars \
-refresh=true \
/home/username/my-terraform/tf
また、一部の iam_policy
では、明示的に false
設定を入れていなかったリソースに対して false
設定を入れる差分が出力されました。
false
のままで問題なかったためそのまま適用しました。
~ aws_iam_role.test_role
force_detach_policies: "" => "false"
Terraform v0.10.8
から v0.11.14
へのバージョンアップ
v0.10.8
から v0.11.14
はすんなり上がりました。
$ cat .terraform-version
0.11.14
$ terraform init \
-backend-config=bucket=terraform.backend \
-backend-config=key=terraform.tfstate \
-backend-config=region=us-west-2 \
/home/username/my-terraform/tf
$ terraform plan \
-var-file=/home/username/my-terraform/conf/vars.tfvars \
-refresh=true \
/home/username/my-terraform/tf
$ terraform apply \
-var-file=/home/username/my-terraform/conf/vars.tfvars \
-refresh=true \
/home/username/my-terraform/tf
v0.11
系から、リソースに変更がある場合は apply
実行時に差分が出力されたあと、以下のメッセージが出力されるようになります。
差分を確認して問題がなければ yes
を入力して apply
を確定します。
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
Terraform v0.11.14
から v0.12.28
へのバージョンアップ
v0.12
系から HCL
の大幅な変更があり、何もせずにそのままバージョンだけ上げるのは難しいようです。
公式ドキュメントのUpgrading to Terraform v0.12に従いアップグレードしていきます。
v0.12
系へのバージョンアップの流れ
- Terrafrom
v0.11.14
までバージョンを上げる - アップグレード前のチェックリスト対応をする
- Terraform
v0.11.14
ではterraform 0.12checklist
というヘルパーコマンドが追加されており、アップグレード前に対応すべき項目を知ることができる - チェックリストに従い、
tf
ファイルの修正を行う
- Terraform
- Terraform
v0.12
へアップグレードする -
terraform 0.12upgrade
でモジュールのアップグレードを行う- Terraform
v0.12
ではterraform 0.12upgrade
というヘルパーコマンドが追加されており、Terraformv0.11
用に書かれたモジュールをv0.12
用に更新することができ
- Terraform
terraform 0.12checklist
に関する注意事項
数字で始まる名前のモジュール名についてはチェックリストツールで自動検出できない様です。
Addendum: Invalid module namesに記載の通り、Terraform v0.11.14
リリース時点でTerraformチームが認識していなかった事象とのことです。
実際にバージョンアップした時の様子
1. Terrafrom v0.11.14
までバージョンを上げる
これは前段のバージョンアップで実施済みです。
$ cat .terrafrom-version
0.11.14
2. アップグレード前のチェックリスト対応をする
怖いぐらいすんなり通りました・・・。
$ terraform 0.12checklist /home/username/my-terraform/tf
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
3. Terraform v0.12
へアップグレードする
Terraform v0.12
へアップグレードするため、.terraform-version
を書き換えて terraform init
していきます。
$ vi .terraform-version
$ cat .terrafrom-version
0.12.28
$ terraform init \
-backend-config=bucket=terraform.backend \
-backend-config=key=terraform.tfstate \
-backend-config=region=us-west-2 \
/home/username/my-terraform/tf
terraform init
時に以下のエラーが出力されました。
Error: Unexpected comma after argument
Error: Unexpected comma after argument
on ../../home/username/my-terraform/tf/iam_policy.tf line 4, in data "aws_iam_policy_document" "sample":
4: effect = "Deny",
Argument definitions must be separated by newlines, not commas. An argument
definition must end with a newline.
ポリシードキュメントの effect
定義の終端に ,(カンマ)
が入っているのが駄目になった様です。
終端の ,(カンマ)
を削除して terraform init
したところ無事通りました。
4. terraform 0.12upgrade
でモジュールのアップグレードを行う
terraform 0.12upgrade
で tf
ファイルをTerraform v0.12
向けにアップグレードします。
$ terraform 0.12upgrade /home/username/my-terraform/tf
<snip>
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 ../../home/livesen/mb-terraform-jsen/accounts/tf?
Only 'yes' will be accepted to confirm.
Enter a value: yes
-----------------------------------------------------------------------------
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.
無事アップグレードできたので、試しに plan
してみます。
$ terraform plan \
-var-file=/home/username/my-terraform/conf/vars.tfvars \
-refresh=true \
/home/username/my-terraform/tf
-var-file
で tfvars
ファイルから変数を読み込んでいるので、以下の通り一部の初期化していない変数で Warning
が出力されるようです。
こちらについては variables.tf
ファイルなどで変数を定義しておきます。
Warning: Value for undeclared variable
The root module does not declare a variable named "env_name" but a value was
found in file "/home/livesen/mb-terraform-jsen/config/playground/env.tfvars".
To use this value, add a "variable" block to the configuration.
Using a variables file to set an undeclared variable is deprecated and will
become an error in a future release. If you wish to provide certain "global"
settings to all configurations in your organization, use TF_VAR_...
environment variables to set these instead.
Warning: Value for undeclared variable
The root module does not declare a variable named "az2" but a value was found
in file "/home/livesen/mb-terraform-jsen/config/playground/env.tfvars". To use
this value, add a "variable" block to the configuration.
Using a variables file to set an undeclared variable is deprecated and will
become an error in a future release. If you wish to provide certain "global"
settings to all configurations in your organization, use TF_VAR_...
environment variables to set these instead.
Warning: Value for undeclared variable
The root module does not declare a variable named "vpc_cidr_16" but a value
was found in file
"/home/livesen/mb-terraform-jsen/config/playground/env.tfvars". To use this
value, add a "variable" block to the configuration.
Using a variables file to set an undeclared variable is deprecated and will
become an error in a future release. If you wish to provide certain "global"
settings to all configurations in your organization, use TF_VAR_...
environment variables to set these instead.
Warning: Values for undeclared variables
In addition to the other similar warnings shown, 3 other variable(s) defined
without being declared.
Releasing state lock. This may take a few moments...
最後に、試しに apply
してみましたが問題なく通りました。
$ terraform apply \
-var-file=/home/username/my-terraform/conf/vars.tfvars \
-refresh=true \
/home/username/my-terraform/tf
5. おまけ その1: 一部でterraform 0.12upgrade
が上手くいかずに手動で書き換えた設定とエラーメッセージ
実は一部のコードについては terraform 0.12upgrade
でアップグレードできなかったため手動で書き換えた箇所がありました。
その際に出力されたエラーメッセージについてまとめます。
エラーについては、 plan
時と tflint
で出力されたものに関してまとめています。
Error: Unsupported block type
Error: Unsupported block type
on ../../home/username/my-terraform/tf/dmz_network.tf line 6, in resource "aws_vpc" "dmz":
6: tags {
Blocks of type "tags" are not expected here. Did you mean to define argument
"tags"? If so, use the equals sign to assign it a value.
tagsの記法が以下の記法でないと駄目になった様です。
tags = {
"Name" = "Sample"
}
Incorrect attribute value type
Error: Incorrect attribute value type
on ../../home/username/my-terraform/tf/dmz_network.tf line 84, in resource "aws_security_group" "dmz":
84: cidr_blocks = ["${var.vpc_network_address}", "${var.own_ips}"]
Inappropriate value for attribute "cidr_blocks": element 1: string required.
以前 cidr_blocks
に設定する値は string
と list
形式が混在していても問題なかったのですが、 string
型の list
として list(string)
を指定するようになったようです。
string
型を維持する場合は以下の様に concat
を使って list
の結合を行います。
cidr_blocks = concat(var.own_ips, [var.vpc_network_address])
今回は var.vpc_network_address
の参照箇所がここだけだったので型を string
型から list
型に変更して以下の記載としました。
cidr_blocks = concat(var.own_ips, var.vpc_network_address)
Warning: Quoted type constraints are deprecated
変数を宣言する際、 type
の指定は "(ダブルクォート)"
が不要になった様です。
Warning: Quoted type constraints are deprecated
on ../../home/username/my-terraform/tf/variables.tf line 2, in variable "env_site_url":
2: type = "map"
Terraform 0.11 and earlier required type constraints to be given in quotes,
but that form is now deprecated and will be removed in a future version of
Terraform. To silence this warning, remove the quotes around "map" and write
map(string) instead to explicitly indicate that the map elements are strings.
以下の様に修正しました。
type = map
Warning: Interpolation-only expressions are deprecated
他のリソース情報を参照する際は "${}"
で括らない記法になった様です。
Warning: Interpolation-only expressions are deprecated
on ../../home/username/my-terraform/tf/iam.tf line 41, in resource "aws_iam_policy_attachment" "sample_policy_attach":
41: policy_arn = "${aws_iam_policy.sample.arn}"
Terraform 0.11 and earlier required all non-constant expressions to be
provided via interpolation syntax, but this pattern is now deprecated. To
silence this warning, remove the "${ sequence from the start and the }"
sequence from the end of this expression, leaving just the inner expression.
Template interpolation syntax is still used to construct strings from
expressions when the template includes multiple interpolation sequences or a
mixture of literal strings and interpolations. This deprecation applies only
to templates that consist entirely of a single interpolation sequence.
6.おまけ その2: 新記法でなくとも tflint
や terraform init
, terraform plan
時に特に何もエラーが出ない記法
tagsで変数を使っている箇所
変数の参照で、以下の記法でも特に問題ないようです。
tags = {
"Name" = "AnyBatch"
"Role" = "Batch"
"Env" = "${var.env_label}"
}
他と記法を合わせる意味で、今回は以下の通り記載しました。
※ただし、VSCodeのシンタックスハイライトが効かなくなるので好みによりそうです
tags = {
"Name" = "AnyBatch"
"Role" = "Batch"
"Env" = var.env_label
}
listで変数を使っている箇所
listで記載するものについて、AWSリソースによっては特に何も指摘されないものがありました。
resource "aws_cloudfront_distribution" "promotion" {
<snip>
aliases = ["${var.promotion_url[var.env_name]}"]
<snip>
こちらも他と記法を合わせる意味で、今回は以下の通り記載しました。
resource "aws_cloudfront_distribution" "promotion" {
<snip>
aliases = [var.promotion_url[var.env_name]]
<snip>
その他、以下の項目でも、リスト内の変数参照に "${}"
が付いていても特に何も指摘されませんでした。
- aws_network_interface
- vpc_security_group_ids
- aws_instance
- vpc_security_group_ids
v0.12.28→v0.13.2
v0.12.28
から v0.13.2
へ上げる際、一部で以下の差分が出ました。
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
<= read (data resources)
Terraform will perform the following actions:
# data.aws_acm_certificate.promotion will be read during apply
# (config refers to values not yet known)
<= data "aws_acm_certificate" "promotion" {
arn = "arn:aws:acm:us-east-1:************:certificate/********-****-****-****-************"
domain = "*.stg.sample.domain"
~ id = "2020-09-17 06:55:01.618103996 +0000 UTC" -> "2020-09-17 06:57:05.718177187 +0000 UTC"
most_recent = false
tags = {}
}
Plan: 0 to add, 0 to change, 0 to destroy.
------------------------------------------------------------------------
手動で作成した ACM
を data source
として読み込んでいる場合、 id
の部分が適用時のものに更新される様です。
add
でも change
でもない差分らしく、plan結果のカウントは全て 0
になります。
そして、一度 apply
しても plan
する度に差分として出力されます。
terraform-provider-awsのコードを読んでみると
d.SetId(time.Now().UTC().String())
と書いてありますね・・・。
data source
を読み込む度に、読み込んだ日時に更新する実装になっている様です。
取り急ぎ、今回のバージョンアップに直接影響しないので別途対応としました。
※2020/10/14現在、こちらのコミットにより修正されています
https://github.com/terraform-providers/terraform-provider-aws/commit/9d9bcbd8931b628b8213541dfc61809623a911ed#diff-a71cf6c5f1fdbb1915e591e3ca8872ac05e1b7a650a61034b55b40f8da061bc3
$ cat .terraform-version
0.13.2
$ terraform init \
-backend-config=bucket=terraform.backend \
-backend-config=key=terraform.tfstate \
-backend-config=region=us-west-2 \
/home/username/my-terraform/tf
$ terraform plan \
-var-file=/home/username/my-terraform/conf/vars.tfvars \
-refresh=true \
/home/username/my-terraform/tf
$ terraform apply \
-var-file=/home/username/my-terraform/conf/vars.tfvars \
-refresh=true \
/home/username/my-terraform/tf
おわりに
以上で 2020/10/02 時点の最新バージョン v0.13.2
まで上げ終わりました。
実行する環境によってハマりどころが変わるとは思いますが、バージョンアップされる方の助けになればと思います。
参考リンク
- Terraform 0.12がリリースされたのでアップグレードしてみた
- Upgrading to Terraform v0.12
- Terraform AWS Provider Version 3 Upgrade Guide