DEV Community

Haripriya Veluchamy
Haripriya Veluchamy

Posted on

Building AWS Infrastructure with Terraform: A Deep Dive into Our Jira Clone Setup πŸ—οΈ

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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"]
}
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

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 


Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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]
}
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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! 🌱


Top comments (0)