Create Infrastructure using Terraform ๐ฅ๐ฅ

Project: You'll create a VPC and deploy 2 applications in different availability zones, also there will be two public subnets attached to the internet gateway & an s3 bucket will be there along with will also create a load balancer to balance the load between the instances automatically.

As a first step launch an Ec2 instance(Ubuntu for me ) and install Terraform [https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli ] as per your OS setup.
Then Install Aws-Cli for the Linux platform
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
Don't forget to configure your terraform with aws with access and secret-access-key.
Let's start the project...
Step 1:
Create a directory and go inside it, then create two files main.tf and provider.tf
mkdir terraform-project/
cd terraform-project/
touch provider.tf main.tf
step 2:
Mention the provider and region in the provider.tf file
provider "aws" {
region="us-east-1"
}
Step 3:
Now start writing the main.tf file ,, as per the project
First create the VPC as the whole setup will be inside of a created VPC[Virtual Private Cloud].
resource "aws_vpc" "new_vpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "Aws-Vpc"
}
}
Step 4:
Now have to create two Public subnets and they also it should be in two different availability zones,,,, There are 6 availability zones present in the N.Virginia region so you can take any two and attach the vpc to the subnets
## Create the public subnet
resource "aws_subnet" "public_subnet1" {
vpc_id = aws_vpc.new_vpc.id ## attach the vpc to the subnets
cidr_block = "10.0.1.0/24"
availability_zone ="us-east-1b" ##mention the availability zones,as per your choice
map_public_ip_on_launch = true ## there should be a public ip created
tags = {
Name = "Public-Subnet1"
}
}
resource "aws_subnet" "public_subnet2" {
vpc_id = aws_vpc.new_vpc.id
cidr_block = "10.0.2.0/24"
availability_zone ="us-east-1a"
map_public_ip_on_launch = true
tags = {
Name = "Public-Subnet2"
}
}
Step 5:
Public subnets should be internet facing so that attach an internet gateway to the subnets.
## Create the internet-gateway
resource "aws_internet_gateway" "aws_igw" {
vpc_id = aws_vpc.new_vpc.id ## reference to the vpc
tags = {
Name = "IGW"
}
}
Step 6:
Create the Route table for the routes to the internet.
## Create the route tabel
resource "aws_route_table" "RT" {
vpc_id = aws_vpc.new_vpc.id ## refernce to the vpc
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.aws_igw.id ## Reference to the Internet gateway
}
tags = {
Name = "Aws-RT"
}
}
Step 7:
Associate the subnets to the Route Table,,,,
##Public route Table Association
resource "aws_route_table_association" "RTA1" {
subnet_id = aws_subnet.public_subnet1.id ## Public subnet 1
route_table_id = aws_route_table.RT.id ## Refernce to the route table id
}
resource "aws_route_table_association" "RTA2" {
subnet_id = aws_subnet.public_subnet2.id ## Public subnet 2
route_table_id = aws_route_table.RT.id
}
Step 8:
Now create the Security Group and attach it to the Vpc.
Here I have allowed the all traffic but you can only allow only port 22 and port 80 ...
## Create the security group
resource "aws_security_group" "mysg" {
name = "Aws-Security-Group"
description = "Allow TLS inbound traffic"
vpc_id = aws_vpc.new_vpc.id
ingress {
description = "TLS from VPC"
from_port = 0 ## All traffic
to_port = 0 ## All traffic
protocol = "-1" ## All protocol
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 = "my-sg"
}
}
Step 9:
Create the S3 bucket and its name should be globally unique.
## Create S3 bucker
resource "aws_s3_bucket" "s3-bucket" {
bucket = "terraform-project-aws-public-subnet"
}
Step 10:
Create two Ec2 instances and the subnets should be attached to the instances.
Also, I want that some scripts should run after the launching of the instances so add the user-data scripts with the instances.
## Create Ec2 instnace
resource "aws_instance" "Instance1" {
ami = "ami-053b0d53c279acc90"
instance_type ="t2.micro"
vpc_security_group_ids = [aws_security_group.mysg.id] ## Attach the Security Group
subnet_id = aws_subnet.public_subnet1.id ## Attach the Public Subnet-1 to the instance
user_data = base64encode(file("userdata.sh")) ## Add the userdata1 to instance 1 and encode it
}
resource "aws_instance" "Instance2" {
ami = "ami-053b0d53c279acc90" ## mention your ami-id
instance_type ="t2.micro" ## Instance type
vpc_security_group_ids = [aws_security_group.mysg.id]
subnet_id = aws_subnet.public_subnet2.id
user_data = base64encode(file("userdata1.sh")) ## Add the userdata1 to instance 2 and encode it
}
User-data 1 script:
#!/bin/bash
apt update
apt install -y apache2
# Get the instance ID using the instance metadata
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
# Install the AWS CLI
apt install -y awscli
# Download the images from S3 bucket
#aws s3 cp s3://myterraformprojectbucket2023/project.webp /var/www/html/project.png --acl public-read
# Create a simple HTML file with the portfolio content and display the images
cat <<EOF > /var/www/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>My Portfolio</title>
<style>
/* Add animation and styling for the text */
@keyframes colorChange {
0% { color: red; }
50% { color: green; }
100% { color: blue; }
}
h1 {
animation: colorChange 2s infinite;
}
</style>
</head>
<body>
<h1>Terraform Project Server 1</h1>
<h2>Instance ID: <span style="color:green">$INSTANCE_ID</span></h2>
<p>Welcome to Abhishek Veeramalla's Channel</p>
</body>
</html>
EOF
# Start Apache and enable it on boot
systemctl start apache2
systemctl enable apache2
This is the User-Data 2 Script:
Both Scripts are the same but only the Heading is Different.
#!/bin/bash
apt update
apt install -y apache2
# Get the instance ID using the instance metadata
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
# Install the AWS CLI
apt install -y awscli
# Download the images from S3 bucket
#aws s3 cp s3://myterraformprojectbucket2023/project.webp /var/www/html/project.png --acl public-read
# Create a simple HTML file with the portfolio content and display the images
cat <<EOF > /var/www/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>My Portfolio</title>
<style>
/* Add animation and styling for the text */
@keyframes colorChange {
0% { color: red; }
50% { color: green; }
100% { color: blue; }
}
h1 {
animation: colorChange 2s infinite;
}
</style>
</head>
<body>
<h1>Terraform Project Server 1</h1>
<h2>Instance ID: <span style="color:green">$INSTANCE_ID</span></h2>
<p>Welcome to CloudChamp's Channel</p>
</body>
</html>
EOF
# Start Apache and enable it on boot
systemctl start apache2
systemctl enable apache2
Step 11:
As per the diagram, everything is created except the load balancer part.
Let's create the application load balancer [It operates at Layer 7 of the OSI model]
An Application Load Balancer operates at layer 7 (application layer) and allows defining routing rules based on content across multiple services or containers running on one or more EC2 instances.
Scales the load balancer as traffic to the application changes over time.
Supports health checks, used to monitor the health of registered targets so that the load balancer can send requests only to the healthy targets.
For the Application LB you can create a separate security group but I have given the previously created security group reference and also mention subnets as it will load the balance between the two instances which are connected to the public subnets.
### Create the application load balancer
resource "aws_lb" "test_aplb" {
name = "test-alb-terraform"
internal = false ## It will be internal or external
load_balancer_type = "application" ### Type is application as there are more lb present
security_groups = [aws_security_group.mysg.id]
subnets = [aws_subnet.public_subnet1.id, aws_subnet.public_subnet2.id]
tags = {
Name = "Alb-Project"
}
}
Step 12:
Create the Target-Group of ALB,,,
routes requests to one or more registered targets, such as EC2 instances, using the specified protocol and port number.
a target can be registered with multiple target groups.
health checks can be configured on a per-target group basis
When a load balancer receives a request, it evaluates the listener rules in priority order to determine which rule to apply and then selects a target from the target group for the rule action.
Listener rules can be configured to route requests to different target groups based on the content of the application traffic.
## Alb target group creation
resource "aws_lb_target_group" "test-target-group" {
name = "test-target-group"
port = 80 ## Port number is 80...
protocol = "HTTP"
vpc_id = aws_vpc.new_vpc.id ## Refernce to the vpc
health_check {
path ="/"
port = "traffic-port"
}
}
Step 13:
The next step is to attach the load balancer to the created target group and also attach the Instances to it.
[Note: To attach the target group and instances to the target group you can use the for-each loop for the instances attachment but here I have created it twice to refer to.]
## Load balancer Target group attachment::
resource "aws_lb_target_group_attachment" "Instance-Attach1" {
target_group_arn = aws_lb_target_group.test-target-group.arn ## target group arn arn
target_id = aws_instance.Instance1.id ## Instance 1
port = 80
}
resource "aws_lb_target_group_attachment" "Instance-Attach2" {
target_group_arn = aws_lb_target_group.test-target-group.arn
target_id = aws_instance.Instance2.id ## Instance 2
port = 80 ## listening to the port 80
}
\*** target_group_arn*
The ARN of the target group with which to register targets.
Step 14:
Attach a Listenr to the Load balancer.
Before you start using your Application Load Balancer, you must add one or more listeners. A listener is a process that checks for connection requests, using the protocol and port that you configure. The rules that you define for a listener determine how the load balancer routes requests to its registered targets.
## Alb Listener
resource "aws_lb_listener" "Alb_Listener" {
load_balancer_arn = aws_lb.test_aplb.arn ## load balancer arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.test-target-group.arn ## target group arn
}
}
Step 15:
Create another file as output.tf and print the load balancer dns-name to get the dns url
output "load-balancer-dns" {
value = aws_lb.test_aplb.dns_name
}
So this is the whole main.tf file.....
resource "aws_vpc" "new_vpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "Aws-Vpc"
}
}
## Create the public subnet
resource "aws_subnet" "public_subnet1" {
vpc_id = aws_vpc.new_vpc.id
cidr_block = "10.0.1.0/24"
availability_zone ="us-east-1b"
map_public_ip_on_launch = true
tags = {
Name = "Public-Subnet1"
}
}
resource "aws_subnet" "public_subnet2" {
vpc_id = aws_vpc.new_vpc.id
cidr_block = "10.0.2.0/24"
availability_zone ="us-east-1a"
map_public_ip_on_launch = true
tags = {
Name = "Public-Subnet2"
}
}
## Create the internet-gateway
resource "aws_internet_gateway" "aws_igw" {
vpc_id = aws_vpc.new_vpc.id
tags = {
Name = "IGW"
}
}
## Create the route tabel
resource "aws_route_table" "RT" {
vpc_id = aws_vpc.new_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.aws_igw.id
}
tags = {
Name = "Aws-RT"
}
}
##Public route Table Association
resource "aws_route_table_association" "RTA1" {
subnet_id = aws_subnet.public_subnet1.id
route_table_id = aws_route_table.RT.id
}
resource "aws_route_table_association" "RTA2" {
subnet_id = aws_subnet.public_subnet2.id
route_table_id = aws_route_table.RT.id
}
## Create the security group
resource "aws_security_group" "mysg" {
name = "Aws-Security-Group"
description = "Allow TLS inbound traffic"
vpc_id = aws_vpc.new_vpc.id
ingress {
description = "TLS from VPC"
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"]
}
tags = {
Name = "my-sg"
}
}
## Create S3 bucker
resource "aws_s3_bucket" "s3-bucket" {
bucket = "terraform-project-aws-public-subnet"
}
## Create Ec2 instnace
resource "aws_instance" "Instance1" {
ami = "ami-053b0d53c279acc90"
instance_type ="t2.micro"
vpc_security_group_ids = [aws_security_group.mysg.id]
subnet_id = aws_subnet.public_subnet1.id
user_data = base64encode(file("userdata.sh"))
}
resource "aws_instance" "Instance2" {
ami = "ami-053b0d53c279acc90"
instance_type ="t2.micro"
vpc_security_group_ids = [aws_security_group.mysg.id]
subnet_id = aws_subnet.public_subnet2.id
user_data = base64encode(file("userdata1.sh"))
}
### Create the application load balancer
resource "aws_lb" "test_aplb" {
name = "test-alb-terraform"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.mysg.id]
subnets = [aws_subnet.public_subnet1.id, aws_subnet.public_subnet2.id]
tags = {
Name = "Alb-Project"
}
}
## Alb target group creation
resource "aws_lb_target_group" "test-target-group" {
name = "test-target-group"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.new_vpc.id
health_check {
path ="/"
port = "traffic-port"
}
}
## Load balancer Target group attachment::
resource "aws_lb_target_group_attachment" "Instance-Attach1" {
target_group_arn = aws_lb_target_group.test-target-group.arn
target_id = aws_instance.Instance1.id
port = 80
}
resource "aws_lb_target_group_attachment" "Instance-Attach2" {
target_group_arn = aws_lb_target_group.test-target-group.arn
target_id = aws_instance.Instance2.id
port = 80
}
## Alb Listener
resource "aws_lb_listener" "Alb_Listener" {
load_balancer_arn = aws_lb.test_aplb.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.test-target-group.arn
}
}
Step 16:
Run the terraform init command.

Step 17:
Check the blueprint of the resources as a pre-plan execution.
Run terraform plan command.
16 resources are going to be created and the DNS name will be generated after applying the command.

Now finally execute the terraform apply command.
terraform apply --auto-approve

Check the dns-name as the printed output

So this is the final output of this project,,
Copy the printed DNS name and paste it into the browser.

To get the load between two instances refresh the page repeatedly...

Please destroy the infra after the project execution whether through terraform or manually as the cost is included here ...
terraform destroy -auto-approve

Refer to the amazing terraform documentation it's very helpful to create any infrastructure.
This is the link
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/
Thank You For Reading ...๐


![AWS VPC Creation Using Terraform[ A Mini Project]](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1689934431510%2Ffb3ca82c-ada0-4f86-9223-80890ea51459.avif&w=3840&q=75)