Deploy a Scalable Web Server Environment Using Terraform

学习如何使用 Terraform 部署可扩展、高度可用的 Web 服务器基础架构来提供内容。

任务详情(通过使用AWS CLI)

虚拟私有云 (VPC)

创建名为 websrv-vpc 的虚拟私有云。

子网

在您的 VPC 中配置 4 个名为 websrv-vpc 的子网,其中 2 个子网指定为公有子网,2 个指定为私有子网。每对子网(1 个公共子网和 1 个私有子网)必须放置在不同的可用区中,以确保高可用性。

互联网网关 (IGW)

将互联网网关连接到 websrv-vpc,以允许您的 VPC 中的资源访问互联网。

NAT 网关

在 websrv-vpc 中部署至少 2 个 NAT 网关,置于不同的可用区,以允许私有子网中的实例访问互联网。

路由表

创建 3 个额外的路由表来管理 websrv-vpc 内的网络流量,包括: 公共路由表,其中包含将互联网流量定向到 IGW 的路由。 每个 AZ 中私有子网的路由表,将互联网绑定流量定向到相应 AZ 的 NAT 网关。 正确的子网关联。公共子网到公共路由表。私有子网到私有路由表。默认主子网不应有关联。

安全组

使用以下规则配置名为 websrv-sg 的安全组: 允许来自任何 IP 地址 (0.0.0.0/0) 的 HTTP 流量(端口 80)的入站规则。 允许所有流量的出站规则,以确保实例可以启动互联网连接。

启动模板

创建名为 websrv-lt 的启动模板。此模板将指定 ASG 将启动的实例的配置。

自动扩展组 (ASG)

使用 websrv-lt 启动模板设置一个名为 websrv-asg 的 ASG。 ASG 必须覆盖至少两个可用区以确保高可用性。

应用程序负载均衡器 (ALB)

部署一个名为 websrv-asg-lb 的 ALB。 ALB 的目的是在由 ASG 管理的实例之间分配传入流量。

目标群体

为 ALB 建立一个名为 websrv-lb-tg 的目标群组。 应将此目标组配置为使用 HTTP 和端口 80,并且必须向其注册 ASG 的实例。

代码参考:

  region = "us-west-1" # 请根据实际情况选择区域
}

resource "aws_vpc" "websrv_vpc" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "websrv-vpc"
  }
}

resource "aws_subnet" "public_subnet_1" {
  vpc_id            = aws_vpc.websrv_vpc.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "us-west-2a"
  tags = {
    Name = "websrv-vpc-public-1"
  }
}

resource "aws_subnet" "private_subnet_1" {
  vpc_id            = aws_vpc.websrv_vpc.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "us-west-2a"
  tags = {
    Name = "websrv-vpc-private-1"
  }
}

# 重复上述资源定义,创建第二个可用区的公有和私有子网
resource "aws_internet_gateway" "websrv_igw" {
  vpc_id = aws_vpc.websrv_vpc.id
  tags = {
    Name = "websrv-vpc-igw"
  }
}

resource "aws_nat_gateway" "nat_gw_1" {
  allocation_id = aws_eip.nat_eip_1.id
  subnet_id     = aws_subnet.public_subnet_1.id
  tags = {
    Name = "websrv-vpc-nat-gw-1"
  }
}

resource "aws_eip" "nat_eip_1" {
  vpc = true
}
resource "aws_route_table" "public_rt" {
  vpc_id = aws_vpc.websrv_vpc.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.websrv_igw.id
  }
  tags = {
    Name = "websrv-vpc-public-rt"
  }
}

resource "aws_route_table" "private_rt_1" {
  vpc_id = aws_vpc.websrv_vpc.id
  route {
    cidr_block = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.nat_gw_1.id
  }
  tags = {
    Name = "websrv-vpc-private-rt-1"
  }
}

# 为每个子网关联相应的路由表
resource "aws_route_table_association" "public_subnet_1_assoc" {
  subnet_id      = aws_subnet.public_subnet_1.id
  route_table_id = aws_route_table.public_rt.id
}

resource "aws_route_table_association" "private_subnet_1_assoc" {
  subnet_id      = aws_subnet.private_subnet_1.id
  route_table_id = aws_route_table.private_rt_1.id
}
resource "aws_security_group" "websrv_sg" {
  name        = "websrv-sg"
  description = "Allow HTTP traffic and all outbound traffic"
  vpc_id      = aws_vpc.websrv_vpc.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"]
  }
}
resource "aws_launch_template" "websrv_lt" {
  name_prefix   = "websrv-lt-"
  image_id      = "ami-0c55b159cbfafe1f0" # 请替换为最新的 Amazon Linux 2 AMI ID
  instance_type = "t2.micro"
  security_group_ids = [aws_security_group.websrv_sg.id]
  user_data = <<EOF
              #!/bin/bash
              yum update -y
              yum install -y httpd
              systemctl start httpd
              systemctl enable httpd
              echo "<h1>Welcome to the Jam!</h1>" > /var/www/html/index.html
              EOF
}

resource "aws_autoscaling_group" "websrv_asg" {
  name             = "websrv-asg"
  launch_template {
    id      = aws_launch_template.websrv_lt.id
    version = "$Latest"
  }
  min_size         = 2
  max_size         = 4
  desired_capacity = 2
  vpc_zone_identifier = [aws_subnet.private_subnet_1.id, aws_subnet.private_subnet_2.id] # 假设您已经创建了第二个私有子网
  target_group_arns = [aws_lb_target_group.websrv_lb_tg.arn]
}

resource "aws_lb" "websrv_asg_lb" {
  name               = "websrv-asg-lb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.websrv_sg.id]
  subnets            = [aws_subnet.public_subnet_1.id, aws_subnet.public_subnet_2.id] # 假设您已经创建了第二个公有子网
}

resource "aws_lb_target_group" "websrv_lb_tg" {
  name     = "websrv-lb-tg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.websrv_vpc.id

  health_check {
    path                = "/"
    interval            = 30
    timeout             = 5
    healthy_threshold   = 5
    unhealthy_threshold = 2
  }
}

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

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