Terraform v0.8.0がリリースされました

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは、中山です。

2016/12/13、Terraformのv0.8.0がリリースされました。CHANGELOGはこちらです。正式リリースする前からいくつかエントリにまとめていたので、ご興味があれば以下のエントリも参照していただけると幸いです。

本エントリではさまざまあるアップデート/機能改善の内、私が気になったポイントをご紹介したいと思います。

count で条件指定に対応

該当のドキュメントはこちらです。このアップデートは恐らくこちらのPR取り込まれたものだと思います。こちらのIssueで古くから議論されていた機能ですね。Terraformのコミッタと思われる方が少し前に報告されていたようです。

v0.8.0の中でも比較的大きな変更点の内の一つだと思います。 count を利用することにより条件指定に対応しました。 count に0を指定するとリソースが作成されないという性質を利用した実装方法となっています。といっても正確には「条件指定が書きやすくなった」の方が正しいかもしれません。以前のバージョンからこの性質は存在していました。事実この性質を利用して擬似的な条件文の記述方法を解説しているブログエントリがありました。以前のバージョンであるv0.7.13で以下のtfファイルを実行すると、1の場合は新規リソースが作成され0の場合は何も作成されません。

  • count が1の場合
provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_eip" "lb" {
  count = 1
  vpc   = true
}

結果

$ 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.


The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ aws_eip.lb
    allocation_id:     "<computed>"
    association_id:    "<computed>"
    domain:            "<computed>"
    instance:          "<computed>"
    network_interface: "<computed>"
    private_ip:        "<computed>"
    public_ip:         "<computed>"
    vpc:               "true"


Plan: 1 to add, 0 to change, 0 to destroy.
  • count が0の場合
provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_eip" "lb" {
  count = 0
  vpc   = true
}

結果

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.


No changes. Infrastructure is up-to-date. This means that Terraform
could not detect any differences between your configuration and
the real physical resources that exist. As a result, Terraform
doesn't need to do anything.

こういったTipsを利用して条件文を記述はできたのですが、若干バッドノウハウですし、なによりもあまり可読性は高くありません。今回のアップデートの一番のポイントは可読性が高まったという点だと思います。一般的なユースケースは環境毎に作成するリソースを変更したい場合だと思います。例えば以下のように記述可能です。

variable "env" {}

provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_eip" "lb" {
  count = "${var.env == "prd" ? 1 : 0 }"
  vpc   = true
}

env 変数の値によって以下のように結果が異なります。

# devの場合は何も新規リソースが作成されない
$ terraform plan -var env=dev
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.


No changes. Infrastructure is up-to-date. This means that Terraform
could not detect any differences between your configuration and
the real physical resources that exist. As a result, Terraform
doesn't need to do anything.
# prdの場合は新規リソースが作成される
$ terraform plan -var env=prd
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.


The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ aws_eip.lb
    allocation_id:     "<computed>"
    association_id:    "<computed>"
    domain:            "<computed>"
    instance:          "<computed>"
    network_interface: "<computed>"
    private_ip:        "<computed>"
    public_ip:         "<computed>"
    vpc:               "true"


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

? の後に変数展開も可能なので、環境によって参照するリソースを変更するなどより柔軟な使い方もできそうですね。

tfファイルでバージョン指定が可能になった

該当ドキュメントはこちらです。本機能はこちらのPRで取り込まれました。

今まではtfファイルを実行する際にTerraformのバージョンを固定する方法がネイティブでサポートされていなかったため、実行するバージョンによって結果が異なってしまうという問題が発生しがちでした。この問題に対応するためにCIを導入して、常に一箇所かつ同じバージョンで実行させるといったプラクティスで対応していたかと思います。ただその場合も問題は存在し、例えばCircleCIを利用している場合であれば、 circle.yml に記述したTerraformのバージョンアップデートを忘れて古いバージョンを使い続けていたなんてことが発生しがちでした。今回のアップデートにより明示的に対応したTerraformバージョンを指定できるので、こういった問題が発生しにくくなると思います。

使い方は簡単です。基本的に読み込まれるtfファイルに以下のブロックを書いておけばOKです。

terraform {
  required_version = "~> 0.8.0"
}

required_version"<比較演算子> <バージョン>" という形式で記述します。比較演算子は結構柔軟に対応しているようです。上記れであれば0.8.0以上0.9.0未満のバージョンであればOKということを意味します。ちなみにエラーになった場合以下のような出力が行われます。

The currently running version of Terraform doesn't meet the
version requirements explicitly specified by the configuration.
Please use the required version or update the configuration.
Note that version requirements are usually set for a reason, so
we recommend verifying with whoever set the version requirements
prior to making any manual changes.

  Module: root
  Required version: > 0.8.0
  Current version: 0.8.0

Lightsail関連のリソースが追加された

re:Invent 2016で発表されたAWS版VPSであるLightsailに対応しました。まだCloudFormationに対応してないのでかなり早いサポートだと思います。導入されたリソースは以下の3つです。

今回は aws_lightsail_key_pairaws_lightsail_instance を利用してWordpressインスタンスを立ち上げてみます。まだLightsail用のデータソースは導入されてないようなので、externalデータソースを利用して取得してみます。

  • externalデータソース用シェルスクリプト
#!/usr/bin/env bash

set -e
eval "$(jq -r '@sh "GROUP=\(.group)"')"

blueprint_id="$(aws lightsail get-blueprints \
  --region us-east-1 \
  --query 'blueprints[?group==`wordpress`].blueprintId' \
  --output text)"

jq -n --arg "blueprint_id" "$blueprint_id" '{"WpBlueprintId": $blueprint_id}'
  • tfファイル
provider "aws" {
  region = "us-east-1"
}

data "external" "wp_blueprint_id" {
  program = ["bash", "${path.module}/get-blueprints.sh"]

  query = {
    group = "wordpress"
  }
}

resource "aws_lightsail_key_pair" "key_pair" {
  public_key = "${file("${path.module}/keys/key_pair.pub")}"
}

resource "aws_lightsail_instance" "wp" {
  name              = "wp"
  availability_zone = "us-east-1b"
  blueprint_id      = "${data.external.wp_blueprint_id.result["WpBlueprintId"]}"
  bundle_id         = "nano_1_0"
  key_pair_name     = "${aws_lightsail_key_pair.key_pair.id}"
}
  • 実行結果
$ terraform apply
data.external.wp_blueprint_id: Refreshing state...
aws_lightsail_key_pair.key_pair: Refreshing state... (ID: terraform-00b2980702b2d0216206b20e98)
aws_lightsail_instance.wp: Creating...
  arn:                "" => "<computed>"
  availability_zone:  "" => "us-east-1b"
  blueprint_id:       "" => "wordpress_4_6_1"
  bundle_id:          "" => "nano_1_0"
  cpu_count:          "" => "<computed>"
  created_at:         "" => "<computed>"
  ipv6_address:       "" => "<computed>"
  is_static_ip:       "" => "<computed>"
  key_pair_name:      "" => "terraform-00b2980702b2d0216206b20e98"
  name:               "" => "wp"
  private_ip_address: "" => "<computed>"
  public_ip_address:  "" => "<computed>"
  ram_size:           "" => "<computed>"
  username:           "" => "<computed>"
aws_lightsail_instance.wp: Still creating... (10s elapsed)
aws_lightsail_instance.wp: Still creating... (20s elapsed)
aws_lightsail_instance.wp: Still creating... (30s elapsed)
aws_lightsail_instance.wp: Still creating... (40s elapsed)
aws_lightsail_instance.wp: Creation complete

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate

マネジメントコンソールで確認してみると正常にインスタンスが起動しているようです。

tf-v0-8-0-1

まとめ

いかがだったでしょうか。

v0.7.0のリリースが2016/08/03なので、大体4ヶ月越しの実質的なメジャーバージョンアップですね。このペースで行くと来年あたりついにv1.0リリースが叶うかもしれません。今後も注目していきたいと思います。

本エントリがみなさんの参考になったら幸いに思います。