Terraform簡易チュートリアル on AWS

## 概要
[Terraform](http://www.terraform.io/)のAWSを使って、CLIを通してインスタンスの起動→変更→停止を行うためのチュートリアル。Terraform の基本概念である `plan` `apply` `show` のサイクルを理解するためのもの。

追記
Terraformのblog投稿、参考訳 - Qiita
http://qiita.com/zembutsu/items/402e02950ce9d59fa0e6
Terraform入門 日本語訳 - Qiita
http://qiita.com/zembutsu/items/84f5478701c5391df537

## Terraform とは

[Hashicorp](http://www.hashicorp.com/) (Vagrant, Packer, Serf, Consul を作っている会社) によって 7/28 に公開された新しいオープンソースのプロダクト。

* Terraform
 * http://www.terraform.io/

* Terraform - HashiCorp
 * http://www.hashicorp.com/blog/terraform.html

> Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform can manage existing and popular service providers as well as custom in-house solutions.

Terraform は、インフラ環境における構築・変更・バージョン変更を安全かつ効率的に行うツール。Terraformは既存の有名なサービスプロバイダが提供している内部サービスも管理できます。

## 事前準備

* AWS のアカウント
 * Access Key ID
 * Secret Access Key
* t1.micro インスタンス利用料金($0.8ドルくらい)が実費で必要

## Terraform のダウンロード・動作確認

Terraform は、MacOS 版(AMD64)、Linux 版 (i386, AMD64)、Windows 版(i386) のバイナリが、[ダウンロードページ](http://www.terraform.io/downloads.html)から配付されている。以下、Linux 版のダウンロードと展開。展開前にディレクトリを作成しているのは、カレントにバイナリが展開されるため。

```bashhh
$ mkdir terraform
$ cd terraform
$ wget -O 0.1.0_linux_amd64.zip https://dl.bintray.com/mitchellh/terraform/0.1.0_linux_amd64.zip
$ unzip ./0.1.0_linux_amd64.zip
Archive:  ./0.1.0_linux_amd64.zip
  inflating: terraform
  inflating: terraform-provider-aws
  inflating: terraform-provider-consul
  inflating: terraform-provider-digitalocean
  inflating: terraform-provider-dnsimple
  inflating: terraform-provider-heroku
  inflating: terraform-provisioner-file
  inflating: terraform-provisioner-local-exec
  inflating: terraform-provisioner-remote-exec
```

動作確認は、そのままコマンドを実行するだけ。

必要があれば、パスの通った `/usr/bin/terraform` にコピーする。

```
$ ./terraform --version
Terraform v0.1.0
$ ./terraform
usage: terraform [--version] [--help] <command> [<args>]

Available commands are:
    apply      Builds or changes infrastructure
    graph      Create a visual graph of Terraform resources
    output     Read an output from a state file
    plan       Generate and show an execution plan
    refresh    Update local state file against real resources
    show       Inspect Terraform state or plan
    version    Prints the Terraform version
```

## Terraform を使う

### インフラの構築(build)

#### 設定ファイルの用意

まずはじめに、定義ファイルを作成する。拡張子は`*.tf`。ここでは`aws.tf` を作成する。

```
provider "aws" {
    access_key = "自分のACCESS_KEY_をここに"
    secret_key = "自分のSECRET_KEY_をここに"
    region = "us-east-1"
}

resource "aws_instance" "example" {
    ami = "ami-408c7f28"
    instance_type = "t1.micro"
}
```

以降、`terraform`実行時は、カレントディレクトリ内の`*.tf`ファイルが自動的に読み込まれる。


#### `plan` で計画

インフラ環境を新しく作るので、`plan` コマンドで変更内容を確認する。

```
$ ./terraform plan
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.example
    ami:               "" => "ami-408c7f28"
    availability_zone: "" => "<computed>"
    instance_type:     "" => "t1.micro"
    key_name:          "" => "<computed>"
    private_dns:       "" => "<computed>"
    private_ip:        "" => "<computed>"
    public_dns:        "" => "<computed>"
    public_ip:         "" => "<computed>"
    security_groups:   "" => "<computed>"
    subnet_id:         "" => "<computed>"
```

ここでは、設定ファイルで定義した AMI `ami-408c7f28` を読み出そうとしていること、そしてインスタンスタイプが`t1.micro`である事が確認できる。

#### `apply` でインスタンス起動

`terraform apply` を実行すると、先に `plan` で確認した内容が実行される。

```
$ ./terraform apply
aws_instance.example: Creating...
  ami:           "" => "ami-408c7f28"
  instance_type: "" => "t1.micro"
aws_instance.example: 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
```

この時、AWS の Management Console を確認すると、実際にインスタンスの起動が始まることが確認できる。

#### `show` で進行状況の確認

public IP や private IP など、インスタンスに関連する情報が確認できる。`show` コマンドでは引数が必須。`apply`時、デフォルトの出力は `terraform.tfstate` というファイルなので、次のように状況を確認する。

```
$ ./terraform show terraform.tfstate
aws_instance.example:
  id = i-98c6ddb3
  ami = ami-408c7f28
  availability_zone = us-east-1d
  instance_type = t1.micro
  key_name =
  private_dns = ip-10-178-172-29.ec2.internal
  private_ip = 10.178.172.29
  public_dns = ec2-107-20-63-177.compute-1.amazonaws.com
  public_ip = 107.20.63.177
  security_groups.# = 1
  security_groups.0 = default
  subnet_id =
```

以上で、インスタンスの起動が完了する。

### 変更

先ほど作成した `aws.tf` を編集し、AMI の種類を違うものにする。

```
resource "aws_instance" "example" {
    ami = "ami-aa7ab6c2"
    instance_type = "t1.micro"
}
```

AMI を差し替えるために、`plan` を実施。変更予定内容を確認する。

```
$ ./terraform plan
Refreshing Terraform state prior to plan...

aws_instance.example: Refreshing state... (ID: i-98c6ddb3)

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.example
    ami:               "ami-408c7f28" => "ami-aa7ab6c2" (forces new resource)
    availability_zone: "us-east-1d" => "<computed>"
    key_name:          "" => "<computed>"
    private_dns:       "ip-10-178-172-29.ec2.internal" => "<computed>"
    private_ip:        "10.178.172.29" => "<computed>"
    public_dns:        "ec2-107-20-63-177.compute-1.amazonaws.com" => "<computed>"
    public_ip:         "107.20.63.177" => "<computed>"
    security_groups:   "" => "<computed>"
    subnet_id:         "" => "<computed>"
```

変更内容を適用するためには、`apply` を実施。

```
$ ./terraform apply
aws_instance.example: Refreshing state... (ID: i-98c6ddb3)
aws_instance.example: Destroying...
aws_instance.example: Destruction complete
aws_instance.example: Modifying...
  ami: "ami-408c7f28" => "ami-aa7ab6c2"
aws_instance.example: Modifications complete

Apply complete! Resources: 0 added, 1 changed, 1 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
```

再び AWS Management Console を確認すると、AMI が差し替わっていることが確認出来る。このとき、インスタンスの状態が、`show` コマンドで見る内容と一致していることがわかる。

```
$ ./terraform show terraform.tfstate
aws_instance.example:
  id = i-dbf2e9f0
  ami = ami-aa7ab6c2
  availability_zone = us-east-1d
  instance_type = t1.micro
  key_name =
  private_dns = ip-10-9-160-50.ec2.internal
  private_ip = 10.9.160.50
  public_dns = ec2-54-82-34-124.compute-1.amazonaws.com
  public_ip = 54.82.34.124
  security_groups.# = 1
  security_groups.0 = default
  subnet_id =
```

変更適用後に `plan` を実施しても、既に変更箇所が無いことがわかる。

```
$ ./terraform plan
Refreshing Terraform state prior to plan...

aws_instance.example: Refreshing state... (ID: i-dbf2e9f0)

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

### インスタンス終了

インスタンスを破棄するときも、まずは `plan` を行う。今回は対象となる既存の環境を破棄 `-destroy` したいので、次のように作成。

```
$ ./terraform plan -destroy -out=./terraform.tfplan
Refreshing Terraform state prior to plan...

aws_instance.example: Refreshing state... (ID: i-dbf2e9f0)

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.

Your plan was also saved to the path below. Call the "apply" subcommand
with this plan file and Terraform will exactly execute this execution
plan.

Path: ./terraform.tfplan

- aws_instance.example
```

それから `apply` で、破棄する設定情報を適用する。

```
$ ./terraform apply ./terraform.tfplan
aws_instance.example: Destroying...
aws_instance.example: Destruction complete

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

再び AWS Management Console で、対象インスタンスが破棄(terminate)されていくことが分かる。

### 次のステップ

その他のドキュメント：

* ElasticIP の定義と適用
 * http://www.terraform.io/intro/getting-started/dependencies.html

* プロビジョナーの定義 (構成管理ツール適用)
 * http://www.terraform.io/intro/getting-started/provision.html

* リージョン変更
 * http://www.terraform.io/intro/getting-started/variables.html

* Web DB 構成
 * http://www.terraform.io/intro/examples/aws.html

* 複数の事業者をまたぐ
 * http://www.terraform.io/intro/examples/cross-provider.html

* 設定例
 * http://www.terraform.io/intro/examples/count.html

* Consul 連携例
 * http://www.terraform.io/intro/examples/consul.html

.. などなど、詳細は http://www.terraform.io/





## 参考

* Installing Terraform - Terraform
 * http://www.terraform.io/intro/getting-started/install.html