Terraformを使ってAWSに検証用VPCを構築する

この記事は [Origami Advent Calendar](http://qiita.com/advent-calendar/2016/origami) の17日目の記事です。
昨日はStraight Outta Comptonを見ながら寝落ちしてしまいました。
ここ数日の記事の内容は、わりとやんちゃな感じ`(*1)`でしたが、この記事は平和な内容です。

`*1 ... 上司にSlackで通知しまくる、ギャングスタ・ラップ、ホットスポットWiFiを便利に使う、など`

# 概要

検証用にVPCを構築する機会が増えてきたので、Terraformを使って自動化を試みました。

# tltr

```:playground.tf
variable "access_key" {}
variable "secret_key" {}
variable "region" {
  default = "us-west-2"
}

provider "aws" {
    access_key = "${var.access_key}"
    secret_key = "${var.secret_key}"
    region = "${var.region}"
}

# VPC
resource "aws_vpc" "playground" {
  cidr_block = "10.3.0.0/16"
  instance_tenancy = "default"
  enable_dns_support = "true"
  enable_dns_hostnames = "true"
  tags {
    Name = "playground"  
  }
}

# EIP
resource "aws_eip" "nat" {
    vpc = true
}

# InternetGateway
resource "aws_internet_gateway" "igw" {
  vpc_id = "${aws_vpc.playground.id}"
}

# NatGateway
resource "aws_nat_gateway" "nat" {
  allocation_id = "${aws_eip.nat.id}"
  subnet_id = "${aws_subnet.public-a.id}"
}

# Subnet
resource "aws_subnet" "public-a" {
  vpc_id = "${aws_vpc.playground.id}"
  cidr_block = "10.3.0.0/24"
  availability_zone = "us-west-2a"
  tags {
    Name = "public-a"
  }
}

resource "aws_subnet" "public-c" {
  vpc_id = "${aws_vpc.playground.id}"
  cidr_block = "10.3.2.0/24"
  availability_zone = "us-west-2c"
  tags {
    Name = "public-c"
  }
}

resource "aws_subnet" "private-a" {
  vpc_id = "${aws_vpc.playground.id}"
  cidr_block = "10.3.4.0/24"
  availability_zone = "us-west-2a"
  tags {
    Name = "private-a"
  }
}

resource "aws_subnet" "private-c" {
  vpc_id = "${aws_vpc.playground.id}"
  cidr_block = "10.3.6.0/24"
  availability_zone = "us-west-2c"
  tags {
    Name = "private-c"
  }
}

# RouteTable
resource "aws_route_table" "public" {
  vpc_id = "${aws_vpc.playground.id}"
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_internet_gateway.igw.id}"
  }
  tags {
    Name = "public"
  }
}

resource "aws_route_table" "private" {
  vpc_id = "${aws_vpc.playground.id}"
  route {
    cidr_block = "0.0.0.0/0"
    nat_gateway_id = "${aws_nat_gateway.nat.id}"
  }
  tags {
    Name = "private"
  }
}

# SubnetRouteTableAssociation
resource "aws_route_table_association" "public-a" {
    subnet_id = "${aws_subnet.public-a.id}"
    route_table_id = "${aws_route_table.public.id}"
}

resource "aws_route_table_association" "public-c" {
    subnet_id = "${aws_subnet.public-c.id}"
    route_table_id = "${aws_route_table.public.id}"
}

resource "aws_route_table_association" "private-a" {
    subnet_id = "${aws_subnet.private-a.id}"
    route_table_id = "${aws_route_table.private.id}"
}

resource "aws_route_table_association" "private-c" {
    subnet_id = "${aws_subnet.private-c.id}"
    route_table_id = "${aws_route_table.private.id}"
}
```

# 補足

## VPCのベストプラクティス

VPCを作成する際には、色々検討すべきポイントがあるかと思いますが、今回は以下の2点を盛り込みました。

- サブネットをプライベートとパブリックで分割する
- Multi-AZ

## Terraformによる抽象化

上記の例では、VPCを作成するリージョン、CIDRなどを変更する場合は.tfファイルを書き換える必要があります。
私はTerraformを今回初めて使用したので、どこまで抽象化すべきなのか、現段階で迷いがあります。

## プロダクションで使用すべきか?

Terraformは非常に便利ですが、プロダクションでの利用にあたってはワークフローを含め色々整備が必要ではないかと感じました。`(個人の見解です)`

- Terraform以外で環境が変更されていないことの保証、または、変更された場合はどうするか?
  - VPCに変更が必要になる度に全部作り直している人は流石にいないはず ... 

- 不慮のエラーによりapplyが失敗した時の対応

# まとめ

便利になりました。