AWS Two-Tier Architecture Deployment With Terraform

AWS Two-Tier Architecture Deployment With Terraform

#10weekcloudops

Introduction:
The two-tier architecture is a common design pattern for deploying web applications that separate the front-end and back-end components into distinct tiers or layers. In this architecture, the front-end tier typically consists of web servers or instances that handle user requests, while the back-end tier includes a database or data storage layer.
When deploying a two-tier architecture on AWS using Terraform, you can leverage various AWS services such as EC2, RDS, and VPC. Here’s an overview of the deployment process:

  1. VPC Configuration: Begin by defining the Virtual Private Cloud (VPC) for your architecture. The VPC provides isolated network space for your resources.

  2. Subnet Configuration: Create subnets within the VPC to segregate your resources. Typically, you will have a public subnet for front-end instances and a private subnet for the back-end database.

  3. Security Group Configuration: Define security groups to control inbound and outbound traffic to your instances. Ensure that the appropriate ports are open for web traffic (e.g., HTTP, HTTPS) to the front-end instances.

  4. EC2 Instance Configuration: Use the aws_instance resource in Terraform to provision EC2 instances in the public subnet. These instances will serve as the front-end web servers or application servers for your web application.

  5. RDS Configuration: Define an RDS instance using the aws_db_instance resource in Terraform. This will provide the database for your back-end tier. Specify the necessary configurations, such as engine type, instance size, and database credentials.

  6. Subnet Group Configuration: Create a DB subnet group using the aws_db_subnet_group resource to associate the RDS instance with the private subnet. This ensures that the database is securely isolated within the private subnet.

  7. Load Balancer Configuration: To enhance scalability and availability, consider using an Application Load Balancer (ALB) or Network Load Balancer (NLB) in front of the EC2 instances. Configure the load balancer to distribute traffic evenly among the instances.

  8. Deployment: Finally, run terraform init to initialize your Terraform configuration, followed by terraform apply creating and provisioning the resources defined in your Terraform code.

Github repo: https://github.com/HARSHALJETHWA19/2-tier-web-architecture

Steps to Create AWS Two-Tier Architecture Deployment With Terraform

Step 1: Initiate Working Directory and Provider Configurations

In the IDE, create a new working directory and change into that directory with this syntax:

mkdir <directory name>
cd <directory name>

In the new working directory, create a main.tf file to begin writing our cloud infrastructure:

touch main.tf

then, open the main.tf file and write down the below code:

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

# Configure AWS Provider
provider "aws" {
  region = "us-east-1"
}

Step 2: Declare VPC and Internet Gateway Resources

With the previous step, declare the VPC and attached Internet Gateway for the infrastructure:

# Deploy VPC
resource "aws_vpc" "vpc" {
  cidr_block       = "10.0.0.0/16"
  instance_tenancy = "default"

  tags = {
    Name = "2-tier-web-architecture"
  }
}

# Deploy Internet Gateway
resource "aws_internet_gateway" "ig" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name = "2-tier-web-vpc"
  }
}

Step 3 — Enable Public and Private Subnets

declare both the public and private subnets in the infrastructure with the following syntax:

# Deploy 2 Public Subnets
resource "aws_subnet" "public1" {
  vpc_id                  = aws_vpc.vpc.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = true

  tags = {
    Name = "1public"
  }
}

resource "aws_subnet" "public2" {
  vpc_id                  = aws_vpc.vpc.id
  cidr_block              = "10.0.2.0/24"
  availability_zone       = "us-east-1b"
  map_public_ip_on_launch = true

  tags = {
    Name = "2public"
  }
}

# Deploy 2 Private Subnets
resource "aws_subnet" "private1" {
  vpc_id                  = aws_vpc.vpc.id
  cidr_block              = "10.0.3.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = false

  tags = {
    Name = "1private"
  }
}

resource "aws_subnet" "private2" {
  vpc_id                  = aws_vpc.vpc.id
  cidr_block              = "10.0.4.0/24"
  availability_zone       = "us-east-1b"
  map_public_ip_on_launch = false

  tags = {
    Name = "2private"
  }
}

Step 4 — Set Route Table and Subnet Associations

The following syntax will declare the route table and its subnet associations for the infrastructure:

# Deploy Route Table
resource "aws_route_table" "rt" {
  vpc_id = aws_vpc.vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.ig.id
  }
  tags = {
    Name = "routetable"
  }
}

# Associate Subnets With Route Table
resource "aws_route_table_association" "route1" {
  subnet_id      = aws_subnet.public1.id
  route_table_id = aws_route_table.rt.id
}

resource "aws_route_table_association" "route2" {
  subnet_id      = aws_subnet.public2.id
  route_table_id = aws_route_table.rt.id
}

Step 5 — Configure Security Groups

The following provides the HCL syntax to properly declare these critical pieces of the infrastructure:

# Deploy Security Groups
resource "aws_security_group" "publicsg" {
  name        = "publicsg"
  description = "Allow traffic"
  vpc_id      = aws_vpc.vpc.id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 22
    to_port     = 22
    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_security_group" "privatesg" {
  name        = "privatesg"
  description = "Allow traffic"
  vpc_id      = aws_vpc.vpc.id

  ingress {
    from_port       = 3306
    to_port         = 3306
    protocol        = "tcp"
    cidr_blocks     = ["10.0.0.0/16"]
    security_groups = [aws_security_group.publicsg.id]
  }
  ingress {
    from_port   = 22
    to_port     = 22
    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"]

  }
}

# Deploy ALB Security Group
resource "aws_security_group" "albsg" {
  name        = "albsg"
  description = "ALB Security Group"
  vpc_id      = aws_vpc.vpc.id

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

Step 6 — Configure the Application Load Balancer

# Deploy Application Load Balancer
resource "aws_lb" "alb" {
  name               = "alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.albsg.id]
  subnets            = [aws_subnet.public1.id, aws_subnet.public2.id]
}

# Create ALB Target Group
resource "aws_lb_target_group" "albtg" {
  name     = "albtg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.vpc.id

  depends_on = [aws_vpc.vpc]
}

# Deploy LB Target Attachments
resource "aws_lb_target_group_attachment" "tgattach1" {
  target_group_arn = aws_lb_target_group.albtg.arn
  target_id        = aws_instance.instance1.id
  port             = 80

  depends_on = [aws_instance.instance1]
}

resource "aws_lb_target_group_attachment" "tgattach2" {
  target_group_arn = aws_lb_target_group.albtg.arn
  target_id        = aws_instance.instance2.id
  port             = 80

  depends_on = [aws_instance.instance2]
}

# Deploy LB Listener
resource "aws_lb_listener" "lblisten" {
  load_balancer_arn = aws_lb.alb.arn
  port              = "80"
  protocol          = "HTTP"

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

Step 7 — Set Up EC2 Instance

write below in the previous HCL code. it will create an EC2 instance with bootstrapping:

# Deploy EC2 Instances
resource "aws_instance" "instance1" {
  ami                         = "ami-0b0dcb5067f052a63"
  instance_type               = "t2.micro"
  availability_zone           = "us-east-1a"
  vpc_security_group_ids      = [aws_security_group.publicsg.id]
  subnet_id                   = aws_subnet.public1.id
  associate_public_ip_address = true
  user_data                   = <<-EOF
        #!/bin/bash
        yum update -y
        yum install httpd -y
        systemctl start httpd
        systemctl enable httpd
        echo "<html><body><h1>First instance successfully deployed</h1></body></html>" > /var/www/html/index.html
        EOF

  tags = {
    Name = "ec2instance1"
  }
}
resource "aws_instance" "instance2" {
  ami                         = "ami-0b0dcb5067f052a63"
  instance_type               = "t2.micro"
  availability_zone           = "us-east-1b"
  vpc_security_group_ids      = [aws_security_group.publicsg.id]
  subnet_id                   = aws_subnet.public2.id
  associate_public_ip_address = true
  user_data                   = <<-EOF
        #!/bin/bash
        yum update -y
        yum install httpd -y
        systemctl start httpd
        systemctl enable httpd
        echo "<html><body><h1>Second instance successfully deployed</h1></body></html>" > /var/www/html/index.html
        EOF

  tags = {
    Name = "ec2instance2"
  }
}

Step 8 — Configure RDS in Private Subnets

We will finalize our data tier with the following syntax:

# Relational Database Service Subnet Group
resource "aws_db_subnet_group" "dbsubnet" {
  name       = "dbsubnet"
  subnet_ids = [aws_subnet.private1.id, aws_subnet.private2.id]
}

# Create RDS Instance
resource "aws_db_instance" "dbinstance" {
  allocated_storage      = 5
  engine                 = "mysql"
  engine_version         = "5.7"
  instance_class         = "db.t2.micro"
  identifier             = "dbinstance"
  db_name                = "db"
  username               = "admin"
  password               = "password"
  db_subnet_group_name   = aws_db_subnet_group.dbsubnet.id
  vpc_security_group_ids = [aws_security_group.privatesg.id]
  skip_final_snapshot    = true
}

Step 9 — Create Outputs. tf file

Initiate the creation of the outputs.tf file with the following syntax:

touch outputs.tf

then, write the following syntax:


# Outputs
# Show EC2 Instance Public IPv4 Address
output "ec2publicip" {
  value = aws_instance.instance1.public_ip
}

# Show DB Instance Address
output "dbinstanceaddress" {
  value = aws_db_instance.dbinstance.address
}

# Show DNS of LB
output "lb_dns_name" {
  description = "The DNS of LB"
  value       = aws_lb.alb.dns_name
}

Step 10 — Initialize Terraform

With our .tf files populated with HCL to manage our infrastructure and outputs, we need to initialize Terraform with the following command:

terraform init

will return similar output:

We can further organize and clean our Terraform source code files with the following command:

terraform fmt

Step 11 — Plan and Apply

With our code formatted properly, we can execute the plan and apply phases of the workflow:

terraform plan

With proper deployment plans verified, we will insert the following command to apply and build out the infrastructure:

terraform apply

After the apply the AWS console resources will be :

Ec2 and security group list

load balancer and vpc list

Route table and Internet gateway

Then, the ec2 public ip url data will display :

Step 12 — Destroy Infrastructure

To initiate the deletion of the two-tier architecture, insert the following command:

NOTE:
DON’T FORGET TO DESTROY THE RESOURCES!!

terraform destroy

Follow me :

Linkedin: https://www.linkedin.com/in/harshaljethwa/

GitHub: https://github.com/HARSHALJETHWA19/

Twitter: https://twitter.com/harshaljethwaa

Thank You!!!