Terraformによるスケーラブルウェブサイト構築

# はじめに
* （Terraformに慣れるために）AWS CLIで構築した[スケーラブルなウェブサイト環境](https://qiita.com/kokichi8/items/fedb84896a286b70cc23)を手順と資料を合わせてアウトプット資料としてまとめます。
* 個人的に気づいたことも付け加えていこうと思います。
# 構成図
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f333530313630352f39386333393837622d663933322d396530652d6235626.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3501605/72272c07-d8f2-17b5-2a67-79d61cac1520.png)


# 手順
```ruby:main.tf
# ---------------------------
# プロバイダ設定
# ---------------------------
# AWS
provider "aws" {
  region     = "ap-northeast-1"
}

# 自分のパブリックIPを取得する
provider "http" {}
```

## VPCの作成
```ruby:vpc.tf
#---
#VPCの作成
#---
resource "aws_vpc" "test" {
  cidr_block       = "10.0.0.0/16"
  enable_dns_hostnames = "true"

  tags = {
    Name = "test"
  }
}

#---
#サブネットの作成
#---
resource "aws_subnet" "test-public-1a" {
  vpc_id     = aws_vpc.test.id
  cidr_block = "10.0.0.0/24"
  availability_zone = "${var.az_a}"

  tags = {
    Name = "test-public-1"
  }
}

resource "aws_subnet" "test-public-1c" {
  vpc_id     = aws_vpc.test.id
  cidr_block = "10.0.1.0/24"
  availability_zone = "${var.az_c}"

  tags = {
    Name = "test-public-2"
  }
}

resource "aws_subnet" "test-private-1a" {
  vpc_id     = aws_vpc.test.id
  cidr_block = "10.0.2.0/24"
  availability_zone = "${var.az_a}"

  tags = {
    Name = "test-private-1"
  }
}

resource "aws_subnet" "test-private-1c" {
  vpc_id     = aws_vpc.test.id
  cidr_block = "10.0.3.0/24"
  availability_zone = "${var.az_c}"

  tags = {
    Name = "test-private-2"
  }
}

#---
#IGWの作成
#---
resource "aws_internet_gateway" "test-igw" {
  vpc_id = aws_vpc.test.id

  tags = {
    Name = "test-igw"
  }
}

#---
#ルートテーブルの作成
#---
resource "aws_route_table" "test-public" {
  vpc_id = aws_vpc.test.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.test-igw.id
  }
  tags = {
    Name = "test-public"
  }
}

#---
#ルートテーブルの関連付け
#---
resource "aws_route_table_association" "test-public-1a" {
  subnet_id      = aws_subnet.test-public-1a.id
  route_table_id = aws_route_table.test-public.id
}

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

#---
#セキュリティグループの作成
#---
#EC2
resource "aws_security_group" "test-web" {
  name        = "test-web"
  description = "test-web sg"
  vpc_id      = aws_vpc.test.id

  ingress {
    description      = "ssh"
    from_port        = 22
    to_port          = 22
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
  }

  ingress {
    description      = "http"
    from_port        = 80
    to_port          = 80
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
  }

  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
  }

  tags = {
    Name = "test-web"
  }
}

#RDS
resource "aws_security_group" "test-rds" {
  name        = "test-rds"
  description = "test-rds-sg"
  vpc_id      = aws_vpc.test.id
  ingress {
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    cidr_blocks =["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "test-rds"
  }
}

#ELB
resource "aws_security_group" "test-elb" {
  name        = "test-elb"
  description = "test-elb-sg"
  vpc_id      = aws_vpc.test.id
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "test-elb"
  }
}
```
## EC2の作成
```ruby:ec2.tf
# Amazon Linux 2 の最新AMIを取得する
data "aws_ssm_parameter" "amzn2_latest_ami" {
  name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}

#キーペアの作成
variable "key_name" {
  default = "test-keypair"
}

# 秘密鍵のアルゴリズム設定
resource "tls_private_key" "private_key" {
  algorithm = "RSA"
  rsa_bits  = 2048
}

# PCにキーペアを作成
locals {
  public_key_file  = "C:\\terraform_handson\\${var.key_name}.id_rsa.pub"
  private_key_file = "C:\\terraform_handson\\${var.key_name}.id_rsa"
}

resource "local_file" "private_key_pem" {
  filename = "${local.private_key_file}"
  content  = "${tls_private_key.private_key.private_key_pem}"
}

# 上記で作成した公開鍵をAWSのKey pairにインポート
resource "aws_key_pair" "keypair" {
  key_name   = "${var.key_name}"
  public_key = "${tls_private_key.private_key.public_key_openssh}"
}

#EC2の作成
resource "aws_instance" "test-ec2" {
  ami                         = data.aws_ssm_parameter.amzn2_latest_ami.value
  instance_type               = "t2.micro"
  availability_zone           = "${var.az_a}"
  vpc_security_group_ids      = [aws_security_group.test-web.id]
  subnet_id                   = aws_subnet.test-public-1a.id
  associate_public_ip_address = "true"
  key_name                    = "${var.key_name}"
  user_data = file("userdata.sh")
  tags = {
    Name = "test-web-instance-1a"
  }

}

```
## RDSの作成
```ruby:rds.tf
#---
#RDSサブネットグループの作成
#---
resource "aws_db_subnet_group" "test-db-subnet" {
  name       = "test-db-subnet"
  subnet_ids = [aws_subnet.test-private-1a.id, aws_subnet.test-private-1c.id]

  tags = {
    Name = "test-db-subnet"
  }
}

#---
#インスタンスの作成
#---
resource "aws_db_instance" "test-db" {
  allocated_storage    = 20
  db_name              = "test-db"
  engine               = "mysql"
  engine_version       = "8.0.28"
  instance_class       = "db.t3.micro"
  username             = "test"
  password             = "password"
  backup_retention_period = 0
  db_subnet_group_name = "test-db-subnet"

  skip_final_snapshot  = true
  multi_az = true

  tags = {
          Name = "test-rds"
  }
}
```
## ELBの作成
```ruby:elb.tf
#---
#ALBの作成
#---
resource "aws_lb" "test" {
  name               = "test-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.lb_sg.id]
  subnets            = [aws_subnet.test-public-1a.id,aws_subnet.test-public-1c.id]
  ip_address_type    = "ipv4"

  enable_deletion_protection = true

  tags = {
  	name = "test-alb"
  }
}

#---
#ターゲットグループの作成
#---
resource "aws_lb_target_group" "test-target" {
  name     		= "test-target"
  target_type	= "instance"
  port     		= 80
  protocol 		= "HTTP"
  vpc_id   		= aws_vpc.test.id
  
  tags			= {
  	name		= "test-elb"
	}

  health_check {
  	protocol	= "HTTP"
  	path		= "/"
  	}
}

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

#ターゲットグループにインスタンスを登録
"##1台目
resource "aws_lb_target_group_attachment" "test-target-1" {
  target_group_arn = aws_lb_target_group.test-target.arn
  target_id        = aws_instance.test.id
  port             = 80
}

##2台目
resource "aws_lb_target_group_attachment" "test-target-2" {
  target_group_arn = aws_lb_target_group.test-target.arn
  target_id        = aws_instance.test.id
  port             = 80
}

#---
#リスナー設定
#---
resource "aws_lb_listener" "test-listnet" {
  load_balancer_arn = aws_lb.test.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.test-target.arn
  }
}
```
## AMIの作成
```ruby:ami.tf
#---
#AMIの作成
#---
resource "aws_ami_from_instance" "test-ami" {
  name               = "test-ec2-ami"
  source_instance_id = "i-xxxxxxxx"
}
``` 
作成したAMIをもとに、EC2を作成します。  

# Terraformレジストリ
## VPC
* [aws_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc)
* [aws_subnet](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet)
* [aws_internet_gateway](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway)
* [aws_route_table](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table)
* [aws_route_table_association](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association)
* [aws_security_group](https://registry.terraform.io/providers/ha作成)
* [aws_key_pair](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/key_pair)
* [aws_instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance)
## RDS
* [aws_db_subnet_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_subnet_group)
* [aws_db_instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/db_instance)
## ELB
* [aws_lb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb)
## AMI
* [aws_ami](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ami)

# 補足
複数台のEC2を構築したいとき、異なるAZ間に配置したいときの
* [Terraformで複数台のEC2インスタンスを構築する場合のTIPS](https://dev.classmethod.jp/articles/tips-for-creating-multiple-aws_instance-resources/)