Help us understand the problem. What is going on with this article?

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

よくありそうなこういうアーキテクチャを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/

sicksixrock66
勉強中インフラエンジニア
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした