Tarraformを使ってAWSにWebサーバを構築 #4 ~ネットワークを整える(VPC, サブネット, ルーティングテーブル,インターネットゲートウェイ)~

## 目的
EC2にNginxがインストールされた状態を作り出し、ブラウザからデフォルトページが確認できることをゴールとする。
インフラ構築はTerraformでコード化することで再現性、再利用性、速度などが手作業に比べると高い。
[GitHubリンク](https://github.com/keitasato/terraform-nginx)

### 手順
1. [TerraformからAWSリソースを操作できるように設定する](https://qiita.com/kekkepy/items/4185a621e5d3cc75016b)
1. [Terraformをインストールする](https://qiita.com/kekkepy/items/1b3f4f14bbc2d2dc2c9b)
1. [TerraformでEC2サーバを立ち上げてみる](https://qiita.com/kekkepy/items/8b84fc0c39313267a078)
1. [ネットワークを整える(VPC, サブネット, ルーティングテーブル,インターネットゲートウェイ)](https://qiita.com/kekkepy/items/c941c00536af57bae163)
1. [セキュリティグループ(ファイアウォール)を設定する](https://qiita.com/kekkepy/items/47dcda4d9a7a2064382f)
1. [Webサーバ用EC2を立ち上げる](https://qiita.com/kekkepy/items/81bfa5d542c9160d430b)
1. [Webサーバが立ち上がる際にWebサーバソフトをインストールするように設定する](https://qiita.com/kekkepy/items/209f7ddb29fb5af65a6e)

#### 今回の到達点
EC2サーバのネットワークを整える(VPC, サブネット, ルーティングテーブル,インターネットゲートウェイ)

#### Webサーバを立てる準備
- ネットワークを構築する　 **←今回はここ！**
- ネットワークに許可する通信を設定する
- EC2をプライベートネットワークに所属させて外部からアクセスできるようにする
- EC2にWebサーバソフト(今回はNginx)をインストールする

##### Step1. 定数ファイルの作成
AWSリソースのタグなどに設定する名称など、様々な場所で共通的に使う変数を定義しておくためのファイルを作成する。このファイル名は「terraform.tfvars」である必要がある。
C:\Users\[ユーザ名]\Documents\MyProject\terraform\terraform.tfvars
```terraform:terraform.tfvars
project     = "kekkepy"
environment = "dev"
```

##### Step2. main.tfの改修
main.tfはあくまでも設定ファイルとし、リソースの作成はそれぞれ適当なtfファイルで行う。
tfファイルは同階層にあるファイルはいくら分割しても全て実行されるので、管理しやすい単位に分割する。
terraform自体の設定とtfファイル内で使用する変数を宣言するように変更する。
以下のようにmain.tfを編集
```terraform:main.tf
# Config
terraform {
  required_version = ">=0.13"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }
}

# Provider
provider "aws" {
  profile = "terraform"
  region  = "ap-northeast-1"
}

variable "project" {
  type = string
}

variable "environment" {
  type = string
}
```

##### Step.3 VPCの設定
Webアプリケーションを構築するVPCを設定する。この中にサブネットを構築していき、ルーティングなどを設定することでネットワークを形成する。
C:\Users\[ユーザ名]\Documents\MyProject\terraform\network.tf
```terraform:network.tf
# VPC
resource "aws_vpc" "vpc" {
  cidr_block                       = "192.168.0.0/24"
  instance_tenancy                 = "default"
  enable_dns_support               = true
  enable_dns_hostnames             = true
  assign_generated_ipv6_cidr_block = false

  tags = {
    Name    = "${var.project}-${var.environment}-vpc"
    Project = "${var.project}"
    Env     = "${var.environment}"
  }
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1221536/51116210-169a-b010-ecc1-2d1b9949ef38.png)


##### Step.4 サブネットの設定
今回はパブリックなサブネットとプライベートなサブネットの２つを作成する。
もちろんEC2は外からのアクセスを可能としたいので、パブリックサブネットに配置する。
ではプライベートサブネットには何を配置するかというと、何もしない。
例えばDBを使うようなWebアプリケーションの場合は、そのDBをプライベートサブネットに配置したりするが、今回はあくまでもEC2の表示を確認するだけなので特に何も配置しない。
network.tfに以下を追記。
```terraform:network.tf
resource "aws_subnet" "public-subnet" {
  vpc_id                  = aws_vpc.vpc.id
  availability_zone       = "ap-notrheast-1a"
  cidr_block              = "192.168.1.0/24"
  map_public_ip_on_launch = true

  tags = {
    Name    = "${var.project}-${var.environment}-public-subnet"
    Project = "${var.project}"
    Env     = "${var.environment}"
    Type    = "public"
  }
}

resource "aws_subnet" "private-subnet" {
  vpc_id                  = aws_vpc.vpc.id
  availability_zone       = "ap-notrheast-1a"
  cidr_block              = "192.168.2.0/24"
  map_public_ip_on_launch = false

  tags = {
    Name    = "${var.project}-${var.environment}-private-subnet"
    Project = "${var.project}"
    Env     = "${var.environment}"
    Type    = "private"
  }
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1221536/de1a37a0-1314-e626-11a2-dd3b68f7b6b5.png)


##### Step.5 ルーティングテーブルの設定
ルーティングテーブルを作成しサブネットにアタッチしていく。
network.tfに以下を追記。
```terraform:network.tf
resource "aws_route_table" "public_route_table" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name    = "${var.project}-${var.environment}-public-route-table"
    Project = "${var.project}"
    Env     = "${var.environment}"
    Type    = "public"
  }
}

resource "aws_route_table_association" "public-route_table-association" {
  route_table_id = aws_route_table.public_route_table.id
  subnet_id      = aws_subnet.public-subnet.id
}

resource "aws_route_table" "private_route_table" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name    = "${var.project}-${var.environment}-private-route-table"
    Project = "${var.project}"
    Env     = "${var.environment}"
    Type    = "private"
  }
}

resource "aws_route_table_association" "private-route_table-association" {
  route_table_id = aws_route_table.private_route_table.id
  subnet_id      = aws_subnet.private-subnet.id
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1221536/5d39c3c3-1ca5-eb62-80eb-3e368fdd6cad.png)


##### Step.6 インターネットゲートウェイの設定
今回構築したネットワークがインターネットと通信できるように、インターネットゲートウェイと接続する。
network.tfに以下を追記。
```terraform:network.tf
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name    = "${var.project}-${var.environment}-igw"
    Project = "${var.project}"
    Env     = "${var.environment}"
  }
}

resource "aws_route" "public_route_table_igw_route" {
  route_table_id         = aws_route_table.public_route_table.id
  gateway_id             = aws_internet_gateway.igw.id
  destination_cidr_block = "0.0.0.0/0"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1221536/15db2f96-d245-c5bb-861d-cde8c71485f6.png)


#### ここで一区切り
ネットワーク構築は完了。
ただインバウンド、アウトバウンド共にどんな通信を許可するかを設定していない。
次回この部分の設定を行うことで、このネットワークとインターネットでの通信を可能とし、Webサーバとしてリクエストを許可したり、サーバにSSHでアクセスできるように設定する。

最終的なnetwork.tfは以下の通り
```terraform:network.tf
# VPC
resource "aws_vpc" "vpc" {
  cidr_block                       = "192.168.0.0/20"
  instance_tenancy                 = "default"
  enable_dns_support               = true
  enable_dns_hostnames             = true
  assign_generated_ipv6_cidr_block = false

  tags = {
    Name    = "${var.project}-${var.environment}-vpc"
    Project = var.project
    Env     = var.environment
  }
}

# Subnet
resource "aws_subnet" "public-subnet" {
  vpc_id                  = aws_vpc.vpc.id
  availability_zone       = "ap-northeast-1a"
  cidr_block              = "192.168.1.0/24"
  map_public_ip_on_launch = true

  tags = {
    Name    = "${var.project}-${var.environment}-public-subnet"
    Project = "${var.project}"
    Env     = "${var.environment}"
    Type    = "public"
  }
}

resource "aws_subnet" "private-subnet" {
  vpc_id                  = aws_vpc.vpc.id
  availability_zone       = "ap-northeast-1a"
  cidr_block              = "192.168.2.0/24"
  map_public_ip_on_launch = false

  tags = {
    Name    = "${var.project}-${var.environment}-private-subnet"
    Project = "${var.project}"
    Env     = "${var.environment}"
    Type    = "private"
  }
}

# Route table
resource "aws_route_table" "public_route_table" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name    = "${var.project}-${var.environment}-public-route-table"
    Project = "${var.project}"
    Env     = "${var.environment}"
    Type    = "public"
  }
}

resource "aws_route_table_association" "public-route_table-association" {
  route_table_id = aws_route_table.public_route_table.id
  subnet_id      = aws_subnet.public-subnet.id
}

resource "aws_route_table" "private_route_table" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name    = "${var.project}-${var.environment}-private-route-table"
    Project = "${var.project}"
    Env     = "${var.environment}"
    Type    = "private"
  }
}

resource "aws_route_table_association" "private-route_table-association" {
  route_table_id = aws_route_table.private_route_table.id
  subnet_id      = aws_subnet.private-subnet.id
}

# Internet Gateway
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name    = "${var.project}-${var.environment}-igw"
    Project = "${var.project}"
    Env     = "${var.environment}"
  }
}

resource "aws_route" "public_route_table_igw_route" {
  route_table_id         = aws_route_table.public_route_table.id
  gateway_id             = aws_internet_gateway.igw.id
  destination_cidr_block = "0.0.0.0/0"
}
```