Terraformでもいつでも最新AMIからEC2を起動したい
はじめに
こんにちは、中山です。
TerraformでAWS providerを利用しているとAMI IDをハードコードしなければならない場面があります。その都度AMCから「最新のAMI IDなんだっけ」と探さなければならず地味に面倒でした。CloudFormationの場合はLambda-Backed Custom Resourcesを使うことによって、EC2インスタンス起動時にLambda関数を起動し最新AMI IDを取得するという手法でこの問題を解決できます。詳細は以下のエントリを参照してください。
- CloudFormationでいつでも最新AMIからEC2を起動したい
- AWS CloudFormationのLambda-Backed Custom Resourcesを使って最新のAMIを取得する
CloudFormationうらやましい、でもAMI ID取得するのにLambda関数起動するのオーバースペックな気もする、などとアンビバレンツな乙女心を抱いておりましたが、Terraformでもv.0.7.0から同等の機能が取り込まれました。Data sourcesという機能です。
「Data sources」とは何か
この機能は#6598のPRで取り込まれました。すごい。ドキュメントから要点を引用すると以下の通りです。
Data sources allow data to be fetched or computed for use elsewhere in Terraform configuration. Use of data sources allows a Terraform configuration to build on information defined outside of Terraform, or defined by another separate Terraform configuration. 略 For example, a data source may retrieve artifact information from Atlas, configuration information from Consul, or look up a pre-existing AWS resource by filtering on its attributes and tags.
つまりTerraform外から情報を取得し、Terraform内でその情報を参照できる機能です。この機能を使うことにより、例えば冒頭で説明したAMI IDハードコード業から開放されるわけです。
現在対応しているData sourceはこちらを参照してください。以下の4つがあるようです。
- aws_ami
- aws_availability_zones
- aws_iam_policy_document
- aws_s3_bucket_object
今回はaws_amiをご紹介します。
それでは早速使ってみましょう。
v0.7.0-rc2をコンパイルする
まずはTerraformを用意します。現時点(2016/06/17)ではまだv0.7.0がリリースされていません。幸いRC版(v0.7.0-rc2)が出ているのでそれを利用します。v0.7.0-rc2のcommit hash値は「46a0709bba004d8b6e0eedad411270b3ae135a9e」です。ソースからコンパイルする方法はREADMEを参照してください。以下はすでに GOPATH
の設定が完了している場合の作業手順です。
$ cd $GOPATH/src/github.com/hashicorp/terraform $ git fetch origin $ git checkout 46a0709bba004d8b6e0eedad411270b3ae135a9e $ git log -1 commit 46a0709bba004d8b6e0eedad411270b3ae135a9e Author: Paul Hinze <phinze@phinze.com> Date: Sun Jun 12 19:07:52 2016 +0000 v0.7.0-rc2 $ make dev $ $GOPATH/bin/terraform version Terraform v0.7.0-rc2 (46a0709bba004d8b6e0eedad411270b3ae135a9e)
aws_amiを使う
サンプルコードをGitHubに上げておきました。以下のコマンドで実行可能です。
$ git clone https://github.com/knakayama/terraform-data-sources-demo.git $ cd terraform-data-sources-demo $ ssh-keygen -f site_key -N '' $ $GOPATH/bin/terraform plan $ $GOPATH/bin/terraform apply
コードの解説
肝となるコードが以下です。
data "aws_ami" "amazon_linux" { most_recent = true owners = ["amazon"] filter { name = "architecture" values = ["x86_64"] } filter { name = "root-device-type" values = ["ebs"] } filter { name = "name" values = ["amzn-ami-hvm-*"] } filter { name = "virtualization-type" values = ["hvm"] } filter { name = "block-device-mapping.volume-type" values = ["gp2"] } }
awscliのdescribe-imagesコマンドや各種AWS SDKの同等機能を利用したことがある方なら見ただけで内容が把握できるかと思います。それぞれのargumentを以下に解説します。
most_recent
複数の結果が返った時に最新のAMIを返します。
owners
AMIの所有者情報に基づき検索条件を絞ります。今回AWS公式AMIを利用するので amazon
を指定しています。
filter
AMIの検索条件を絞ります。設定の記述方法はawscliのdescribe-images用ドキュメントを参照してください。
aws_instance
リソースにこの出力結果を指定します。該当箇所をハイライトします。
resource "aws_instance" "ec2" { ami = "${data.aws_ami.amazon_linux.id}" instance_type = "${var.instance_type}" vpc_security_group_ids = ["${aws_security_group.ec2.id}"] subnet_id = "${aws_subnet.public.id}" key_name = "${aws_key_pair.site_key.key_name}" associate_public_ip_address = true root_block_device { volume_type = "gp2" volume_size = 8 } }
実行結果
意図した動作をするのでしょうか。実行してみましょう。
$ $GOPATH/bin/terraform apply <snip> State path: terraform.tfstate Outputs: latest_ami_id = ami-6154bb00 public_ip = 54.199.234.255
outputs.tf
でattributeを参照しているため apply
サブコマンド実行後、その値が出力されています。
output "latest_ami_id" { value = "${data.aws_ami.amazon_linux.id}" } output "public_ip" { value = "${aws_instance.ec2.public_ip}" }
ami-6154bb00
は2016/06/17現在、東京リージョンの最新AmazonLinux AMI IDです。インスタンス上でも確認してみましょう。
$ ssh -i site_key ec2-user@54.199.234.255 $ curl -s http://169.254.169.254/latest/meta-data/ami-id ami-6154bb00
まとめ
いかがだったでしょうか。
Data sourcesで夢がひろがりんぐですね。
本エントリがみなさんの参考になれば幸いです。