
marvintowettToday we will be looking at deploying a cluster of web servers. To make all this possible we are...
Today we will be looking at deploying a cluster of web servers. To make all this possible we are going to employ the use of the following AWS technologies:
Auto Scaling Group handles:
Creating an ASG:
In order to create an ASG you must first create a launch configuration that specifies how to configure each EC2 instance in the ASG
This Terraform configuration creates an Auto Scaling group with a launch configuration that sets up a simple HTTP server using BusyBox. The server listens on a port defined by the server_port variable, which defaults to 8080. The security group allows incoming traffic on the specified port from any IP address.
resource "aws_launch_configuration" "example" {
image_id = "ami-0735c191cf914754d"
instance_type = "t2.micro"
security_groups = [aws_security_group.instance.id]
user_data = <<-EOF
#!/bin/bash
echo "Hello, World" > index.html
nohup busybox httpd -f -p ${var.server_port} &
EOF
// Ensure that the new launch configuration is created before the old one is destroyed
lifecycle {
create_before_destroy = true
}
}
We added lifecycle block. this ensures that when updating/creating a new EC2 instance, Terraform will first create the new instance update then delete the old instance
For this ASG to work we need to add another value subnet_ids.
This parameter specifies which subnet the EC2 instances should be deployed to the ASG.
Each subnet lives in an isolated AWS Availability Zone (AWS AZ) to ensure your instances keep running even if some of the data centres have an outage
In order to get the ips of each subnet we are going to use data sources.
A data sources represents a piece of read-only information that is fetched from the provider whenever you run Terraform.
Data source is used to simply query information from the providers IP.
The Syntax for using a data source:
data "<PROVIDER_NAME>_<TYPE>" "<NAME>" {
[CONFIG ...]
}
We will go ahead and look up data for our Default VPC and then combine that with another data source aws_subnets to look upthe subnets within the VPC.
// Data sources to get the default VPC
data "aws_vpc" "default" {
default = true
}
// Get the subnets in the default VPC
data "aws_subnets" "default" {
filter {
name = "vpc-id"
values = [data.aws_vpc.default.id]
}
}
Now we can pull the Ids out of the aws_subnets required by the ASG.
// Create an Auto Scaling group that uses the launch configuration
resource "aws_autoscaling_group" "example" {
launch_configuration = aws_launch_configuration.example.name
vpc_zone_identifier = data.aws_subnets.default.ids
min_size = 2
max_size = 10
tag{
key = "Name"
value = "mk-terraform-instance"
propagate_at_launch = true
}
}
A Load balance is a server that distributes traffic across your server while using the load balancer's IP.
we have 3 types of Load balancers:
For this example since we are deploying a simple server we will be using ALB Application Load Balancer.
To create a load balance we will use the aws_lb resource.
resource "aws_lb" "example" {
name = "terraform-asg-example"
load_balancer_type = "application"
subnets = data.aws_subnets.default.ids
}
Our load balancer is configured to use all subnets.
Now we need to configure listeners to the loab balancer using the aws_lb_listener resource.
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.example.arn
port = var.http_port
protocol = "HTTP"
// Set up a fixed response for any requests that do not match the target group
default_action {
type = "fixed-response"
fixed_response {
content_type = "text/plain"
message_body = "${var.status_code}: Page Not Found"
status_code = var.status_code
}
}
}
The listener above is configured to listen to default port 80, use the HTTP protocol and send 404 page for request that don't match listeners rules.
Now we will need to create a new security group for our ASG since AWS does not allow any incoming or outgoing traffic by default.
resource "aws_security_group" "alb" {
name = "mk-terraform-alb-security-group"
// Allow incoming traffic on the HTTP port from any IP address
ingress{
from_port = var.http_port
to_port = var.http_port
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
// Allow all outbound traffic from the load balancer
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
The next Step is now to pass this security group in the
security_group arguments of our load balance.
// Create an Application Load Balancer to distribute traffic to the instances in the Auto Scaling group
resource "aws_lb" "example" {
name = "terraform-asg-example"
load_balancer_type = "application"
subnets = data.aws_subnets.default.ids
security_groups = [aws_security_group.alb.id]
}
Next we will have to create a target group for our ASG using the aws_b_target_group resource. a target group is a part of the ASG that receives request from the load balancer. it also performs health checks on the server and sends request to healthy nodes only.
// Create a target group for the Auto Scaling group instances
resource "aws_lb_target_group" "asg" {
name = "terraform-asg-example"
port = var.server_port
protocol = "HTTP"
vpc_id = data.aws_vpc.default.id
health_check {
path = "/"
protocol = "HTTP"
matcher = "200"
interval = 15
timeout = 3
healthy_threshold = 2
unhealthy_threshold = 2
}
}
The target groups sends request to EC2 Instance by setting target_group_arns in the aws_autoscaling_group resource.
// Create an Auto Scaling group that uses the launch configuration
resource "aws_autoscaling_group" "example" {
launch_configuration = aws_launch_configuration.example.name
vpc_zone_identifier = data.aws_subnets.default.ids
target_group_arns = [aws_lb_target_group.asg.arn]
health_check_type = "ELB"
min_size = 2
max_size = 10
tag{
key = "Name"
value = "mk-terraform-instance"
propagate_at_launch = true
}
}
Note: we updated the health_check_type to "ELB" health check as it is more robust and instructs ASG to use the target group health check to determine whether an instance is healthy.
Finally, we create a listener_rule. This is the last part of the ASG we need to configure. The Listener Rule takes a request that's come in and send's those that match specific paths or hostnames to specific target_group.
// Create a listener rule that forwards traffic to the target group for the Auto Scaling group instances
resource "aws_lb_listener_rule" "asg" {
listener_arn = aws_lb_listener.http.arn
priority = 100
// Forward traffic to the target group for the Auto Scaling group instances if the path is "/"
condition {
path_pattern {
values = ["/"]
}
}
// Forward traffic to the target group for the Auto Scaling group instances
action {
type = "forward"
target_group_arn = aws_lb_target_group.asg.arn
}
}