简介

基础架构即代码或 IaC 允许架构师使用代码部署服务,而不是登录控制台并使用 GUI 进行部署。这种通过控制台部署的好处是它允许更一致的环境,并且可以根据需要重用和编辑代码,从而节省时间。我将在这个项目中使用的 IaC 工具是 Terraform,它与大多数主要的云提供商兼容。

该项目将涉及使用 Terraform 在 AWS 上构建三层架构。在三层架构中,应用程序被分解为面向 Web 的表示层、内部应用程序和数据库层。这与以前构建应用程序的方式不同,以前前端、后端和数据库都位于同一个位置。我们将用于构建此架构的服务将是 Virtual Private Cloud (VPC)、Elastic Compute Cloud (EC2)、Elastic Load Balancer (ELB)、Security Groups、Route Tables 和 Internet Gateway (IGW)

[图像描述](https://res.cloudinary.com/practicaldev/image/fetch/s--yfunvFv4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/msnj3ghnuidf1bgvt1eb.jpg)


我们为什么要这样架构?

1\。模块化: 以这种方式构建我们的架构的一个好处是每一层都可以单独管理。这有利于保持一个安全的环境,用户只能登录并管理他们需要使用的特定服务器和服务,即。数据库开发人员在数据库上工作,前端开发人员在前端工作。这样做的另一个好处是更有效的故障排除,如果要关闭一个层,我们可以专门专注于该层,而无需关闭整个应用程序。

2\。高可用性: 我们将关注的另一件事是高可用性,我们将通过在两个单独的 AWS 可用区中构建来解决这一问题。万一一个可用区由于某种原因出现故障,我们的应用程序仍将在另一个可用区中运行。与传统的现场服务器相比,这是云的巨大优势,如果断电或互联网连接丢失,应用程序将完全关闭。

3\。安全性: 我们将在公共子网上构建前端,该子网将通过负载均衡器访问。我们的应用程序和数据库层将位于私有子网中,只能使用 SSH 从指定的安全组或 IP 地址访问这些子网。安全组将允许我们设置入口和出口流量的标准,并指定可以从哪些 CIDR 块中使用哪些协议。

4\。一致性: 推出这些项目的一个重要部分是保持一致性。当我们在这个项目中进行任何更改时,我们将使用 Terraform 而不是 AWS 控制台进行更改。这样做的原因是,如果我们需要找出任何关于配置的信息,我们可以查看我们的 Terraform 文件,这将让我们确切地知道事情是如何设置的。这样做的另一个好处是我们可以再次重用代码,例如如果我们需要添加额外的服务器或者我们正在处理另一个类似的项目,我们可以使用这个项目的代码来部署架构,从而节省我们的时间。


让我们开始吧!

Terraform 的一大优点是,当我们编写代码时,只要服务在文档中,它们的顺序无关紧要。例如,如果我们将 VPC 信息放在子网之后,Terraform 会仍然先构建 VPC,然后构建子网。最佳实践仍然是按顺序构建事物,这就是我们将在此处遵循的内容。

在我们开始做其他事情之前,我们将编写的第一段代码将是我们的提供程序配置。这将指定我们正在使用的云提供商以及您的 AWS 账户的密钥和访问密钥。对于密钥和访问密钥,最佳做法是使用环境变量而不是在代码中键入值。用于此的命令是 export AWS_ACCESS_KEY_IDu003d"anaccesskey"export AWS_SECRET_ACCESS_KEYu003d"asecretkey"

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region     = "us-east-1"
  access_key = AWS_ACCESS_KEY_ID
  secret_key = AWS_SECRET_ACCESS_KEY
}

进入全屏模式 退出全屏模式


变量

使用 Terraform 时的另一个最佳实践是使用变量,原因是在更新某些内容时,它提供了更多的一致性来更新一个变量,而不是进入并更新每个值。例如,假设我们的实例类型有一个变量,如果我们想更改类型,我们只需更新一个变量,所有使用该变量的代码都会被更新。如果我们不使用变量,我们将需要进入并更新每个项目,我们可能会忘记更新一个项目,这会导致我们的架构不一致。现在让我们继续创建变量。

Vpc_cidr

这是我们 VPC 的 CIDR 块的默认值,即 10.0.0.0/16

### VPC variable

variable "vpc_cidr" {
  description = "default VPC CIDR block"
  type        = string
  default     = "10.0.0.0/16"
}

进入全屏模式 退出全屏模式

可用性\区域\名称

此变量将创建一个包含我们将使用的可用区的列表

### Availability Zone variable

variable "availability_zone_names" {
  type    = list(string)
  default = ["us-east-1a", "us-east-1b"]
}

进入全屏模式 退出全屏模式

子网_cidr

这些变量将是保存我们子网的 CIDR 值的列表

### Web Subnet CIDR

variable "web_subnet_cidr" {
  type    = list(string)
  default = ["10.0.1.0/24", "10.0.2.0/24"]

}

### Application Subnet CIDR

variable "application_subnet_cidr" {
  type    = list(string)
  default = ["10.0.11.0/24", "10.0.12.0/24"]
}

### Database Subnet CIDR

variable "database_subnet_cidr" {
  type    = list(string)
  default = ["10.0.21.0/24", "10.0.22.0/24"]

}

进入全屏模式 退出全屏模式

Rds_instance

稍后我们将在构建数据库实例时使用此变量。它包含存储、数据库引擎、版本、实例类型以及是否部署在多个可用区中的值

### Database variables

variable "rds_instance" {
  type = map(any)
  default = {
    allocated_storage   = 10
    engine              = "mysql"
    engine_version      = "8.0.20"
    instance_class      = "db.t2.micro"
    multi_az            = true
    name                = "my_db"
    skip_final_snapshot = true
  }
}

### Create DB Variables
variable "user_information" {
  type = map(any)
  default = {
    username = "username"
    password = "password"
  }
  sensitive = true
}

进入全屏模式 退出全屏模式

实例变量

以下变量将保存我们的 EC2 实例的信息,例如 AMI ID 和实例类型

### Instance variable 

variable "ami_id" {
  description = "default ami"
  type        = string
  default     = "ami-0cff7528ff583bf9a"
}

variable "instance_type" {
  description = "default instance type"
  type        = string
  default     = "t2.micro"
}

进入全屏模式 退出全屏模式

计数变量

这将用作我们的可用区和实例的计数,我们将在此项目中将其保持为 2。

### Count variable

variable "item_count" {
  description = "default count used to set AZs and instances"
  type        = number
  default     = 2
}

进入全屏模式 退出全屏模式


创建我们的服务

1\。专有网络

我们的第一步将是创建一个虚拟私有云 (VPC)。这是一个虚拟网络,我们将在其中部署我们的服务。创建 VPC 时,我们会给它一个名称和 CIDR 范围,这里要记住的一件事是 CIDR 范围以后不能更改。

对于这个项目,我们将使用非常原始的名称 vpc-1,我们的 CIDR 范围将是 10.0.0.0/16

### Create a VPC
resource "aws_vpc" "vpc-1" {
  cidr_block = var.vpc_cidr
  tags = {
    Name = "Demo VPC"
  }

}

进入全屏模式 退出全屏模式

2\。 IGW

接下来是互联网网关或 IGW,这将允许我们公共子网中的 EC2 实例访问公共互联网。同样在这一步中,我创建了一个路由表,它将通过我们的 IGW 添加到公共 Internet 的路由,以及一个路由表关联,它将路由表附加到所需的子网。

您将在下面和后续部分中看到的一件事是 count,它指的是我们之前创建的变量,这将是我们正在创建的 route_table_associations 的数量。另一件事是 subnet_id 字段中的 [count.index]。这意味着它将通过我们将创建的两个子网运行,它们是面向 Web 的[0] 和面向 Web 的[1]。我将在下一节中对此进行更多介绍。

### Create an Internet Gateway
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc-1.id

  tags = {
    Name = "IGW"
  }

}

### Create a Web Facing Routing Table
resource "aws_route_table" "public-rt" {
  vpc_id = aws_vpc.vpc-1.id


  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id

  }

  tags = {
    Name = "Public-Rt"
  }

}

### Create Subnet Association with Route Table
resource "aws_route_table_association" "a" {
  count          = var.item_count
  subnet_id      = aws_subnet.web-facing[count.index].id
  route_table_id = aws_route_table.public-rt.id
}

进入全屏模式 退出全屏模式

3\。子网

现在我们的 VPC 已经创建,我们可以继续创建子网。对于这个项目,我们将有 6 个子网,2 个用于表示层的公共子网,2 个用于应用程序层的私有子网,以及 2 个用于数据库层的私有子网。公共子网中的实例将具有公共 IP,并且能够访问 Internet,而私有子网将具有私有 IP,并且仅在内部发送流量。

正如我在上一节中提到的,我们不会输入两个不同的子网,例如 web-facing1web-facing2。相反,我们使用 count 变量来引用数字 2,因此它将循环两次并创建两个子网,这使我们不必输入额外的代码,从而使我们看起来更清晰。我们将对引用 cidr_block 变量和我们之前创建的索引的 cidr_block 执行相同的操作。

### Create Web Public Subnet
resource "aws_subnet" "web-facing" {
  count                   = var.item_count
  vpc_id                  = aws_vpc.vpc-1.id
  cidr_block              = var.web_subnet_cidr[count.index]
  availability_zone       = var.availability_zone_names[count.index]
  map_public_ip_on_launch = true

  tags = {
    Name = "web-${count.index + 1}"
  }

}

### Create Application Private Subnet
resource "aws_subnet" "application" {
  count                   = var.item_count
  vpc_id                  = aws_vpc.vpc-1.id
  cidr_block              = var.application_subnet_cidr[count.index]
  availability_zone       = var.availability_zone_names[count.index]
  map_public_ip_on_launch = false

  tags = {
    Name = "application-${count.index + 1}"
  }

}


### Create Database Private Subnet
resource "aws_subnet" "db" {
  count             = var.item_count
  vpc_id            = aws_vpc.vpc-1.id
  cidr_block        = var.database_subnet_cidr[count.index]
  availability_zone = var.availability_zone_names[count.index]

  tags = {
    Name = "db-${count.index + 1}"
  }

}

进入全屏模式 退出全屏模式

4\。应用程序负载均衡器

我们将配置一个负载均衡器来在不同可用区的实例之间分配流量。当访问我们的应用程序时,用户将点击负载均衡器的 IP 地址,然后将流量引导到我们的 EC2 实例。

除了负载均衡器本身,我们还有:

  • 一个目标组,我们用它来将请求路由到一个注册的目标

  • 允许我们将实例附加到负载均衡器的目标组附件

  • 一个侦听器,用于检查来自我们指定的端口和协议的连接请求

### Create External Load Balancer

resource "aws_lb" "external-lb" {
  name               = "External-LB"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.web-sg.id]
  subnets            = aws_subnet.web-facing[count.index]

  enable_deletion_protection = true
}

### Create an External Target Group

resource "aws_lb_target_group" "external-elb" {
  name     = "ALB-TG"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.vpc-1.id
}

### Create Target Group Attachment

resource "aws_lb_target_group_attachment" "external-elb1" {
  count            = var.item_count
  target_group_arn = aws_lb_target_group.external-elb.arn
  target_id        = aws_instance.webserver[count.index].id
  port             = 80

  depends_on = [
    aws_instance.webserver,
  ]
}

### Create LB Listener

resource "aws_lb_listener" "external-elb" {
  load_balancer_arn = aws_lb.external-lb.arn
  port              = "80"
  protocol          = "HTTP"


  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.external-elb.arn
  }
}

进入全屏模式 退出全屏模式

5\。安全组

下一步是创建安全组。安全组允许来自指定端口的流量,它还允许您设置允许来自哪里的流量,无论是 CIDR 范围还是另一个 AWS 安全组。我们将创建 4 个安全组,一个用于负载均衡器,一个用于 Web 服务器,一个用于应用程序层,一个用于数据库层。

负载均衡器将允许来自任何地方的 HTTP 和 HTTPS 流量,Web 服务器将允许来自负载均衡器的 HTTP 流量,应用程序层将允许来自我们可以设置堡垒主机的公共层的 SSH,而数据库层将允许流量来自应用程序层的端口 3306,用于 MySQL。

### Create Security Groups

resource "aws_security_group" "web-sg" {
  name        = "Web-SG"
  description = "Allow HTTP Inbound Traffic"
  vpc_id      = aws_vpc.vpc-1.id

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

  ingress {
    description = "HTTPS from VPC"
    from_port   = 443
    to_port     = 443
    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 = "Web-SG"
  }
}

### Create Web Server Security Group

resource "aws_security_group" "webserver-sg" {
  name        = "Webserver-SG"
  description = "Allow Inbound Traffic from ALB"
  vpc_id      = aws_vpc.vpc-1.id

  ingress {
    description     = "Allow traffic from web layer"
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    security_groups = [aws_security_group.web-sg.id]
  }

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

  tags = {
    Name = "Webserver-SG"
  }
}

### Create Application Security Group

resource "aws_security_group" "app-sg" {
  name        = "App-SG"
  description = "Allow SSH Inbound Traffic"
  vpc_id      = aws_vpc.vpc-1.id

  ingress {
    description     = "SSH from VPC"
    from_port       = 22
    to_port         = 22
    protocol        = "tcp"
    security_groups = [aws_security_group.web-sg.id]
  }

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

  tags = {
    Name = "App-SG"
  }
}
### Created Database Security Group

resource "aws_security_group" "database-sg" {
  name        = "Database-SG"
  description = "Allow Inbound Traffic from application layer"
  vpc_id      = aws_vpc.vpc-1.id

  ingress {
    description     = "Allow traffic from application layer"
    from_port       = 3306
    to_port         = 3306
    protocol        = "tcp"
    security_groups = [aws_security_group.webserver-sg.id]
  }

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

  tags = {
    Name = "Database-SG"
  }
}

进入全屏模式 退出全屏模式

6\。 EC2 实例

现在已经完成了网络方面的工作,我们可以开始处理 EC2 实例了。在本节中,我们将为面向 Web 的层和应用层创建实例。我们将在不同的可用区启动这两种类型的 2 个实例。

我们再次使用 count 变量来指定我们想要创建的实例数。同样在面向 Web 的实例中,我正在使用 shell 命令 file("install_apache.sh") 实例将在创建时执行,这将安装 Apache 以使其成为 Web 服务器。

### Create EC2 Instance
resource "aws_instance" "webserver" {
  count                  = var.item_count
  ami                    = var.ami_id
  instance_type          = var.instance_type
  availability_zone      = var.availability_zone_names[count.index]
  vpc_security_group_ids = [aws_security_group.webserver-sg.id]
  subnet_id              = aws_subnet.web-facing[count.index].id
  user_data              = file("install_apache.sh")

  tags = {
    Name = "Web Server-${count.index}"
  }
}

### Create App Instance
resource "aws_instance" "appserver" {
  count                  = var.item_count
  ami                    = var.ami_id
  instance_type          = var.instance_type
  availability_zone      = var.availability_zone_names[count.index]
  vpc_security_group_ids = [aws_security_group.app-sg.id]
  subnet_id              = aws_subnet.application[count.index].id

  tags = {
    Name = "App Server-${count.index}"
  }

}

进入全屏模式 退出全屏模式

7\。 RDS 实例

接下来,我们将开始创建 RDS 实例,该实例将成为我们的后端数据库。除了实例本身,我们还将为我们的数据库实例创建一个子网_组。这是我们为所有数据库实例指定的子网。

### Create RDS Instance

resource "aws_db_instance" "default" {
  allocated_storage      = var.rds_instance.allocated_storage
  db_subnet_group_name   = aws_db_subnet_group.default.id
  engine                 = var.rds_instance.engine
  engine_version         = var.rds_instance.engine_version
  instance_class         = var.rds_instance.instance_class
  multi_az               = var.rds_instance.multi_az
  name                   = var.rds_instance.name
  username               = var.user_information.username
  password               = var.user_information.password
  skip_final_snapshot    = var.rds_instance.skip_final_snapshot
  vpc_security_group_ids = [aws_security_group.database-sg.id]

}

### Create RDS Subnet Group

resource "aws_db_subnet_group" "default" {
  name       = "main"
  subnet_ids = aws_subnet.db[count.index]

  tags = {
    name = "My DB subnet group"
  }
}

进入全屏模式 退出全屏模式

8.输出

下一步会将负载均衡器的 DNS 名称打印到我们的终端中,以便在我们的实例启动并运行后,我们可以将其复制并粘贴到浏览器中,以确保我们能够访问该站点。

### Create ouput to print

output "lb_dns_name" {
  description = "The DNS name of the load balancer"
  value       = aws_lb.external-lb.dns_name

}

进入全屏模式 退出全屏模式

9\。地形命令

现在我们的服务模板已经创建,下一步是初始化 Terraform 并构建我们的基础设施。这些是我们将用来完成任务的 Terraform 命令。我们首先需要打开终端并移动到我们拥有 Terraform 文件的目录。

  • Terraform init 将初始化 Terraform

  • Terraform fmt 将确保我们的代码格式正确,并将修改我们的代码以匹配格式

  • Terraform validate 将确保我们的语法没有错误,如果我们这样做,它将返回发生错误的文件和行

  • Terraform plan 是我们将要做的规划并查看将创建哪些资源

  • Terraform apply 在我们运行计划命令并确保一切看起来正确之后,我们将运行实际构建我们的基础架构的应用命令。

10\。测试

创建服务后,终端还应列出负载均衡器的 DNS 名称。我们会将其复制并粘贴到我们的浏览器中,以确保我们能够访问该站点。

11\。清理

每当我们完成这个项目时,删除我们的基础设施是很重要的,这样我们就不会继续被收费。为此,我们发出 Terraform destroy 命令,该命令将删除我们创建的所有内容。

成功!我们刚刚使用 Terraform 创建了三层 AWS 架构


最后的想法

当我第一次开始使用 AWS 时,我想知道为什么人们在创建架构时会使用 CLI 或 IaC 工具而不是 GUI。对于初学者来说,GUI 似乎更容易使用,但在玩过 Terraform 之后,我可以清楚地看到为什么这是首选方式。

以这种方式创建服务更加容易和快捷,并且作为额外的好处,您可以将代码重用于其他项目,从而节省大量时间,虽然 Terraform 代码对于该工具的新手来说可能看起来令人生畏,但它其实真的很容易理解。此外,Terraform 网站上的文档真的很棒,让使用该工具变得更加容易。


全码

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region     = "us-east-1"
  access_key = AWS_ACCESS_KEY_ID
  secret_key = AWS_SECRET_ACCESS_KEY
}


### VPC variable

variable "vpc_cidr" {
  description = "default VPC CIDR block"
  type        = string
  default     = "10.0.0.0/16"
}

### Availability Zone variable

variable "availability_zone_names" {
  type    = list(string)
  default = ["us-east-1a", "us-east-1b"]
}

### Web Subnet CIDR

variable "web_subnet_cidr" {
  type    = list(string)
  default = ["10.0.1.0/24", "10.0.2.0/24"]

}

### Application Subnet CIDR

variable "application_subnet_cidr" {
  type    = list(string)
  default = ["10.0.11.0/24", "10.0.12.0/24"]
}

### Database Subnet CIDR

variable "database_subnet_cidr" {
  type    = list(string)
  default = ["10.0.21.0/24", "10.0.22.0/24"]

}

### Database variables

variable "rds_instance" {
  type = map(any)
  default = {
    allocated_storage   = 10
    engine              = "mysql"
    engine_version      = "8.0.20"
    instance_class      = "db.t2.micro"
    multi_az            = true
    name                = "my_db"
    skip_final_snapshot = true
  }
}

### Create DB Variables
variable "user_information" {
  type = map(any)
  default = {
    username = "username"
    password = "password"
  }
  sensitive = true
}

### Instance variable 

variable "ami_id" {
  description = "default ami"
  type        = string
  default     = "ami-0cff7528ff583bf9a"
}

variable "instance_type" {
  description = "default instance type"
  type        = string
  default     = "t2.micro"
}
### Count variable

variable "item_count" {
  description = "default count used to set AZs and instances"
  type        = number
  default     = 2
}

### Create a VPC
resource "aws_vpc" "vpc-1" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "Demo VPC"
  }

}


### Create an Internet Gateway
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc-1.id

  tags = {
    Name = "IGW"
  }

}

### Create a Web Facing Routing Table
resource "aws_route_table" "public-rt" {
  vpc_id = aws_vpc.vpc-1.id


  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id

  }

  tags = {
    Name = "Public-Rt"
  }

}

### Create Subnet Association with Route Table
resource "aws_route_table_association" "a" {
  count          = var.item_count
  subnet_id      = aws_subnet.web-facing[count.index].id
  route_table_id = aws_route_table.public-rt.id
}

### Create Web Public Subnet
resource "aws_subnet" "web-facing" {
  count                   = var.item_count
  vpc_id                  = aws_vpc.vpc-1.id
  cidr_block              = var.web_subnet_cidr[count.index]
  availability_zone       = var.availability_zone_names[count.index]
  map_public_ip_on_launch = true

  tags = {
    Name = "web-${count.index + 1}"
  }

}

### Create Application Private Subnet
resource "aws_subnet" "application" {
  count                   = var.item_count
  vpc_id                  = aws_vpc.vpc-1.id
  cidr_block              = var.application_subnet_cidr[count.index]
  availability_zone       = var.availability_zone_names[count.index]
  map_public_ip_on_launch = false

  tags = {
    Name = "application-${count.index + 1}"
  }

}


### Create Database Private Subnet
resource "aws_subnet" "db" {
  count             = var.item_count
  vpc_id            = aws_vpc.vpc-1.id
  cidr_block        = var.database_subnet_cidr[count.index]
  availability_zone = var.availability_zone_names[count.index]

  tags = {
    Name = "db-${count.index + 1}"
  }

}

### Create External Load Balancer

resource "aws_lb" "external-lb" {
  name               = "External-LB"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.web-sg.id]
  subnets            = [aws_subnet.web-facing[0].id, aws_subnet.web-facing[1].id]

  enable_deletion_protection = true
}

### Create Internal Load Balancer

resource "aws_lb" "internal-lb" {
  name               = "Internal-LB"
  internal           = true
  load_balancer_type = "application"
  security_groups    = [aws_security_group.app-sg.id]
  subnets            = [aws_subnet.application[0].id, aws_subnet.application[1].id]

  enable_deletion_protection = true
}

### Create an External Target Group

resource "aws_lb_target_group" "external-elb" {
  name     = "ALB-TG"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.vpc-1.id
}

### Create and Internal Target Group

resource "aws_lb_target_group" "internal-elb" {
  name     = "ILB-TG"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.vpc-1.id
}
### Create Target Group Attachment

resource "aws_lb_target_group_attachment" "external-elb1" {
  count            = var.item_count
  target_group_arn = aws_lb_target_group.external-elb.arn
  target_id        = aws_instance.webserver[count.index].id
  port             = 80

  depends_on = [
    aws_instance.webserver,
  ]
}

resource "aws_lb_target_group_attachment" "internal-elb1" {
  count            = var.item_count
  target_group_arn = aws_lb_target_group.internal-elb.arn
  target_id        = aws_instance.appserver[count.index].id
  port             = 80

  depends_on = [
    aws_instance.webserver,
  ]
}


### Create LB Listener

resource "aws_lb_listener" "external-elb" {
  load_balancer_arn = aws_lb.external-lb.arn
  port              = "80"
  protocol          = "HTTP"


  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.external-elb.arn
  }
}

resource "aws_lb_listener" "internal-elb" {
  load_balancer_arn = aws_lb.internal-lb.arn
  port              = "80"
  protocol          = "HTTP"


  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.internal-elb.arn
  }
}

### Create Security Groups

resource "aws_security_group" "web-sg" {
  name        = "Web-SG"
  description = "Allow HTTP Inbound Traffic"
  vpc_id      = aws_vpc.vpc-1.id

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

  ingress {
    description = "HTTPS from VPC"
    from_port   = 443
    to_port     = 443
    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 = "Web-SG"
  }
}

### Create Web Server Security Group

resource "aws_security_group" "webserver-sg" {
  name        = "Webserver-SG"
  description = "Allow Inbound Traffic from ALB"
  vpc_id      = aws_vpc.vpc-1.id

  ingress {
    description     = "Allow traffic from web layer"
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    security_groups = [aws_security_group.web-sg.id]
  }

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

  tags = {
    Name = "Webserver-SG"
  }
}

### Create Application Security Group

resource "aws_security_group" "app-sg" {
  name        = "App-SG"
  description = "Allow SSH Inbound Traffic"
  vpc_id      = aws_vpc.vpc-1.id

  ingress {
    description     = "SSH from VPC"
    from_port       = 22
    to_port         = 22
    protocol        = "tcp"
    security_groups = [aws_security_group.web-sg.id]
  }

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

  tags = {
    Name = "App-SG"
  }
}
### Created Database Security Group

resource "aws_security_group" "database-sg" {
  name        = "Database-SG"
  description = "Allow Inbound Traffic from application layer"
  vpc_id      = aws_vpc.vpc-1.id

  ingress {
    description     = "Allow traffic from application layer"
    from_port       = 3306
    to_port         = 3306
    protocol        = "tcp"
    security_groups = [aws_security_group.webserver-sg.id]
  }

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

  tags = {
    Name = "Database-SG"
  }
}

### Create EC2 Instance
resource "aws_instance" "webserver" {
  count                  = var.item_count
  ami                    = var.ami_id
  instance_type          = var.instance_type
  availability_zone      = var.availability_zone_names[count.index]
  vpc_security_group_ids = [aws_security_group.webserver-sg.id]
  subnet_id              = aws_subnet.web-facing[count.index].id
  user_data              = file("install_apache.sh")

  tags = {
    Name = "Web Server-${count.index}"
  }
}

### Create App Instance
resource "aws_instance" "appserver" {
  count                  = var.item_count
  ami                    = var.ami_id
  instance_type          = var.instance_type
  availability_zone      = var.availability_zone_names[count.index]
  vpc_security_group_ids = [aws_security_group.app-sg.id]
  subnet_id              = aws_subnet.application[count.index].id

  tags = {
    Name = "App Server-${count.index}"
  }

}
### Create RDS Instance

resource "aws_db_instance" "default" {
  allocated_storage      = var.rds_instance.allocated_storage
  db_subnet_group_name   = aws_db_subnet_group.default.id
  engine                 = var.rds_instance.engine
  engine_version         = var.rds_instance.engine_version
  instance_class         = var.rds_instance.instance_class
  multi_az               = var.rds_instance.multi_az
  name                   = var.rds_instance.name
  username               = var.user_information.username
  password               = var.user_information.password
  skip_final_snapshot    = var.rds_instance.skip_final_snapshot
  vpc_security_group_ids = [aws_security_group.database-sg.id]

}

### Create RDS Subnet Group

resource "aws_db_subnet_group" "default" {
  name       = "main"
  subnet_ids = aws_subnet.db[count.index]

  tags = {
    name = "My DB subnet group"
  }
}

### Create ouput to print

output "lb_dns_name" {
  description = "The DNS name of the load balancer"
  value       = aws_lb.external-lb.dns_name

}

进入全屏模式 退出全屏模式

Logo

CI/CD社区为您提供最前沿的新闻资讯和知识内容

更多推荐