Terraform: Deploying a 2-Tier Architecture
Scenario
Deploying a 2-tier architecture that includes all our code in a single main.tf file (known as a monolith) with hardcoded data.
Step 1: Create main.tf-
The file that will be used here is the main.tf file (Note: the “.tf” extension allows terraform to track the file).
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
# Configure the AWS Provider
provider "aws" {
region = "us-west-2"
}
Step 2: Create VPC (Virtual Private Cloud) and subnets
We will be creating the VPC, 2 public subnets and 2 private subnets. The public and private subnets will be in different availability zones
#Create VPC
resource "aws_vpc" "my_vpc" {
cidr_block = "10.0.0.0/16"
instance_tenancy = "default"
tags = {
Name = "my_vpc"
}
}
#Create Public subnet #1
resource "aws_subnet" "Public_sub2a" {
vpc_id = aws_vpc.my_vpc.id
cidr_block = "10.0.1.0/24"
map_public_ip_on_launch = true
availability_zone = "us-west-2a"
tags = {
Name = "Public_sub2a"
}
}
#Create Public subnet #2
resource "aws_subnet" "Public_sub2b" {
vpc_id = aws_vpc.my_vpc.id
cidr_block = "10.0.2.0/24"
map_public_ip_on_launch = true
availability_zone = "us-west-2b"
tags = {
Name = "Public_sub2b"
}
}
#Create Private subnet #1
resource "aws_subnet" "db_private_sub2a" {
vpc_id = aws_vpc.my_vpc.id
cidr_block = "10.0.3.0/24"
map_public_ip_on_launch = false
availability_zone = "us-west-2a"
tags = {
Name = "Db_Private_sub2a"
}
}
#Create Private subnet #2
resource "aws_subnet" "Private_sub2b" {
vpc_id = aws_vpc.my_vpc.id
cidr_block = "10.0.4.0/24"
availability_zone = "us-west-2b"
tags = {
Name = "Private_sub2b"
}
}
Step 3: Create a Route table and Internet gateway
The next step would be to create the internet gateway and the routing table for the public subnets. The route specified shows traffic would go out to the internet via the internet gateway
#Create Internet gateway
resource "aws_internet_gateway" "my_igw" {
vpc_id = aws_vpc.my_vpc.id
tags = {
Name = "main_IGW"
}
}
#Create Route Table for Public Subnets
resource "aws_route_table" "my_rt_table" {
vpc_id = aws_vpc.my_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.my_igw.id
}
tags = {
Name = "My_Route_Table"
}
}
Step 4: Association of Public subnets to the routing table
Here we have to specify the subnet id for each public subnet and the route table id.
#Associate public subnets with routing table
resource "aws_route_table_association" "Public_sub1_Route_Association" {
subnet_id = aws_subnet.Public_sub2a.id
route_table_id = aws_route_table.my_rt_table.id
}
resource "aws_route_table_association" "Public_sub2_Route_Association" {
subnet_id = aws_subnet.Public_sub2b.id
route_table_id = aws_route_table.my_rt_table.id
}
Step 5: Create security groups for VPC and RDS MySQL instance
It is important we get our security groups set up rightly to allow inbound traffic into the instances that would be launched in the public subnets. The security groups for both the VPC and RDS MySQL instance will be set up.
#Create Security group for VPC
resource "aws_security_group" "my_vpc_sg" {
name = "my_vpc_sg"
description = "Allow inbound traffic to instance"
vpc_id = aws_vpc.my_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"]
}
}
#Create a Security group for Database server
resource "aws_security_group" "db_sg" {
name = "db_sg"
description = "Allows inbound traffic"
vpc_id = aws_vpc.my_vpc.id
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
security_groups = [aws_security_group.my_vpc_sg.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Step 6: Create a target group and Loadbalancer
Next, we will create the Application load balancer and the target group. The load balancer is listening on port 80 and the target group must also have port 80 specified.
#Create an ALB target group
resource "aws_lb_target_group" "alb-TG" {
name = "alb-TG"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.my_vpc.id
}
#Create Load balancer
resource "aws_lb" "my-aws-alb" {
name = "my-aws-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.my_vpc_sg.id]
subnets = [aws_subnet.Public_sub2a.id, aws_subnet.Public_sub2b.id]
}
# Create Load balancer listner rule
resource "aws_lb_listener" "lb_lst" {
load_balancer_arn = aws_lb.my-aws-alb.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.alb-TG.arn
}
}
#Load balancer-Target group attachment
resource "aws_lb_target_group_attachment" "my-aws-alb" {
target_group_arn = aws_lb_target_group.alb-TG.arn
target_id = aws_instance.Pub2a_ec2.id
port = 80
}
#Load balancer-Target group attachment
resource "aws_lb_target_group_attachment" "my-aws-alb2" {
target_group_arn = aws_lb_target_group.alb-TG.arn
target_id = aws_instance.Pub2b_ec2.id
port = 80
}
Step 7: Create ec2 instances and database instance
Now we will create the ec2 and database instances and also do some bootstrapping in our ec2 instances.
#Create EC2 instances in public subnets
resource "aws_instance" "Pub2a_ec2" {
ami = "ami-00448a337adc93c05"
instance_type = "t2.micro"
associate_public_ip_address = true
subnet_id = aws_subnet.Public_sub2a.id
security_groups = [aws_security_group.my_vpc_sg.id]
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Code finally Worked!!!</h1>" > var/www/html/index.html
EOF
}
resource "aws_instance" "Pub2b_ec2" {
ami = "ami-00448a337adc93c05"
instance_type = "t2.micro"
associate_public_ip_address = true
subnet_id = aws_subnet.Public_sub2b.id
security_groups = [aws_security_group.my_vpc_sg.id]
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Welcome to 2-Tier Architecture Project!!!</h1>" > var/www/html/index.html
EOF
}
# Create a Database instance
resource "aws_db_instance" "db_instance" {
allocated_storage = 10
db_name = "my_private_db"
engine = "mysql"
engine_version = "5.7"
instance_class = "db.t2.micro"
username = "projectTerraform"
password = "Terraform1234"
parameter_group_name = "default.mysql5.7"
db_subnet_group_name = "db_sub_grp"
vpc_security_group_ids = [aws_security_group.my_vpc_sg.id]
skip_final_snapshot = true
availability_zone = "us-west-2b"
}
#Create RDS instance subnet group
resource "aws_db_subnet_group" "db_sub_grp" {
name = "db_sub_grp"
subnet_ids = [aws_subnet.db_private_sub2a.id, aws_subnet.Private_sub2b.id]
}
Now, we need run below commands
$terraform init
This command prepares the current working directory for terraform to run the configuration
Next command
$terraform validate
The code is literally a lifesaver as it validates your configuration, pointing out any errors or unspecified attributes in your resource blocks. I got that so many times after running the code severally. Now our configuration is super valid.
领英推荐
After that, we will run
$terraform plan
This basically shows a plan for every resource that is to be executed/deployed. It allows you to review the plan before executing the configuration.
finally,
$terraform apply
This takes action on the terraform configuration to create the resources
After running it to completion, we have 20 resources added.
Let’s navigate to the AWS console to see what we spun up. I’ll show a few of them,
VPC
Subnets
EC2
RDS
now, browse your load balancer ARN/URL
Finally, we will have to take down everything we have created using the command below,
$terraform destroy
Thank you for reading. I hope you found this article helpful.
Happy Learning :-)
Mounika Jilakari.