Hey cloud enthusiasts! In my last post, I walked you through the flow of our Jira clone deployment. Today, let's dive deep into the infrastructure and how we're managing it all with Terraform. Grab your coffee ☕ - we're about to get technical!
Why Terraform? The Infrastructure as Code Journey 🤔
When I started this project, I had two options: manually click through the AWS console or use Infrastructure as Code (IaC). Here's why I chose Terraform:
- Version Control: Every infrastructure change is tracked
- Repeatability: Same setup every time
- Documentation: The code itself documents our infrastructure
- Collaboration: Team members can understand and contribute easily
Breaking Down Our Infrastructure 🔍
First Things First: State Management 📦
terraform {
backend "s3" {
bucket = "zscrum-terraform-state"
key = "dev/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}
Why this setup? Because:
- S3 is reliable and secure for state storage
- DynamoDB prevents concurrent modifications
- Encryption keeps our state file secure
Networking: The Foundation 🌐
Remember our "virtual city" from the last post? Here's how we build it:
module "vpc" {
source = "./modules/vpc"
vpc_cidr = "10.0.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b"]
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnets = ["10.0.3.0/24", "10.0.4.0/24"]
}
We split our network into:
- Public subnets for load balancers
- Private subnets for our containers
- NAT Gateways for private subnet internet access
Load Balancer: The Traffic Director 🚦
module "alb" {
source = "./modules/alb"
vpc_id = module.vpc.vpc_id
public_subnets = module.vpc.public_subnet_ids
certificate_arn = module.acm.certificate_arn
health_check = {
path = "/api/health"
healthy_threshold = 2
unhealthy_threshold = 10
}
}
Our ALB configuration ensures:
- Health checks detect issues quickly
- SSL termination at the load balancer
- Smart traffic distribution
Container Infrastructure: Building and Deploying 🐳
First, let's look at our Dockerfile that packages our application:
# Base image
FROM node:18-alpine
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy application files
COPY . .
# Build the application
RUN npm run build
# Expose port
EXPOSE 3000
# Start the application
CMD ["npm", "start"]
To automate our container builds and pushes to ECR, I created a handy shell script (let's call it deploy-ecr.sh
):
#!/bin/bash
set -e
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
#for full code refer github
This script handles everything from building to pushing our container image. Simply run it with:
./deploy-ecr.sh -a your-aws-account -r your-region -e your-repo-name
Now, let's look at how we manage our containers with Terraform:
module "ecs" {
source = "./modules/ecs"
cluster_name = "zscrum-cluster"
task_cpu = 256
task_memory = 512
container_port = 3000
desired_count = 1
private_subnet_ids = module.vpc.private_subnet_ids
security_groups = [module.security.ecs_sg_id]
}
Why these choices?
- Fargate for serverless container management
- Right-sized resources for our app
- Auto-scaling ready
Security: Defense in Depth 🔒
Security is implemented through multiple modules:
module "security" {
source = "./modules/security"
vpc_id = module.vpc.vpc_id
alb_sg = module.alb.security_group_id
# Parameter Store for sensitive data
parameters = {
database_url = "secure-string"
clerk_key = "secure-string"
}
}
Key security features:
- Tight security group rules
- Encrypted parameters
- IAM roles with minimal permissions
Monitoring: Eyes on Everything 👀
module "monitoring" {
source = "./modules/monitoring"
log_retention_days = 30
alarm_sns_topic = module.sns.topic_arn
containers_to_monitor = {
app = module.ecs.container_name
}
}
This gives us:
- CloudWatch Log Groups
- Performance metrics
- Alert notifications
The Power of Modules 🔧
Our Terraform structure:
terraform/
├── modules/
│ ├── network/
│ ├── alb/
│ ├── ecs/
│ ├── cdn/
│
├── environments/
│ ├── dev/
│ └── prod/
└── variables.tf
Why this structure?
- Reusable components
- Environment isolation
- Easy maintenance
Cost Optimization Strategies 💰
We're smart about costs:
- Right-sized containers
- Auto-scaling limits
- Reserved NAT Gateway instances
- CloudFront caching optimization
Lessons Learned 📚
- Start Small: Build one module at a time
-
Test Everything: Use
terraform plan
religiously - Use Workspaces: Keep environments separate
- Document As You Go: Your future self will thank you
Want to Try This Yourself? 🚀
Head over to my GitHub repo where I've shared the complete Terraform setup. And don't forget to check out Piyush's original Jira Clone that made this all possible!
Questions? Comments? 💭
Drop them below! I'd love to hear about your infrastructure adventures and help where I can.
Remember: Infrastructure as Code is a journey. Start small, learn continuously, and don't be afraid to make mistakes - that's how we all learn! 🌱