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:

  1. Version Control: Every infrastructure change is tracked
  2. Repeatability: Same setup every time
  3. Documentation: The code itself documents our infrastructure
  4. 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 📚

  1. Start Small: Build one module at a time
  2. Test Everything: Use terraform plan religiously
  3. Use Workspaces: Keep environments separate
  4. 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! 🌱