Deploying a Highly Available Web Application on AWS with Terraform: A Step-by-Step Guide
As organizations embrace cloud-native technologies, one of the critical components for achieving scalability and efficiency is implementing Infrastructure as Code (IaC). Among the many tools available, Terraform has gained significant popularity for provisioning infrastructure across various cloud providers. This blog post will delve into how to deploy a highly available and scalable web application on AWS using Terraform. We’ll walk through the steps required, provide necessary code snippets, and share best practices to ensure a robust infrastructure setup.
Why Terraform?
Terraform is an open-source IaC tool developed by HashiCorp. It enables you to define cloud infrastructure in declarative configuration files. With Terraform, you can provision, update, and version your infrastructure safely and efficiently, taking advantage of its state management and extensive support for multiple cloud platforms.
Setting Up Your Environment
Before you start, ensure you have the following prerequisites:
- AWS account with necessary permissions
- Terraform installed on your machine (version 0.13 or later)
- Basic knowledge of AWS services like EC2, VPC, and Auto Scaling groups
Step-by-Step Guide to Deploy a Web Application Using Terraform
1. Configure AWS Access
Configure AWS CLI with your credentials. Run the following command and follow the prompts:
aws configure
2. Define Provider Configuration
Create a directory for your Terraform configuration files. In this directory, create a file named main.tf
and define the provider configuration:
provider "aws" {
region = "us-west-2"
}
3. Create a VPC
A Virtual Private Cloud (VPC) will host your infrastructure. Add the following code to main.tf
to create a VPC:
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "main_vpc"
}
}
4. Create Subnets
Create public and private subnets within the VPC:
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
map_public_ip_on_launch = true
availability_zone = "us-west-2a"
tags = {
Name = "public_subnet"
}
}
resource "aws_subnet" "private" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.2.0/24"
availability_zone = "us-west-2a"
tags = {
Name = "private_subnet"
}
}
5. Create an Internet Gateway
Public subnets require an Internet Gateway for outbound traffic:
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "main_igw"
}
}
6. Create Route Tables
Associate the Internet Gateway with the public subnet routing table:
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
tags = {
Name = "public_rt"
}
}
resource "aws_route_table_association" "public_assoc" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
7. Create Security Groups
Define security groups to control inbound and outbound traffic:
resource "aws_security_group" "web_sg" {
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
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"]
}
tags = {
Name = "web_sg"
}
}
8. Launch EC2 Instances
Use an Auto Scaling group to ensure high availability and scalability:
resource "aws_launch_configuration" "web_lc" {
name = "web-launch-configuration"
image_id = "ami-0c55b159cbfafe1f0" // Amazon Linux 2 AMI
instance_type = "t2.micro"
security_groups = [aws_security_group.web_sg.id]
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "Hello, World" > /var/www/html/index.html
EOF
lifecycle {
create_before_destroy = true
}
}
resource "aws_autoscaling_group" "web_asg" {
launch_configuration = aws_launch_configuration.web_lc.id
min_size = 2
max_size = 5
desired_capacity = 2
vpc_zone_identifier = [aws_subnet.public.id]
tag {
key = "Name"
value = "web_asg_instance"
propagate_at_launch = true
}
lifecycle {
create_before_destroy = true
}
}
9. Output the Application URL
Finally, output the application URL for easy access:
output "app_url" {
value = "http://${aws_autoscaling_group.web_asg.instances[0].public_dns}"
}
Deploying Your Infrastructure
With your Terraform configuration ready, follow these steps to deploy your infrastructure:
1. Initialize Terraform
terraform init
2. Create an Execution Plan
terraform plan
3. Apply the Changes
terraform apply
Best Practices and Lessons Learned
1. Maintain State Files Securely
Store Terraform state files in a remote backend like AWS S3 with state locking enabled to prevent concurrent edits.
2. Modularize Configurations
Break down your Terraform configurations into reusable modules for better organization and maintainability.
3. Use Version Control
Track changes to your Terraform configuration files using a version control system like Git to ensure auditability and collaboration.
4. Validate Configurations
Regularly validate your configurations using terraform validate
and apply linting tools to maintain code quality.
Conclusion
Terraform empowers teams to manage and provision infrastructure efficiently by adopting Infrastructure as Code. By following this guide, you can deploy a highly available and scalable web application on AWS with ease. Have you utilized Terraform in your cloud-native projects? Share your experiences and tips in the comments below!