LoginSignup
21

More than 3 years have passed since last update.

TerraformでELBとEC2とRDSのよくありそうなWebパターンを作ってみる。

Last updated at Posted at 2020-02-02

よくありそうなこういうアーキテクチャをTerraformで練習がてら作ってみました。
変数もモジュールも考慮せず書いています。
(ALBにDNS名でアクセスするとラウンドロビンアクセスされること、
EC2からRDSに接続できることは確認していますが、セキュリティ上穴があるかもしれません。)

プレゼンテーション1.jpg

ディレクトリ構造

work/
├── alb.tf
├── ec2.tf
├── rds.tf
└── vpc.tf

Terraformの実行環境は以下の通り

$ terraform --version
Terraform v0.12.16
+ provider.aws v2.47.0

vpc.tf

##########################################################
///VPCの定義
##########################################################
resource "aws_vpc" "example" {
    cidr_block = "10.0.0.0/16"
    instance_tenancy = "default" #ハードウェア占有インスタンスを立てるかどうか
    enable_dns_hostnames = true
    enable_dns_support   = true
}
##########################################################
///パブリックサブネットの定義(マルチAZ),ALBを配置する
##########################################################
resource "aws_subnet" "public_a" {
    vpc_id                  = aws_vpc.example.id
    cidr_block              = "10.0.1.0/24"
    map_public_ip_on_launch = true   #サブネットで起動したインスタンスにパブリックIPを許可する
    availability_zone       = "ap-northeast-1a"
}

resource "aws_subnet" "public_c" {
    vpc_id                  = aws_vpc.example.id
    cidr_block              = "10.0.2.0/24"
    map_public_ip_on_launch = true
    availability_zone       = "ap-northeast-1c"
}

##########################################################
///パブリックサブネットの定義(マルチAZ),EC2(webサーバを配置する)
##########################################################
resource "aws_subnet" "public_a_web" {
    vpc_id                  = aws_vpc.example.id
    cidr_block              = "10.0.3.0/24"
    map_public_ip_on_launch = true
    availability_zone       = "ap-northeast-1a"
}

resource "aws_subnet" "public_c_web" {
    vpc_id                  = aws_vpc.example.id
    cidr_block              = "10.0.4.0/24"
    map_public_ip_on_launch = true
    availability_zone       = "ap-northeast-1c"
}
##########################################################
///インターネットゲートウェイの定義
##########################################################
resource "aws_internet_gateway" "example" {
    vpc_id                  = aws_vpc.example.id
}
##########################################################
///パブリックルートテーブルの定義
##########################################################
resource "aws_route_table" "public" {
    vpc_id = aws_vpc.example.id
}
##########################################################
///パブリックルートの定義(IGWに接続する)
##########################################################
resource "aws_route" "public" {
    route_table_id = aws_route_table.public.id
    gateway_id     = aws_internet_gateway.example.id
    destination_cidr_block = "0.0.0.0/0" 
}
##########################################################
///パブリックルートテーブルと関連付け
##########################################################
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" "public_a_web" {
    subnet_id      = aws_subnet.public_a_web.id
    route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "public_c_web" {
    subnet_id      = aws_subnet.public_c_web.id
    route_table_id = aws_route_table.public.id
}
##########################################################
///プライベートサブネットの定義(マルチAZ),RDSを配置する
##########################################################
resource "aws_subnet" "private_a" {
    vpc_id                  = aws_vpc.example.id
    cidr_block              = "10.0.5.0/24"
    map_public_ip_on_launch = false   #サブネットで起動したインスタンスにパブリックIPを許可する
    availability_zone       = "ap-northeast-1a"
}

resource "aws_subnet" "private_c" {
    vpc_id                  = aws_vpc.example.id
    cidr_block              = "10.0.6.0/24"
    map_public_ip_on_launch = false
    availability_zone       = "ap-northeast-1c"
}

ec2.tf

##########################################################
///EC2
##########################################################

///publicサブネットaに配置

resource "aws_instance" "a" {
  ami                    ="ami-0c3fd0f5d33134a76"
  vpc_security_group_ids =[aws_security_group.for_webserver_ec2.id]
  instance_type          ="t2.micro"
  subnet_id              = aws_subnet.public_a_web.id
  user_data = <<EOF
  #!/bin/bash
  yum install -y httpd
  yum install -y mysql
  systemctl start httpd
  systemctl enable httpd
  usermod -a -G apache ec2-user
  chown -R ec2-user:apache /var/www
  chmod 2775 /var/www
  find /var/www -type d -exec chmod 2775 {} \;
  find /var/www -type f -exec chmod 0664 {} \;
  echo `hostname` > /var/www/html/index.html
  EOF
}

///publicサブネットcに配置

resource "aws_instance" "c" {
  ami                    ="ami-0c3fd0f5d33134a76"
  vpc_security_group_ids =[aws_security_group.for_webserver_ec2.id]
  instance_type          ="t2.micro"
  subnet_id              = aws_subnet.public_c_web.id
  user_data = <<EOF
  #!/bin/bash
  yum update -y
  yum install -y httpd
  yum install -y mysql
  systemctl start httpd
  systemctl enable httpd
  usermod -a -G apache ec2-user
  chown -R ec2-user:apache /var/www
  chmod 2775 /var/www
  find /var/www -type d -exec chmod 2775 {} \;
  find /var/www -type f -exec chmod 0664 {} \;
  echo `hostname` > /var/www/html/index.html
  EOF
}
##########################################################
///EC2用のSG
##########################################################

resource "aws_security_group" "for_webserver_ec2" {
    name ="for-ec2"
    vpc_id= aws_vpc.example.id
    ingress{
        from_port = 80
        to_port   = 80
        protocol  = "tcp"
        security_groups =[aws_security_group.alb.id]
    }
   egress{
       from_port  = 0
       to_port    = 0
       protocol   = "-1"
       cidr_blocks=["0.0.0.0/0"]
   }
}

alb.tf

##########################################################
///ALBの定義
##########################################################
resource "aws_lb" "for_webserver" {
  name               = "webserver-alb"
  internal           = false             #falseを指定するとインターネット向け,trueを指定すると内部向け
  load_balancer_type = "application"

  security_groups    = [
    aws_security_group.alb.id
  ]

  subnets            = [
      aws_subnet.public_a.id,
      aws_subnet.public_c.id,
  ]
}
##########################################################
///ALBに付与するセキュリティグループの定義
##########################################################

resource "aws_security_group" "alb" {
    name ="alb"
    vpc_id= aws_vpc.example.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"]
   }
}
##########################################################
///ALBのリスナーの定義
##########################################################

resource "aws_lb_listener" "for_webserver" {
  load_balancer_arn = aws_lb.for_webserver.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.for_webserver.arn
  }

}

///リスナールールの定義

resource "aws_lb_listener_rule" "forward" {
  listener_arn = aws_lb_listener.for_webserver.arn
  priority     = 99

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.for_webserver.arn
  }

  condition {
      path_pattern{
        values = ["/*"]
      }
  }
}


##########################################################
///ALBのターゲットグループの定義
##########################################################
resource "aws_lb_target_group" "for_webserver" {
  name        = "for-webserver-lb-tg"
  port        = 80
  protocol    = "HTTP"
  vpc_id      = aws_vpc.example.id

  health_check {
        path        = "/index.html"
  }
}

///ターゲットグループをインスタンスに紐づける

resource "aws_lb_target_group_attachment" "for_webserver_a" {
  target_group_arn = aws_lb_target_group.for_webserver.arn
  target_id        = aws_instance.a.id
  port             = 80
}

resource "aws_lb_target_group_attachment" "for_webserver_c" {
  target_group_arn = aws_lb_target_group.for_webserver.arn
  target_id        = aws_instance.c.id
  port             = 80
}

rds.tf

##########################################################
///RDSの定義
##########################################################
resource "aws_db_instance" "default" {
  allocated_storage      = 20
  storage_type           = "gp2"
  engine                 = "mysql"
  engine_version         = "5.7"
  instance_class         = "db.t2.micro"
  name                   = "mydb"
  username               = "foo"
  password               = "foobarbaz"
  parameter_group_name   = "default.mysql5.7"
  multi_az               = true
  db_subnet_group_name   = aws_db_subnet_group.dbsubnet.name
  skip_final_snapshot    = true
  vpc_security_group_ids = [aws_security_group.for_rds.id]
}
##########################################################
///DBサブネットグループの定義
##########################################################
resource "aws_db_subnet_group" "dbsubnet" {
  name       = "main"
  subnet_ids = [aws_subnet.private_a.id, aws_subnet.private_c.id]

  tags = {
    Name = "My DB subnet group"
  }
}
##########################################################
///RDS用のSG
##########################################################

resource "aws_security_group" "for_rds" {
    name ="for-rds"
    vpc_id= aws_vpc.example.id
    ingress{
        from_port = 3306
        to_port   = 3306
        protocol  = "tcp"
        cidr_blocks = [aws_vpc.example.cidr_block]
    }
   egress{
       from_port  = 0
       to_port    = 0
       protocol   = "-1"
       cidr_blocks = ["0.0.0.0/0"]
   }
}

改善点

変数化・モジュール化
AMI作成

ALBをパブリックサブネット、EC2をプライベートサブネットに配置するようにする
→作成しようとしたらunhealthyでBadGatewayになってしまったので要検証

参考にさせていただいた書籍・ページ

実践Terraform AWSにおけるシステム設計とベストプラクティス
https://dx.nissho-ele.co.jp/blog/aws-beginner-ec2-elb_20190410.html
https://www.terraform.io/

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21