More than 1 year has passed since last update.

オーケストレーションツールとして 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 をそれぞれ定義。
resourceresource TYPE NAME という感じで、NAME は任意。但し、変数化は無理っぽい。

test.tf
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 でないと引数で指定してもエラーとなる。

test.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.tfstateterraform.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"
]

以上。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.