待ちに待ったTerraform v0.7がリリースされました!!
Hashicorp社のブログにもリリース情報が掲載されています。
https://www.hashicorp.com/blog/terraform-0-7.html
今回は機能追加/変更など大きめのものが多かったからか、アップグレードガイドが用意されています。
https://www.terraform.io/upgrade-guides/0-7.html
アップグレードについて以下に意訳がてらメモを残しておきます。
(詳しいことは上のアップグレードガイドを参照してくださいね!)
Plugin Binaries
0.6系までは以下のようにバイナリが分割されていました。
terraform # core binary
terraform-provider-* # provider plugins
terraform-provisioner-* # provisioner plugins
これらのバイナリは$PATH
が通ったところ、または~/.terraform.d
に配置されているはずです。
0.7系ではこれらのバイナリが統合され、terraform
バイナリのみとなりました。
このためアップグレードする際はterraform
バイナリを置き換えたのちにterraform-provider-*
やterraform-provisioner-*
バイナリは削除してください。
筆者注
Terraform組み込みのプロバイダ/プロビジョナ以外の外部プラグインについてはこれまで通りバイナリ分割されています。
- Terraform for さくらのクラウド(
terraform-provider-sakuracloud
バイナリ) - Terraform for Arukas(
terraform-provider-arukas
バイナリ)
などです。これらはこれまで通り、$PATH
が通ったところ、または~/.terraform.d
に配置すればOKです。
Maps in Displayed Plans
これまで、配列の要素数は#
で表現されていました。
これからはListについては#
、Mapについては%
で表現されます。
somelist.#: "0" => "1"
somelist.0: "" => "someitem"
somemap.%: "0" => "1"
somemap.foo: "" => "bar"
String Concatenation
concat()
関数はこれまで配列の結合、文字列の結合両方に対応していましたが、
0.7系では配列でのみ利用可能です。文字列で利用するとエラーとなります。
"${concat(var.foo, "-suffix")}" # => Error! No longer supported.
文字列の場合は、以下のようにします。
"${var.foo}-suffix"
Nested Quotes and Escaping
これまで、後方互換性確保のために以下のような書き方ができましたが今後エラーとなります。
"${lookup(var.somemap, \"somekey\")}" # => Syntax Error!
${}
の内側では新たなクォートコンテキストとなるため、以下のように書けばOKです
"${lookup(var.somemap, "somekey")}"
もし${}
の内側の文字列内でダブルクォートを使いたい場合はエスケープを行います。
"${upper("\"quoted\"")}" # => "QUOTED"
upper()
関数の引数として"quoted"
というダブルクォートを含む文字を指定していますね。
この場合はエスケープが必要ということです。
Safer terraform plan Behavior
0.6系まではterraform plan
実行時にstateファイルが更新されてしまうことがありました。
terraform plan
ではリソース状態のリフレッシュ(APIなどで情報を再取得)が行われるのですが、
そのタイミングでstateファイルが書き換わってしまうということがありました。
0.7系ではこの点が改善され、plan
は副作用なく(stateファイルが更新されることなく)実行できます。apply
またはrefresh
を実行するとstateファイルの更新が行われます。
Migrating to Data Sources
0.7系ではData Sources
が追加されました。
(読み取り専用のリソースみたいなやつですね)
これにより、幾つかのリソースが非推奨となりました。
(まだ使えるけど警告が出ます)
以下のリソースが非推奨となったものです。
atlas_artifact
template_file
template_cloudinit_config
tls_cert_request
これらのリソースをData Sources
に対応させるには、以下のようにresource
キーワード部分をdata
に変えるだけです。
変更前:
resource "template_file" "example" {
template = "someconfig"
}
resource "aws_instance" "example" {
user_data = "${template_file.example.rendered}"
# ...
}
変更後:
data "template_file" "example" {
template = "someconfig"
}
resource "aws_instance" "example" {
user_data = "${template_file.example.rendered}"
# ...
}
Migrating to native lists and maps
0.7系ではList、Mapをファーストクラスオブジェクトとして扱うようになりました。
これまでjoin()
とsplit()
などで擬似的に表現していた配列などの記述が直感的に、すっきりと表現できるようになりました。
0.6系での書き方
例えば、モジュールからのOutputですが、これまでは1つの値しか返せなかったため、
join()
でカンマ区切り文字列などにすることで擬似的に配列扱いさせていました。
output "private_subnets" {
value = "${join(",", aws_subnet.private.*.id)}"
}
この値を利用する側では、split()
してカンマ区切りから配列に戻して使っていました。
subnet_id = "${element(split(",", var.private_subnets), count.index)}"
注: element([list] , index)
は指定配列の中からindexの位置にある要素を返す関数
0.7系での書き方
0.7系では配列を直接返すことができるようになりました。
output "private_subnets" {
value = ["${aws_subnet.private.*.id}"]
}
この値を利用する側も[]
構文が使えるようになったため、直感的に書けるようになりました。
subnet_id = "${var.private_subnets[count.index]}"
これらはモジュールだけでなく、variableなどでも使えます。
おまけ
element
関数もこれまで通り使えます。[]
と比べると、配列要素数より大きい値が指定できるという点があります。
例えば以下のように指定した場合、
subnet_id = "${element(var.private_subnets, count.index)}"
private_subnetsの要素数が3、要素数以上のindexが指定されたらmod
してくれたりします。
(index=3の場合はprivate_subnets[0]、index=4の場合はprivate_subnets[1]、、、ですね)
Map value overrides
これまではmap型変数の上書きにはカンマ区切りでの名前指定を行っていました。
例として、以下のような変数定義に対し、
variable "amis" {
type = "map"
default = {
us-east-1 = "ami-123456"
us-west-2 = "ami-456789"
eu-west-1 = "ami-789123"
}
}
コマンドラインオプションで-var "amis.us-west-2=overriden_value"
という書き方で上書きしていました。
(環境変数、tfvarファイルでの指定も同様)
0.7系ではこれが変更され、以下のようになります。
-var 'amis = { us-west-2 = "overriden_value" }'
map型変数はdefault値とコマンドライン(など)で指定された値がマージされます。
先ほどの変数定義は以下のような値になります。
{
us-east-1 = "ami-123456"
us-west-2 = "overriden_value"
eu-west-1 = "ami-789123"
}
注:これまでの書き方-var "amis.us-west-2=overriden_value"
をしてもエラーになりませんが、変数の上書きはできないようです。
terraform plan
するだけでは気づけない可能性もありますのでこの部分は注意が必要そうですね。
見るべき点は
-
terraform.tfvars
ファイルでの指定 -
-var-file
フラグで指定しているファイル - 環境変数
TF_VAR_[name]
など
などでしょうか。
変数定義、上書き方法についての詳細は公式ドキュメント:variablesに記載されていますので参照してみてください。
その他注意点(筆者追記)
エラーの例1:
アップグレード時に以下のようなエラーが出ることがあります。
Error configuring: 1 error(s) occurred:
* Unrecognized remote plugin message: 2|unix|/var/folders/wh/5gklk3s17hn9c60827qnkgk99999gn/T/tf-plugin9999999
This usually means that the plugin is either invalid or simply
needs to be recompiled to support the latest protocol.
これは、プラグイン(terraform-provider-*
バイナリ、またはterraform-provisioner-*
バイナリ)のバージョンが古い場合に表示されます。
0.6系のプラグインのバイナリが残っていないか確認しましょう。
(プラグイン自体が0.7系に対応していない場合もありますが、、、その場合は該当プラグイン開発者にIssue投げましょう)
エラーの例2:
Error configuring: 1 error(s) occurred:
* Incompatible API version with plugin. Plugin version: 1, Ours: 2
これはプラグインは0.7系になっているが、terraform
本体のバージョンが古い場合に出ます。
terraform version
コマンドを実行して、きちんとterraform本体が0.7系になっているか確認しましょう。
終わりに
Terraform v0.7になって様々な機能がより使いやすくなりました。
特にimport
については強力な機能です。
参考記事:Terraform v0.7が誘う「Infrastructure as Code」の世界
また、List/Mapが使える範囲が拡大したことで、よりモジュール化しやすくなっています。
この新しいバージョンを機にぜひTerraformでInfrastructure as Codeしてみてください!
こちらもよろしくお願いします!もちろんTerraform v0.7対応してます。
以上です。