I’ve updated configuration to include variables, locals, and output. Now it’s time to update the architecture of deployment to include resiliency by adding new resources.
Our current architecture is using a single subnet in a single AZ with a single EC2 instance. That’s a lot of single point of failure. To improve reliability of the deployment, I’ll start by:
- Add a second availability zone
- Add a second EC2 instance
- Add load balancing for instances
- Maintain readability of code
Add availability zone
Add data source for AZ on main.tf
data "aws_availability_zones" "available" {
state = "available"
}
Add a new argument for the AZ on aws_subnet
resource and subnet.
resource "aws_subnet" "subnet1" {
cidr_block = var.vpc_subnets_cidr_block[0]
vpc_id = aws_vpc.vpc.id
map_public_ip_on_launch = var.map_public_ip_on_launch
# Add new argument
availability_zone = data.aws_availability_zones.available.names[0]
tags = local.common_tags
}
resource "aws_subnet" "subnet2" {
cidr_block = var.vpc_subnets_cidr_block[1]
vpc_id = aws_vpc.vpc.id
map_public_ip_on_launch = var.map_public_ip_on_launch
availability_zone = data.aws_availability_zones.available.names[1]
tags = local.common_tags
}
variable "vpc_subnets_cidr_block" {
# Change string to list()
type = list(string)
description = "CIDR Block for Subnets in VPC"
# Use list to add subnet
default = ["10.0.0.0/24", "10.0.1.0/24"]
}
Add route table associations
# Copy existing route table resource, then change the name label to "rta-subnet2" and subnet_id reference to subnet2
# Both of theses subnets are going to use the same route table.
resource "aws_route_table_association" "rta-subnet2" {
subnet_id = aws_subnet.subnet2.id
route_table_id = aws_route_table.rtb.id
}
Add Second EC2 instance
Add aws_instance
resource and modify subnet id and label name.
# INSTANCES #
resource "aws_instance" "nginx1" {
ami = data.aws_ssm_parameter.ami.value
instance_type = var.instance_type
subnet_id = aws_subnet.subnet1.id
vpc_security_group_ids = [aws_security_group.nginx-sg.id]
user_data = <<EOF
#! /bin/bash
sudo amazon-linux-extras install -y nginx1
sudo service nginx start
sudo rm /usr/share/nginx/html/index.html
echo '<html><head><title>Taco Team Server 1</title></head><body style=\"background-color:#1F778D\"><p style=\"text-align: center;\"><span style=\"color:#FFFFFF;\"><span style=\"font-size:28px;\">You did it! Have a 🌮</span></span></p></body></html>' | sudo tee /usr/share/nginx/html/index.html
EOF
tags = local.common_tags
}
# INSTANCES #
resource "aws_instance" "nginx2" {
ami = data.aws_ssm_parameter.ami.value
instance_type = var.instance_type
subnet_id = aws_subnet.subnet2.id
vpc_security_group_ids = [aws_security_group.nginx-sg.id]
user_data = <<EOF
#! /bin/bash
sudo amazon-linux-extras install -y nginx1
sudo service nginx start
sudo rm /usr/share/nginx/html/index.html
echo '<html><head><title>Taco Team Server 2</title></head><body style=\"background-color:#1F778D\"><p style=\"text-align: center;\"><span style=\"color:#FFFFFF;\"><span style=\"font-size:28px;\">You did it! Have a 🌮</span></span></p></body></html>' | sudo tee /usr/share/nginx/html/index.html
EOF
tags = local.common_tags
}
Add load balancing for instances
I’ll update the name label of security group to alb_sg and allow traffic from addresses that are in the vpc_cidr_block.
resource "aws_security_group" "alb_sg" {
name = "nginx_alb_sg"
vpc_id = aws_vpc.vpc.id
# HTTP access from anywhere
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = [var.vpc_cidr_block]
}
# outbound internet access
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = local.common_tags
}
The next thing to do is add our load balancer resources. We need to construct each of those resources.
Search for the aws load balancing in the Terraform docs page, and copy a example of load balancer resource
resource "aws_lb" "test" {
name = "test-lb-tf"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.lb_sg.id]
subnets = [for subnet in aws_subnet.public : subnet.id]
enable_deletion_protection = true
access_logs {
bucket = aws_s3_bucket.lb_logs.bucket
prefix = "test-lb"
enabled = true
}
tags = {
Environment = "production"
}
}
update the name label and the name of our load balancer
resource "aws_lb" "nginx" {
name = "globo_web_alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb_sg.id] // update correct security group name label
subnets = [aws_subnet.subnet1.id, aws_subnet.subnet2.id] // both of the subnets are associated with load balancer
enable_deletion_protection = false // I want to delete this load balancer when I'm done with it.
tags = local.common_tags // use local value
}
Add load balancer target group
resource "aws_lb_target_group" "nginx" {
name = "nginx-alb-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.vpc.id
tags = local.common_tags
}
Add the aws_lb_listener
which needs to reference the ARN of the load balancer. Set the proper port and protocol, and the default_action
resource "aws_lb_listener" "nginx" {
load_balancer_arn = aws_lb.nginx.arn
port = 80
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.nginx.arn
}
tags = local.common_tags
}
Add two target group attachments
resource "aws_lb_target_group_attachment" "nginx1" {
target_group_arn = aws_lb_target_group.nginx.arn
target_id = aws_instance.nginx1.id
port = 80
}
resource "aws_lb_target_group_attachment" "nginx2" {
target_group_arn = aws_lb_target_group.nginx.arn
target_id = aws_instance.nginx2.id
port = 80
}
Final
resource "aws_lb" "nginx" {
name = "globo_web_alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb_sg.id] // update correct security group name label
subnets = [aws_subnet.subnet1.id, aws_subnet.subnet2.id] // both of the subnets are associated with load balancer
enable_deletion_protection = false // I want to delete this load balancer when I'm done with it.
tags = local.common_tags // use local value
}
## aws_lb_target_group
resource "aws_lb_target_group" "nginx" {
name = "nginx-alb-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.vpc.id
tags = local.common_tags
}
## aws_lb_listener
resource "aws_lb_listener" "nginx" {
load_balancer_arn = aws_lb.nginx.arn
port = 80
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.nginx.arn
}
tags = local.common_tags
}
## aws_lb_target_group_attachment
resource "aws_lb_target_group_attachment" "nginx1" {
target_group_arn = aws_lb_target_group.nginx.arn
target_id = aws_instance.nginx1.id
port = 80
}
resource "aws_lb_target_group_attachment" "nginx2" {
target_group_arn = aws_lb_target_group.nginx.arn
target_id = aws_instance.nginx2.id
port = 80
}