portfolio / devops / cloud infrastructure
← Back to Portfolio

End-to-End Cloud
Deployment on AWS ECS

Provisioned a production-grade containerized application on AWS Fargate with full CI/CD automation, infrastructure as code, and GitOps — built from scratch in under 72 hours.

AWS ECS Fargate Terraform Docker Jenkins GitHub Actions CI/CD GitOps ECR ALB CloudWatch
45 AWS Resources
Provisioned
99.9% Availability
Under Load
2 CI/CD Pipelines
Implemented
32s Pipeline Build
Duration
01

Architecture

Developer Push ────────────────────────────────────────────────────── │ ▼ GitHub (main branch) ──webhook──▶ Jenkins EC2 (t3.small / Amazon Linux 2023) GitHub (gitops branch) ──OIDC──────▶ GitHub Actions (ubuntu-latest runner) │ │ └──────────────── both pipelines ──────────┘ │ ┌─────────────┼─────────────┐ ▼ ▼ ▼ docker build ECR push ECS update │ │ │ └─────────────┴─────────────┘ │ ▼ ALB (Application Load Balancer) ├── / ──▶ ECS Frontend Service (React / Fargate) └── /api/* ──▶ ECS Backend Service (Express / Fargate)
Key design decision: Both services run in private subnets with no public IP. All traffic enters through the ALB in the public subnet, which handles path-based routing between frontend and backend — a pattern that mirrors production-grade architectures.
02

What I Built

01
Infrastructure as Code — Terraform
Wrote ten modular Terraform files provisioning a complete AWS environment: custom VPC with public/private subnets across two AZs, NAT gateway, internet gateway, ALB with path-based routing, ECS cluster, Fargate task definitions, ECR repositories with lifecycle policies, IAM roles, security groups, and a Jenkins EC2 instance with Elastic IP.
terraform vpc ecs fargate iam ecr alb
02
Containerization — Docker
Containerized a React frontend and Express backend with separate Dockerfiles. Debugged a Node.js version compatibility issue where Node 18 broke the React build due to a postcss-safe-parser incompatibility — resolved by pinning to Node 16, which matched the project's lockfile.
docker node.js react express
03
Jenkins CI/CD Pipeline
Deployed Jenkins as a Docker container on an EC2 instance with Docker-in-Docker support. Wrote a declarative Jenkinsfile with five stages: checkout, Docker build, ECR authentication, image push, and ECS service update. Configured GitHub webhook for automatic pipeline triggers on every push.
jenkins groovy webhooks ecr auth
04
GitOps with GitHub Actions & OIDC
Implemented a parallel GitOps deployment workflow on a separate branch using GitHub Actions. Configured AWS OIDC identity federation so the pipeline authenticates using short-lived tokens rather than stored credentials — a more secure pattern than traditional access key injection.
github actions oidc iam roles zero secrets
05
Auto Scaling & Load Testing
Configured CPU-based auto scaling for both ECS services (min 1, max 4 tasks, 50% CPU threshold). Validated with a siege load test at 250 concurrent users for 2 minutes, achieving 99.86% availability and 141 transactions/second. Verified CloudWatch scale-in and scale-out alarms.
auto scaling cloudwatch siege load testing
03

Problems I Solved

Real-world troubleshooting is where engineering skill shows. Here's what I ran into and how I resolved it.

ISSUE GitHub rejected a push due to a 685MB Terraform provider binary tracked in git history — even after deleting the folder locally.
RESOLVED Used git filter-branch to rewrite commit history and permanently remove the binary. Updated .gitignore with **/.terraform/ and force-pushed the cleaned history.
ISSUE Jenkins pipeline SSH connection to GitHub failed with "Host key verification failed" — the server had never connected to GitHub before.
RESOLVED Switched repository URL from SSH to HTTPS. PAT token credentials handle authentication cleanly over HTTPS without requiring pre-established host keys.
ISSUE Jenkins container exited immediately with volume permission errors on /var/jenkins_home — Docker created the directory as root before Jenkins could write to it.
RESOLVED Pre-created the directory and set ownership to UID 1000 (the Jenkins container user) before starting the container: sudo chown -R 1000:1000 /var/jenkins_home.
ISSUE React build failed inside Docker with ERR_PACKAGE_PATH_NOT_EXPORTED from postcss-safe-parser when using Node 18 as specified in the docs.
RESOLVED Identified the root cause as a Node 18 incompatibility with older postcss dependencies. Pinned the frontend Dockerfile to Node 16 to match the project's package lockfile.
04

Skills Demonstrated

Cloud & Infrastructure
  • AWS ECS Fargate (task definitions, services, auto scaling)
  • Application Load Balancer with path-based routing
  • VPC design with public/private subnet architecture
  • ECR with lifecycle policies
  • IAM roles, policies, and OIDC federation
  • CloudWatch alarms and log groups
  • NAT Gateway and Internet Gateway configuration
DevOps & Automation
  • Terraform — modular IaC across 10 configuration files
  • Jenkins declarative pipelines (Groovy)
  • GitHub Actions workflow authoring (YAML)
  • Docker multi-stage builds and container orchestration
  • GitHub webhook integration
  • OIDC-based credential-free AWS authentication
  • Git history rewriting with filter-branch
Operations & Reliability
  • Load testing with siege (250 concurrent users)
  • ECS auto scaling policy configuration
  • CloudWatch monitoring and alarm validation
  • Container permission and networking troubleshooting
  • SSH key management and EC2 access
Development & Tooling
  • Node.js / React / Express application setup
  • CORS configuration between services
  • AWS CLI for resource management and verification
  • Linux system administration (Amazon Linux, Ubuntu)
  • Git branching strategy (main + gitops branches)
05

Load Test Results

99.86%
Availability
250 concurrent users / 2 min
16,334
Transactions
23 failed (0.14%)
141/s
Throughput
transactions per second