terraformでVPC, サブネットを作成する

本日から数記事に分けてterraformを使ってAWSでインフラ構築していきます。
今回はVPCとサブネットを作成します。

# 環境
- macOS Mojave 10.14.5
- MacBook Pro, 13-inch, Early 2015
- terraform v0.12.0
- direnv 2.20.1

# 目標成果物(本記事ではVPCとsubnetを作成)
<img width="541" alt="スクリーンショット 2019-07-15 20.00.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324032/a6a160b0-bf3b-eaba-63f9-7367dddae2aa.png">

# github格納先
成果物のコードは下記githubのリポジトリに格納していきます。
https://github.com/sasshi-i/terraform_ec2_rds

# ディレクトリ構成
現状のディレクトリ構成は下記の通りです。

```
├─ envs
│    ├─ prod
│    │   ├─ backend.tf
│    │   ├─ main.tf
│    │   └─ variables.tf
│    │
│    └─ staging
│        ├─ backend.tf
│        ├─ main.tf
│        └─ variables.tf
├─ modules
│    ├─ provider
│    │   └─ main.tf
│    └─ vpc
│        └─ main.tf
├─ .envrc
├─ .gigtgnore
└─READNE.md
```

# 作成したプログラム
作成したプログラムは下記の通りです。
詳細は後述します。

```/modules/provider/main.tf
provider "aws" {
  region  = "us-east-1"
  version = "~> 2.16"
}
```

```/modules/vpc/main.tf
variable "stage" {}

resource "aws_vpc" "qiita_vpc" {
  cidr_block                       = "10.8.0.0/16"
  enable_dns_hostnames             = true
  enable_dns_support               = true
  instance_tenancy                 = "default"
  assign_generated_ipv6_cidr_block = true

  tags = {
    Name = "qiita_ec2_rds"
  }
}

resource "aws_subnet" "qiita_subnet_1a" {
  count             = 2
  vpc_id            = aws_vpc.qiita_vpc.id
  cidr_block        = cidrsubnet(aws_vpc.qiita_vpc.cidr_block, 8, count.index)
  availability_zone = "us-east-1a"

  tags = {
    Name = "qiita-${var.stage}-us-east-1a"
  }
}

resource "aws_subnet" "qiita_subnet_1b" {
  count             = 2
  vpc_id            = aws_vpc.qiita_vpc.id
  cidr_block        = cidrsubnet(aws_vpc.qiita_vpc.cidr_block, 8, count.index+2)
  availability_zone = "us-east-1b"

  tags = {
    Name = "qiita-${var.stage}-us-east-1b"
  }
}
```

```/envs/staging/backend.tf
terraform {
  backend "s3" {
    bucket = "ec2-rds-deploy"
    key    = "terraform/staging.tfstate"
    region = "us-east-1"
  }
}
```

```/envs/staging/main.tf
module "provider" {
  source = "../../modules/provider"
}

module "vpc" {
  source = "../../modules/vpc"
  stage  = var.stage
}
```

```/envs/staging/variables.tf
variable "stage" {
  default = "staging"
}
```

# 実行手順

- AWSコンソールにて`ec2-rds-deploy`のS3バケットを`us-east-1`リージョンに作成する
->tfstate管理用のS3バケット。terraformで管理しているインフラの状態を管理しているファイルです。ローカルで管理しないことで、チームメンバー全員が最新のtfstateを参照してインフラ開発をすることができます。

- ワーキングディレクトリの初期化

```
cd /envs/staging
terraform init
```

- 実行計画を確認

```
terraform plan
```

何が作成されるか、または変更、削除されるかなどを確認することができます。

- インフラ構築を実行

```
terraform apply
```

実行計画に問題なければ、上記コマンドでインフラを構築します。

あとは、下記コマンドでterraformで作成したインフラを削除できます。

```
terraform destroy
```


# 各種プログラムの解説
ここからは各ファイルの役割とプログラムの説明を記載します。

### /modules/provider/main.tf
AWSとかGCPとかプロバイダーを定義します。
またここで指定したプロバイダーのバージョンに従って、`terraform init`した時にプラグインがインストールされるため、バージョンを明記しておいた方が良いです。

[プログラムでの定義項目概要]

- region: AWSのリージョン
- version: AWS プロバイダーのバージョン

### /modules/vpc/main.tf
VPCやサブネットの設定を定義します。

[プログラムでの定義項目概要]
aws_vpc  

- cidr_block: VPCに割り振るIPv4 アドレスの範囲
- enable_dns_hostnames: パブリック IP アドレスを持つインスタンスが、対応するパブリック DNS ホスト名を取得するかどうか。(デフォルトはfalse)
- enable_dns_support: DNS 解決をサポートするかどうか。

- instance_tenancy: AWSのハードウェアを占有して使用したいかどうか。defaultだと他のユーザーと共有するハードウェア上で起動します。

aws_subnet

- count: こちらに記載した値の個数だけ同じ設定のサブネットが作成されます
- cidrsubnet: terraformで用意されている関数。3つの引数を渡すとIP範囲をサブネット分割した場合のIP範囲を返してくれます｡こちらについては、下記の記事がわかりやすいです。

https://dev.classmethod.jp/cloud/aws/terraform-ipv6-subnet/

### /envs/*/backend.tf

tfstateファイルの格納先を定義します。

[プログラムでの定義項目概要]

- bucket: 格納先バケット名
- key: ディレクトリ定義。ここに指定した通りにtfstateファイルがS3に格納されます
- region: AWSのリージョン

### /envs/*/variables.tf
変数を定義します。

### /envs/*/main.tf
参照するmoduleのパスやmodule内で使用する変数を定義します。
main.tfに記載された資源がAWSに作成されます。

以上！

次回はルートテーブル、セキュリティグループあたりを作っていきたいと思います。

# 関連記事
tfenvを用いたterraformのインストール方法
https://qiita.com/sasshi_i/items/b5117d51fed800fa6b09

direnvを用いてterraformで複数のAWSアカウントを使い分ける方法
https://qiita.com/sasshi_i/items/609044aa106cdcb43a89