Terraformでインフラを構築する方法 part.1

このブログをご覧のみなさん、こんにちは。

Terraformを使ったので、その概要をまとめてみました。

TerraformはCloudFormationよりも定義ファイルが簡潔で、習得し易いツールです。
しかも、CloudFormationと違ってAWSからAzure、Google Cloud、Herokuなどさまざまな環境を対象にすることができます。

以下は、HashiCorpの公式サイトにあるTerraformのGetting Startedを実践した内容になります。

Environment

  • Mac Book Pro
    • OS X Yosemite 10.10.5
  • Terraform 0.7.1

Install Terraform

Install Terraformの手順に従って、Terraformをインストールします。

Mac向けのバイナリパッケージがあるので、Download Terraformからファイルをダウンロードし、適当なディレクトリで解凍後、パスを通すだけです。

OS Xの場合は、.bash_profileexportするといいでしょう。

export PATH="/usr/local/terraform/0.7.1/bin:$PATH"

ターミナルからterraformコマンドを実行できればセットアップ完了です。

$ terraform
usage: terraform [--version] [--help] <command> [args]

The available commands for execution are listed below.
The most common, useful commands are shown first, followed by
less common or more advanced commands. If you're just getting
started with Terraform, stick with the common commands. For the
other commands, please read the help and docs before usage.

Common commands:
    apply              Builds or changes infrastructure
    destroy            Destroy Terraform-managed infrastructure
    fmt                Rewrites config files to canonical format
    get                Download and install modules for the configuration
    graph              Create a visual graph of Terraform resources
    import             Import existing infrastructure into Terraform
    init               Initializes Terraform configuration from a module
    output             Read an output from a state file
    plan               Generate and show an execution plan
    push               Upload this Terraform module to Atlas to run
    refresh            Update local state file against real resources
    remote             Configure remote state storage
    show               Inspect Terraform state or plan
    taint              Manually mark a resource for recreation
    untaint            Manually unmark a resource as tainted
    validate           Validates the Terraform files
    version            Prints the Terraform version

All other commands:
    state              Advanced state management

Build Infrastructure

Build Infrastructureの手順に従って、AWSにEC2を構築します。

手順ではt2.microと記載されていますが、ここはt2.nanoに変えています。

provider "aws" {
  access_key = "ACCESS_KEY_HERE"
  secret_key = "SECRET_KEY_HERE"
  region     = "us-east-1"
}

resource "aws_instance" "example" {
  ami           = "ami-0d729a60"
  instance_type = "t2.nano"
}

terraform planを実行すると、実行計画を確認できます。

$ 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_instance.example
    ami:                      "ami-0d729a60"
    availability_zone:        "<computed>"
    ebs_block_device.#:       "<computed>"
    ephemeral_block_device.#: "<computed>"
    instance_state:           "<computed>"
    instance_type:            "t2.nano"
    key_name:                 "<computed>"
    network_interface_id:     "<computed>"
    placement_group:          "<computed>"
    private_dns:              "<computed>"
    private_ip:               "<computed>"
    public_dns:               "<computed>"
    public_ip:                "<computed>"
    root_block_device.#:      "<computed>"
    security_groups.#:        "<computed>"
    source_dest_check:        "true"
    subnet_id:                "<computed>"
    tenancy:                  "<computed>"
    vpc_security_group_ids.#: "<computed>"

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

はリソースを作成してみないとわからない項目です。

というわけでterraform applyを実行してみましょう。

$ terraform apply
aws_instance.example: Creating...
  ami:                      "" => "ami-0d729a60"
  availability_zone:        "" => "<computed>"
  ebs_block_device.#:       "" => "<computed>"
  ephemeral_block_device.#: "" => "<computed>"
  instance_state:           "" => "<computed>"
  instance_type:            "" => "t2.nano"
  key_name:                 "" => "<computed>"
  network_interface_id:     "" => "<computed>"
  placement_group:          "" => "<computed>"
  private_dns:              "" => "<computed>"
  private_ip:               "" => "<computed>"
  public_dns:               "" => "<computed>"
  public_ip:                "" => "<computed>"
  root_block_device.#:      "" => "<computed>"
  security_groups.#:        "" => "<computed>"
  source_dest_check:        "" => "true"
  subnet_id:                "" => "<computed>"
  tenancy:                  "" => "<computed>"
  vpc_security_group_ids.#: "" => "<computed>"
aws_instance.example: Still creating... (10s elapsed)
aws_instance.example: Still creating... (20s elapsed)
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
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

と書いてある通り、AWS上にEC2が構築されました。

Change Infrastructure

Change Infrastructureの手順に従って、AWS上に構築したEC2の設定を変えます。

<code>aws.tf</code>を修正したら、Build Infrastructureと同様に、<code>terraform plan</code>、<code>terraform apply</code>を実行します。

$ terraform plan
:
-/+ aws_instance.example
    ami:                      "ami-0d729a60" => "ami-13be557e" (forces new resource)
    availability_zone:        "us-east-1c" => "<computed>"
    ebs_block_device.#:       "0" => "<computed>"
    ephemeral_block_device.#: "0" => "<computed>"
    instance_state:           "running" => "<computed>"
    instance_type:            "t2.nano" => "t2.nano"
    key_name:                 "" => "<computed>"
    network_interface_id:     "eni-b954dda9" => "<computed>"
    placement_group:          "" => "<computed>"
    private_dns:              "ip-172-31-51-198.ec2.internal" => "<computed>"
    private_ip:               "172.31.51.198" => "<computed>"
    public_dns:               "ec2-54-164-45-203.compute-1.amazonaws.com" => "<computed>"
    public_ip:                "54.164.45.203" => "<computed>"
    root_block_device.#:      "1" => "<computed>"
    security_groups.#:        "0" => "<computed>"
    source_dest_check:        "true" => "true"
    subnet_id:                "subnet-6e303a44" => "<computed>"
    tenancy:                  "default" => "<computed>"
    vpc_security_group_ids.#: "1" => "<computed>"

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

$ terraform apply
aws_instance.example: Refreshing state... (ID: i-01c22590)
aws_instance.example: Destroying...
aws_instance.example: Still destroying... (10s elapsed)
aws_instance.example: Still destroying... (20s elapsed)
aws_instance.example: Destruction complete
aws_instance.example: Creating...
  ami:                      "" => "ami-13be557e"
  availability_zone:        "" => "<computed>"
  ebs_block_device.#:       "" => "<computed>"
  ephemeral_block_device.#: "" => "<computed>"
  instance_state:           "" => "<computed>"
  instance_type:            "" => "t2.nano"
  key_name:                 "" => "<computed>"
  network_interface_id:     "" => "<computed>"
  placement_group:          "" => "<computed>"
  private_dns:              "" => "<computed>"
  private_ip:               "" => "<computed>"
  public_dns:               "" => "<computed>"
  public_ip:                "" => "<computed>"
  root_block_device.#:      "" => "<computed>"
  security_groups.#:        "" => "<computed>"
  source_dest_check:        "" => "true"
  subnet_id:                "" => "<computed>"
  tenancy:                  "" => "<computed>"
  vpc_security_group_ids.#: "" => "<computed>"
aws_instance.example: Still creating... (5s elapsed)
:
aws_instance.example: Still creating... (30s elapsed)
aws_instance.example: Creation complete

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

インスタンスIDが変わっていることからも分かる通り、新規作成->既存破壊という流れになっています。

Destroy Infrastructure

Destroy Infrastructureの手順に従って、AWS上に構築したEC2を破棄します。

<code>terraform plan -destroy</code>で破棄の実行計画を確認します。

$ terraform plan -destroy
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.

aws_instance.example: Refreshing state... (ID: i-72c82fe3)

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_instance.example

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

続いて、<code>terraform destroy</code>で実際に破棄します。
デフォルトは<code>Enter a value:</code>で入力待ちになるので、<code>yes</code>と入力するとそのまま破棄が実行されます。

$ terraform destroy
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.example: Refreshing state... (ID: i-72c82fe3)
aws_instance.example: Destroying...
aws_instance.example: Still destroying... (10s elapsed)
aws_instance.example: Still destroying... (20s elapsed)
aws_instance.example: Still destroying... (30s elapsed)
aws_instance.example: Destruction complete

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