Infrastructure as Code: Building a Production-Ready AWS Environment with Terraform
A comprehensive guide to setting up a production-ready AWS infrastructure using Terraform, including ECS clusters, RDS instances, Application Load Balancers, and automated CI/CD pipelines with CodeCommit.
Terraform
AWS
ECS
RDS
Load Balancer
CodeCommit
CI/CD
Infrastructure as Code
Introduction to Infrastructure as Code with Terraform
In this guide, we'll explore how to use Terraform to create a production-ready AWS infrastructure. We'll set up an ECS cluster for container orchestration, RDS for database management, Application Load Balancer for traffic distribution, and a CI/CD pipeline using AWS CodeCommit.
Project Structure and Prerequisites
# Project structure
.
├── environments/
│ ├── prod/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ └── staging/
├── modules/
│ ├── ecs/
│ ├── rds/
│ ├── alb/
│ └── pipeline/
└── versions.tf
# versions.tf
terraform {
required_version = ">= 1.0.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
Setting up the ECS Cluster
First, let's create an ECS cluster with Fargate launch type for running containerized applications. We'll set up the necessary networking components and security groups.
领英推è
# modules/ecs/main.tf
resource "aws_ecs_cluster" "main" {
name = var.cluster_name
setting {
name = "containerInsights"
value = "enabled"
}
tags = var.tags
}
resource "aws_ecs_task_definition" "app" {
family = var.app_name
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = var.cpu
memory = var.memory
execution_role_arn = aws_iam_role.ecs_execution_role.arn
task_role_arn = aws_iam_role.ecs_task_role.arn
container_definitions = jsonencode([
{
name = var.app_name
image = var.container_image
essential = true
portMappings = [
{
containerPort = var.container_port
protocol = "tcp"
}
]
environment = var.environment_variables
logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = aws_cloudwatch_log_group.app.name
awslogs-region = var.aws_region
awslogs-stream-prefix = "ecs"
}
}
}
])
}
resource "aws_ecs_service" "app" {
name = var.app_name
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.app.arn
desired_count = var.service_desired_count
launch_type = "FARGATE"
network_configuration {
security_groups = [aws_security_group.ecs_tasks.id]
subnets = var.private_subnet_ids
assign_public_ip = false
}
load_balancer {
target_group_arn = var.target_group_arn
container_name = var.app_name
container_port = var.container_port
}
}
Configuring RDS Instance
Next, we'll set up an RDS instance in a private subnet with proper security groups and backup configurations.
# modules/rds/main.tf
resource "aws_db_subnet_group" "main" {
name = "${var.identifier}-subnet-group"
subnet_ids = var.subnet_ids
tags = var.tags
}
resource "aws_security_group" "rds" {
name = "${var.identifier}-rds-sg"
description = "Security group for RDS instance"
vpc_id = var.vpc_id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [var.ecs_security_group_id]
}
}
resource "aws_db_instance" "main" {
identifier = var.identifier
allocated_storage = var.allocated_storage
storage_type = "gp3"
engine = "postgres"
engine_version = var.engine_version
instance_class = var.instance_class
db_name = var.database_name
username = var.database_username
password = var.database_password
parameter_group_name = "default.postgres14"
vpc_security_group_ids = [aws_security_group.rds.id]
db_subnet_group_name = aws_db_subnet_group.main.name
backup_retention_period = 7
backup_window = "03:00-04:00"
maintenance_window = "Mon:04:00-Mon:05:00"
multi_az = var.environment == "production"
skip_final_snapshot = false
deletion_protection = true
tags = var.tags
}
Application Load Balancer Setup
The Application Load Balancer will distribute traffic across our ECS tasks and handle SSL termination.
# modules/alb/main.tf
resource "aws_lb" "main" {
name = var.alb_name
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = var.public_subnet_ids
enable_deletion_protection = true
tags = var.tags
}
resource "aws_lb_target_group" "app" {
name = var.app_name
port = var.container_port
protocol = "HTTP"
vpc_id = var.vpc_id
target_type = "ip"
health_check {
healthy_threshold = 3
interval = 30
protocol = "HTTP"
matcher = "200"
timeout = 5
path = var.health_check_path
unhealthy_threshold = 3
}
}
resource "aws_lb_listener" "https" {
load_balancer_arn = aws_lb.main.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = var.certificate_arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.app.arn
}
}
Setting up CodeCommit CI/CD Pipeline
Finally, we'll create a CI/CD pipeline using AWS CodeCommit, CodeBuild, and CodePipeline for automated deployments.
# modules/pipeline/main.tf
resource "aws_codecommit_repository" "app" {
repository_name = var.repository_name
description = "Application repository"
}
resource "aws_codebuild_project" "app" {
name = var.project_name
description = "Build project for ${var.project_name}"
build_timeout = "10"
service_role = aws_iam_role.codebuild.arn
artifacts {
type = "CODEPIPELINE"
}
environment {
compute_type = "BUILD_GENERAL1_SMALL"
image = "aws/codebuild/amazonlinux2-x86_64-standard:4.0"
type = "LINUX_CONTAINER"
image_pull_credentials_type = "CODEBUILD"
privileged_mode = true
environment_variable {
name = "AWS_DEFAULT_REGION"
value = var.aws_region
}
}
source {
type = "CODEPIPELINE"
buildspec = "buildspec.yml"
}
}
resource "aws_codepipeline" "app" {
name = var.pipeline_name
role_arn = aws_iam_role.codepipeline.arn
artifact_store {
location = aws_s3_bucket.artifacts.bucket
type = "S3"
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
owner = "AWS"
provider = "CodeCommit"
version = "1"
output_artifacts = ["source_output"]
configuration = {
RepositoryName = aws_codecommit_repository.app.repository_name
BranchName = var.branch_name
}
}
}
stage {
name = "Build"
action {
name = "Build"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
input_artifacts = ["source_output"]
version = "1"
configuration = {
ProjectName = aws_codebuild_project.app.name
}
}
}
stage {
name = "Deploy"
action {
name = "Deploy"
category = "Deploy"
owner = "AWS"
provider = "ECS"
input_artifacts = ["build_output"]
version = "1"
configuration = {
ClusterName = var.ecs_cluster_name
ServiceName = var.ecs_service_name
}
}
}
}
Putting It All Together
Now let's see how to combine all these modules to create a complete infrastructure.
# environments/prod/main.tf
module "ecs" {
source = "../../modules/ecs"
cluster_name = "production-cluster"
app_name = "my-application"
container_image = "${var.ecr_repository_url}:latest"
vpc_id = module.vpc.vpc_id
private_subnet_ids = module.vpc.private_subnet_ids
target_group_arn = module.alb.target_group_arn
tags = var.tags
}
module "rds" {
source = "../../modules/rds"
identifier = "production-db"
allocated_storage = 100
instance_class = "db.t3.large"
database_name = "appdb"
database_username = var.db_username
database_password = var.db_password
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.database_subnet_ids
ecs_security_group_id = module.ecs.ecs_security_group_id
environment = "production"
tags = var.tags
}
module "alb" {
source = "../../modules/alb"
alb_name = "production-alb"
vpc_id = module.vpc.vpc_id
public_subnet_ids = module.vpc.public_subnet_ids
certificate_arn = var.certificate_arn
tags = var.tags
}
module "pipeline" {
source = "../../modules/pipeline"
repository_name = "my-application"
project_name = "my-application-build"
pipeline_name = "my-application-pipeline"
branch_name = "main"
ecs_cluster_name = module.ecs.cluster_name
ecs_service_name = module.ecs.service_name
tags = var.tags
}
Security Best Practices
- Use KMS encryption for sensitive data
- Implement proper IAM roles with least privilege
- Enable VPC flow logs for network monitoring
- Use security groups to restrict access
- Enable encryption at rest for RDS
- Implement proper backup and disaster recovery
Monitoring and Maintenance
- Set up CloudWatch alarms for key metrics
- Enable ECS container insights
- Configure RDS enhanced monitoring
- Implement proper logging and tracing
- Set up automated backups
- Plan for regular maintenance windows
This infrastructure setup provides a solid foundation for running containerized applications in AWS. The combination of ECS, RDS, and Application Load Balancer, along with the automated CI/CD pipeline, creates a robust and scalable environment suitable for production workloads. Remember to adjust the configurations based on your specific requirements and always follow AWS best practices for security and performance.
https://www.dhirubhai.net/feed/update/urn:li:activity:7294550665828175872/