オーケストレーションツールとして Amazon CloudFormation
をちょっと見てみたけど、なんか面倒な感じがしたので流行りそうな Terraform
を試してみる。
環境はMac(Yosemite 10.10.2)。
目標はAWSにEC2インスタンスを構築して破棄すること。
Terraformインストール
Homebrewを使用してGo言語とMecurialを入れ、Githubからソースを落としてコンパイルする。
(MacのZIP版[v0.3.7]だと微妙にバグっぽい感じがあったのでソースが良さげ)
$ brew install hg
$ brew install go
$ echo 'export GOPATH=${HOME}/.golang' >> ~/.bash_profile
$ echo 'export PATH=${PATH}:${GOROOT}/bin:${GOPATH}/bin' >> ~/.bash_profile
$ source ~/.bash_profile
$ git clone https://github.com/hashicorp/terraform ${GOPATH}/src/github.com/hashicorp/terraform
$ cd ${GOPATH}/src/github.com/hashicorp/terraform
$ make updatedeps
$ make dev
$ terraform -version
Terraform v0.4.0-dev (da7f307e5696c640612173368b8faa4bc68e511a)
どうやって作るか
基本的には以下の流れで進める。
- 作業ディレクトリを作成し、そこに定義ファイル群を配置
-
terraform plan
で構築の確認 -
terraform apply
で構築実行 -
terraform show
で確認 - 破棄する場合は
terraform plan --destory
で確認 - OKなら
terraform destroy
で破壊
定義作成
作業用ディレクトリを作成し、そこに設定ファイルと変数用ファイルの2ファイルを作成する。
1ファイルでも可能だが、後々分割することを考えて最初からそうしてみる。
ざっくりとは provider
を定義して、それに関連する resource
を定義し、variable
という変数を適宜使う流れ。詳細は本家のドキュメント。
なお、設定は .tf
、変数は .tfvars
という拡張子。特に変数は .tf
だとエラーになる。
terraform plan
コマンドで定義に問題がないか事前確認する。
$ mkdir -p ~/terraform/test
$ cd ~/terraform/test
$ vi test.tf
$ vi test.tfvars
$ terraform plan -var-file=test.ifvars
Refreshing Terraform state prior to plan...
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.
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_instance.test01
ami: "" => "ami-XXXXXXXX"
availability_zone: "" => "ap-northeast-1X"
ebs_block_device.#: "" => "<computed>"
ephemeral_block_device.#: "" => "<computed>"
instance_type: "" => "t2.micro"
key_name: "" => "XXXXXXXX"
private_dns: "" => "<computed>"
private_ip: "" => "X.X.X.X"
public_dns: "" => "<computed>"
public_ip: "" => "<computed>"
root_block_device.#: "" => "<computed>"
security_groups.#: "" => "1"
security_groups.348470369: "" => "sg-XXXXXXXX"
subnet_id: "" => "subnet-XXXXXXXX"
tags.#: "" => "1"
tags.Name: "" => "TAG_NAME"
tenancy: "" => "<computed>"
設定ファイル
変数を宣言し、AWS用の provider
とEC2インスタンス用の resource
をそれぞれ定義。
resource
は resource TYPE NAME
という感じで、NAME
は任意。但し、変数化は無理っぽい。
variable "access_key" {}
variable "secret_key" {}
variable "key_path" {}
variable "key_name" {}
variable "region" {}
variable "ami" {}
variable "type" {}
variable "name" {}
variable "az" {}
variable "sg" {}
variable "subnet" {}
variable "ip" {}
provider "aws" {
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
region = "${var.region}"
}
resource "aws_instance" "test01" {
ami = "${var.ami}"
instance_type = "${var.type}"
availability_zone = "${var.az}"
security_groups = ["${var.sg}"]
subnet_id = "${var.subnet}"
private_ip = "${var.ip}"
key_name = "${var.key_name}"
tags {
Name = "${var.name}"
}
}
変数用ファイル
設定ファイル内で宣言した変数に代入する値を記載。
拡張子は .tfvars
でないと引数で指定してもエラーとなる。
access_key = "XXXXXXXX"
secret_key = "XXXXXXXX"
key_path = "/path/to/key.pem"
key_name = "XXXXXXXX"
region = "ap-northeast-1"
ami = "ami-XXXXXXXX"
type = "t2.micro"
name = "TAG_NAME"
az = "ap-northeast-1X"
sg = "sg-XXXXXXXX"
subnet = "subnet-XXXXXXXX"
ip = "X.X.X.X"
変数の値は実行時に与えるのが基本的な考え方っぽい。
なので、設定内では変数宣言のみで、実際の値を変数用ファイルとして用意しておく感じ。
構築
terraform plan
でエラーがなければ実際に構築する。
-var-file
引数で変数用ファイルを指定する。
$ terraform apply -var-file=test.tfvars
aws_instance.test01: Creating...
ami: "" => "ami-XXXXXXXX"
availability_zone: "" => "ap-northeast-1X"
ebs_block_device.#: "" => "<computed>"
ephemeral_block_device.#: "" => "<computed>"
instance_type: "" => "t2.micro"
key_name: "" => "XXXXXXXX"
private_dns: "" => "<computed>"
private_ip: "" => "X.X.X.X"
public_dns: "" => "<computed>"
public_ip: "" => "<computed>"
root_block_device.#: "" => "<computed>"
security_groups.#: "" => "1"
security_groups.348470369: "" => "sg-XXXXXXXX"
subnet_id: "" => "subnet-XXXXXXXX"
tags.#: "" => "1"
tags.Name: "" => "TAG_NAME"
tenancy: "" => "<computed>"
aws_instance.test01: 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
構築後 terraform.tfstate
と terraform.tfstate.backup
という2つのファイルが作成される。
確認
先ほど作成された terraform.tfstate
に定義情報が出力されているが、コマンドでも確認可能。
$ terraform show
aws_instance.test01:
id = i-XXXXXXXX
ami = ami-XXXXXXXX
availability_zone = ap-northeast-1X
ebs_block_device.# = 0
ebs_optimized = false
ephemeral_block_device.# = 0
instance_type = t2.micro
key_name = XXXXXXXX
private_dns = ip-X-X-X-X.ap-northeast-1.compute.internal
private_ip = X.X.X.X
public_dns =
root_block_device.# = 1
root_block_device.1234567890.delete_on_termination = true
root_block_device.1234567890.iops = 0
root_block_device.1234567890.volume_size = 8
root_block_device.1234567890.volume_type = standard
security_groups.# = 1
security_groups.1234567890 = sg-XXXXXXXX
subnet_id = subnet-XXXXXXXX
tenancy = default
インスタンスIDが分かるので、実際に aws cli
でも確認してみる。
$ aws ec2 describe-instances --instance-ids i-XXXXXXXX --query 'Reservations[].Instances[].{ID:InstanceId,IP:PrivateIpAddress,TYPE:InstanceType,SUBNET:SubnetId,SG:SecurityGroups[0].GroupId,NAME:Tags[?Key==`Name`].Value|[0]}[0]'
{
"SUBNET": "subnet-XXXXXXXX",
"NAME": "TAG_NAME",
"IP": "X.X.X.X",
"TYPE": "t2.micro",
"SG": "sg-XXXXXXXX",
"ID": "i-XXXXXXXX"
}
破壊
まずは破壊対象を確認。
terraform plan
に -destroy
引数を付与すればOK。
$ terraform plan -destroy -var-file=test.tfvars
Refreshing Terraform state prior to plan...
aws_instance.test01: Refreshing state... (ID: i-XXXXXXXX)
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.
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_instance.test01
問題なければ破壊。
本当にやっちゃって良いか確認を求められるので yes
と入力。
$ terraform destroy -var-file=test.tfvars
Do you really want to destroy?
Terraform will delete all your managed infrastructure.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
aws_instance.test01: Refreshing state... (ID: i-XXXXXXXX)
aws_instance.test01: Destroying...
aws_instance.test01: Destruction complete
Apply complete! Resources: 0 added, 0 changed, 1 destroyed.
本当にいなくなったことを確認。
$ terraform show
$ aws ec2 describe-instances --instance-ids i-XXXXXXXX --query 'Reservations[].Instances[].[State.Name][]'
[
"terminated"
]
以上。