Terraformを試してみる

今日はTerraformを使ってみることにしました。

Terraform


TerraformはHashiCorp社が開発しているオーケストレーションツールです。
興味があって、少し試していたのですが、今回はそのときのメモです。

セットアップなど


セットアップはバイナリをダウンロードして展開するだけなので、簡単です。

$ wget https://dl.bintray.com/mitchellh/terraform/terraform_0.3.7_linux_amd64.zip
$ unzip terraform_0.3.7_linux_amd64.zip 
Archive:  terraform_0.3.7_linux_amd64.zip
  inflating: terraform               
  inflating: terraform-provider-atlas  
  inflating: terraform-provider-aws  
  inflating: terraform-provider-cloudflare  
  inflating: terraform-provider-cloudstack  
  inflating: terraform-provider-consul  
  inflating: terraform-provider-digitalocean  
  inflating: terraform-provider-dnsimple  
  inflating: terraform-provider-google  
  inflating: terraform-provider-heroku  
  inflating: terraform-provider-mailgun  
  inflating: terraform-provider-null  
  inflating: terraform-provisioner-file  
  inflating: terraform-provisioner-local-exec  
  inflating: terraform-provisioner-remote-exec

リソースを新規に作成してみる


まず、サンプルとして、以下のようなコンフィグを用意しました。
planディレクトリの下にコンフィグを用意しています。


「terraform plan dir」「terraform apply dir」で適用します。

$ cat plan/terraform_sample.tf
provider "aws" {
  access_key = <your access key>
  secret_key = <your secret key>
  region     = "ap-northeast-1"
}

resource "aws_vpc" "tf-vpc" {
  cidr_block = "10.0.0.0/16"
  tags {
    Name = "tf-vpc"
  }
}

$ terraform plan 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_vpc.tf-vpc
    cidr_block:                "" => "10.0.0.0/16"
    default_network_acl_id:    "" => "<computed>"
    default_security_group_id: "" => "<computed>"
    enable_dns_hostnames:      "" => "<computed>"
    enable_dns_support:        "" => "<computed>"
    main_route_table_id:       "" => "<computed>"
    tags.#:                    "" => "1"
    tags.Name:                 "" => "tf-vpc"

$ terraform apply plan/                                                                                                                              
aws_vpc.tf-vpc: Creating...
  cidr_block:                "" => "10.0.0.0/16"
  default_network_acl_id:    "" => "<computed>"
  default_security_group_id: "" => "<computed>"
  enable_dns_hostnames:      "" => "<computed>"
  enable_dns_support:        "" => "<computed>"
  main_route_table_id:       "" => "<computed>"
  tags.#:                    "" => "1"
  tags.Name:                 "" => "tf-vpc"
aws_vpc.tf-vpc: 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」に保存されます。

cat terraform.tfstate                                                                                                                                 
{
    "version": 1,
    "serial": 1,
    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {
                "aws_vpc.tf-vpc": {
                    "type": "aws_vpc",
                    "primary": {
                        "id": "vpc-1839f77d",
                        "attributes": {
                            "cidr_block": "10.0.0.0/16",
                            "default_network_acl_id": "acl-c23befa7",
                            "default_security_group_id": "sg-8d992ae8",
                            "enable_dns_hostnames": "false",
                            "enable_dns_support": "true",
                            "id": "vpc-1839f77d",
                            "main_route_table_id": "rtb-2ed3054b",
                            "tags.#": "1",
                            "tags.Name": "tf-vpc"
                        }
                    }
                }
            }
        }
    ]
}

リソースを更新してみる


次に先ほどの設定にSubnetとInternetGatewayを追加します。

provider "aws" {
  access_key = <your access key>
  secret_key = <your secret key>
  region     = "ap-northeast-1"
}

resource "aws_vpc" "tf-vpc" {
  cidr_block = "10.0.0.0/16"
  tags {
    Name = "tf-vpc"
  }
}

resource "aws_internet_gateway" "tf-internet-gateway" {
  vpc_id ="${aws_vpc.tf-vpc.id}"
  tags {
    Name = "tf-internet-gateway"
  }
}

resource "aws_subnet" "tf-subnet1" {
  vpc_id = "${aws_vpc.tf-vpc.id}"
  cidr_block = "10.0.1.0/24"
  availability_zone = "ap-northeast-1a"
  tags {
    Name = "tf-subnet1"
  }
}

resource "aws_subnet" "tf-subnet2" {
  vpc_id = "${aws_vpc.tf-vpc.id}"
  cidr_block = "10.0.2.0/24"
  availability_zone = "ap-northeast-1c"
  tags {
    Name = "tf-subnet2"
  }
}

resource "aws_route_table" "tf-public-route-table" {
  vpc_id = "${aws_vpc.tf-vpc.id}"
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_internet_gateway.tf-internet-gateway.id}"
  }
}

resource "aws_route_table_association" "tf-subnet1-route-table-association" {
    subnet_id = "${aws_subnet.tf-subnet1.id}"
    route_table_id = "${aws_route_table.tf-public-route-table.id}"
}

resource "aws_route_table_association" "tf-subnet2-route-table-association" {
    subnet_id = "${aws_subnet.tf-subnet2.id}"
    route_table_id = "${aws_route_table.tf-public-route-table.id}"
}


先ほど同様「terraform plan」を実行します。

$ terraform plan 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_internet_gateway.tf-internet-gateway
    tags.#:    "0" => "1"
    tags.Name: "" => "tf-internet-gateway"
    vpc_id:    "" => "${aws_vpc.tf-vpc.id}"

+ aws_route_table.tf-public-route-table
    route.#:                                     "" => "1"
    route.~2206632460.cidr_block:                "" => "0.0.0.0/0"
    route.~2206632460.gateway_id:                "" => "${aws_internet_gateway.tf-internet-gateway.id}"
    route.~2206632460.instance_id:               "" => ""
    route.~2206632460.vpc_peering_connection_id: "" => ""
    vpc_id:                                      "" => "${aws_vpc.tf-vpc.id}"

+ aws_route_table_association.tf-subnet1-route-table-association
    route_table_id: "" => "${aws_route_table.tf-public-route-table.id}"
    subnet_id:      "" => "${aws_subnet.tf-subnet1.id}"

+ aws_route_table_association.tf-subnet2-route-table-association
    route_table_id: "" => "${aws_route_table.tf-public-route-table.id}"
    subnet_id:      "" => "${aws_subnet.tf-subnet2.id}"

+ aws_subnet.tf-subnet1
    availability_zone:       "" => "ap-northeast-1a"
    cidr_block:              "" => "10.0.1.0/24"
    map_public_ip_on_launch: "" => "<computed>"
    tags.#:                  "" => "1"
    tags.Name:               "" => "tf-subnet1"
    vpc_id:                  "" => "${aws_vpc.tf-vpc.id}"

+ aws_subnet.tf-subnet2
    availability_zone:       "" => "ap-northeast-1c"
    cidr_block:              "" => "10.0.2.0/24"
    map_public_ip_on_launch: "" => "<computed>"
    tags.#:                  "" => "1"
    tags.Name:               "" => "tf-subnet2"
    vpc_id:                  "" => "${aws_vpc.tf-vpc.id}"

+ aws_vpc.tf-vpc
    cidr_block:                "" => "10.0.0.0/16"
    default_network_acl_id:    "" => "<computed>"
    default_security_group_id: "" => "<computed>"
    enable_dns_hostnames:      "" => "<computed>"
    enable_dns_support:        "" => "<computed>"
    main_route_table_id:       "" => "<computed>"
    tags.#:                    "" => "1"
    tags.Name:                 "" => "tf-vpc"

$ terraform apply plan/                                                                                                                           
aws_vpc.tf-vpc: Creating...
  cidr_block:                "" => "10.0.0.0/16"
  default_network_acl_id:    "" => "<computed>"
  default_security_group_id: "" => "<computed>"
  enable_dns_hostnames:      "" => "<computed>"
  enable_dns_support:        "" => "<computed>"
  main_route_table_id:       "" => "<computed>"
  tags.#:                    "" => "1"
  tags.Name:                 "" => "tf-vpc"
aws_vpc.tf-vpc: Creation complete
aws_subnet.tf-subnet1: Creating...
  availability_zone:       "" => "ap-northeast-1a"
  cidr_block:              "" => "10.0.1.0/24"
  map_public_ip_on_launch: "" => "<computed>"
  tags.#:                  "" => "1"
  tags.Name:               "" => "tf-subnet1"
  vpc_id:                  "" => "vpc-d839f7bd"
aws_subnet.tf-subnet2: Creating...
  availability_zone:       "" => "ap-northeast-1c"
  cidr_block:              "" => "10.0.2.0/24"
  map_public_ip_on_launch: "" => "<computed>"
  tags.#:                  "" => "1"
  tags.Name:               "" => "tf-subnet2"
  vpc_id:                  "" => "vpc-d839f7bd"
aws_internet_gateway.tf-internet-gateway: Creating...
  tags.#:    "0" => "1"
  tags.Name: "" => "tf-internet-gateway"
  vpc_id:    "" => "vpc-d839f7bd"
aws_internet_gateway.tf-internet-gateway: Creation complete
aws_route_table.tf-public-route-table: Creating...
  route.#:                                    "" => "1"
  route.3291085789.cidr_block:                "" => "0.0.0.0/0"
  route.3291085789.gateway_id:                "" => "igw-4cf80d29"
  route.3291085789.instance_id:               "" => ""
  route.3291085789.vpc_peering_connection_id: "" => ""
  vpc_id:                                     "" => "vpc-d839f7bd"
aws_subnet.tf-subnet2: Creation complete
aws_route_table.tf-public-route-table: Creation complete
aws_route_table_association.tf-subnet2-route-table-association: Creating...
  route_table_id: "" => "rtb-fad3059f"
  subnet_id:      "" => "subnet-0530c75c"
aws_subnet.tf-subnet1: Creation complete
aws_route_table_association.tf-subnet1-route-table-association: Creating...
  route_table_id: "" => "rtb-fad3059f"
  subnet_id:      "" => "subnet-aa35e7dd"
aws_route_table_association.tf-subnet1-route-table-association: Creation complete
aws_route_table_association.tf-subnet2-route-table-association: Creation complete

Apply complete! Resources: 7 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 plan -destroy」コマンドを発行します。

$ terraform plan -destroy plan/                                                                                                                       
Refreshing Terraform state prior to plan...

aws_vpc.tf-vpc: Refreshing state... (ID: vpc-d839f7bd)
aws_subnet.tf-subnet2: Refreshing state... (ID: subnet-0530c75c)
aws_subnet.tf-subnet1: Refreshing state... (ID: subnet-aa35e7dd)
aws_internet_gateway.tf-internet-gateway: Refreshing state... (ID: igw-4cf80d29)
aws_route_table.tf-public-route-table: Refreshing state... (ID: rtb-fad3059f)
aws_route_table_association.tf-subnet2-route-table-association: Refreshing state... (ID: rtbassoc-9de538f8)
aws_route_table_association.tf-subnet1-route-table-association: Refreshing state... (ID: rtbassoc-9ce538f9)

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_internet_gateway.tf-internet-gateway

- aws_route_table.tf-public-route-table

- aws_route_table_association.tf-subnet1-route-table-association

- aws_route_table_association.tf-subnet2-route-table-association

- aws_subnet.tf-subnet1

- aws_subnet.tf-subnet2

- aws_vpc.tf-vpc


その後、「terraform destroy」コマンドでリソースを削除します。

$ terraform destroy plan/
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_vpc.tf-vpc: Refreshing state... (ID: vpc-d839f7bd)
aws_subnet.tf-subnet1: Refreshing state... (ID: subnet-aa35e7dd)
aws_subnet.tf-subnet2: Refreshing state... (ID: subnet-0530c75c)
aws_internet_gateway.tf-internet-gateway: Refreshing state... (ID: igw-4cf80d29)
aws_route_table.tf-public-route-table: Refreshing state... (ID: rtb-fad3059f)
aws_route_table_association.tf-subnet2-route-table-association: Refreshing state... (ID: rtbassoc-9de538f8)
aws_route_table_association.tf-subnet1-route-table-association: Refreshing state... (ID: rtbassoc-9ce538f9)
aws_route_table_association.tf-subnet2-route-table-association: Destroying...
aws_route_table_association.tf-subnet1-route-table-association: Destroying...
aws_route_table_association.tf-subnet1-route-table-association: Destruction complete
aws_subnet.tf-subnet1: Destroying...
aws_route_table_association.tf-subnet2-route-table-association: Destruction complete
aws_subnet.tf-subnet2: Destroying...
aws_route_table.tf-public-route-table: Destroying...
aws_subnet.tf-subnet1: Destruction complete
aws_subnet.tf-subnet2: Destruction complete
aws_route_table.tf-public-route-table: Destruction complete
aws_internet_gateway.tf-internet-gateway: Destroying...
aws_internet_gateway.tf-internet-gateway: Destruction complete
aws_vpc.tf-vpc: Destroying...
aws_vpc.tf-vpc: Destruction complete

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


作成したリソース情報は、「terraform show」コマンドで確認できます。

$ terraform show                                                                                                                                      
aws_internet_gateway.tf-internet-gateway:
  id = igw-4cf80d29
  vpc_id = vpc-d839f7bd
aws_route_table.tf-public-route-table:
  id = rtb-fad3059f
  route.# = 1
  route.3291085789.cidr_block = 0.0.0.0/0
  route.3291085789.gateway_id = igw-4cf80d29
  route.3291085789.instance_id = 
  route.3291085789.vpc_peering_connection_id = 
  vpc_id = vpc-d839f7bd
aws_route_table_association.tf-subnet1-route-table-association:
  id = rtbassoc-9ce538f9
  route_table_id = rtb-fad3059f
  subnet_id = subnet-aa35e7dd
aws_route_table_association.tf-subnet2-route-table-association:
  id = rtbassoc-9de538f8
  route_table_id = rtb-fad3059f
  subnet_id = subnet-0530c75c
aws_subnet.tf-subnet1:
  id = subnet-aa35e7dd
  availability_zone = ap-northeast-1a
  cidr_block = 10.0.1.0/24
  map_public_ip_on_launch = false
  tags.# = 1
  tags.Name = tf-subnet1
  vpc_id = vpc-d839f7bd
aws_subnet.tf-subnet2:
  id = subnet-0530c75c
  availability_zone = ap-northeast-1c
  cidr_block = 10.0.2.0/24
  map_public_ip_on_launch = false
  tags.# = 1
  tags.Name = tf-subnet2
  vpc_id = vpc-d839f7bd
aws_vpc.tf-vpc:
  id = vpc-d839f7bd
  cidr_block = 10.0.0.0/16
  default_network_acl_id = acl-913beff4
  default_security_group_id = sg-1e982b7b
  enable_dns_hostnames = false
  enable_dns_support = true
  main_route_table_id = rtb-f9d3059c
  tags.# = 1
  tags.Name = tf-vpc


また、リソース同士の関係を、「terraform graph」コマンドで確認できます。

terraform graph plan/
digraph {
   compound = true;
   subgraph {
     "0_aws_vpc.tf-vpc" [
       label="aws_vpc.tf-vpc"
       shape=box
     ];
     "0_aws_internet_gateway.tf-internet-gateway" [
       label="aws_internet_gateway.tf-internet-gateway"
       shape=box
     ];
     "0_aws_subnet.tf-subnet1" [
       label="aws_subnet.tf-subnet1"
       shape=box
     ];
     "0_aws_subnet.tf-subnet2" [
       label="aws_subnet.tf-subnet2"
       shape=box
     ];
     "0_aws_route_table.tf-public-route-table" [
       label="aws_route_table.tf-public-route-table"
       shape=box
     ];
     "0_aws_route_table_association.tf-subnet1-route-table-association" [
       label="aws_route_table_association.tf-subnet1-route-table-association"
       shape=box
     ];
     "0_aws_route_table_association.tf-subnet2-route-table-association" [
       label="aws_route_table_association.tf-subnet2-route-table-association"
       shape=box
     ];
   }

   "0_aws_vpc.tf-vpc" -> "0_provider.aws";
   "0_aws_internet_gateway.tf-internet-gateway" -> "0_provider.aws";
   "0_aws_internet_gateway.tf-internet-gateway" -> "0_aws_vpc.tf-vpc";
   "0_aws_subnet.tf-subnet1" -> "0_provider.aws";
   "0_aws_subnet.tf-subnet1" -> "0_aws_vpc.tf-vpc";
   "0_aws_subnet.tf-subnet2" -> "0_provider.aws";
   "0_aws_subnet.tf-subnet2" -> "0_aws_vpc.tf-vpc";
   "0_aws_route_table.tf-public-route-table" -> "0_provider.aws";
   "0_aws_route_table.tf-public-route-table" -> "0_aws_vpc.tf-vpc";
   "0_aws_route_table.tf-public-route-table" -> "0_aws_internet_gateway.tf-internet-gateway";
   "0_aws_route_table_association.tf-subnet1-route-table-association" -> "0_provider.aws";
   "0_aws_route_table_association.tf-subnet1-route-table-association" -> "0_aws_subnet.tf-subnet1";
   "0_aws_route_table_association.tf-subnet1-route-table-association" -> "0_aws_route_table.tf-public-route-table";
   "0_aws_route_table_association.tf-subnet2-route-table-association" -> "0_provider.aws";
   "0_aws_route_table_association.tf-subnet2-route-table-association" -> "0_aws_route_table.tf-public-route-table";
   "0_aws_route_table_association.tf-subnet2-route-table-association" -> "0_aws_subnet.tf-subnet2";

   subgraph {
   }

   subgraph {
     "0_provider.aws" [
       label="provider.aws"
       shape=diamond
     ];
   }

}


色々試してみようと思います。


今日はこんなところで。