Welcome to the Cloud-Native DevSecOps Three-Tier Application Deployment project! π
This repository hosts the implementation of a Three-Tier Web App using ReactJS, Node.js, PostgreSQL, and Redis, deployed on AWS EKS. The entire platform is Infrastructure as Code β from bootstrap to teardown, every component is declarative and automated.
β‘ Built across 4 deployment cycles. 17 production issues encountered and resolved. Every fix is documented. This is not a tutorial follow-along.
π οΈ Infrastructure as Code β Everything Automated:
- Terraform provisions Jenkins server, EKS cluster, VPC, ALB controller, EBS CSI driver, ExternalDNS, and Prometheus/Grafana monitoring
- JCasC (Jenkins Configuration as Code) auto-configures plugins, credentials, SonarQube, and pipeline jobs β zero UI clicking
- ArgoCD App-of-Apps pattern deploys all application components from a single
kubectl apply - ExternalDNS auto-creates Route 53 records from Ingress annotations
- Bootstrap + Destroy scripts for full lifecycle management
π’ The deployment covers:
- Bootstrap β S3, DynamoDB, ECR, key pair (one idempotent script)
- Jenkins Server β Terraform + JCasC with 102 pre-installed plugins and automated SonarQube setup
- EKS Cluster β Terraform creates VPC, cluster, node groups, OIDC, EBS CSI, ALB controller, ExternalDNS, and monitoring stack
- Application Deployment β ArgoCD App-of-Apps deploys database, backend, frontend, ingress, and Grafana ingress
- CI/CD Pipeline β 9-stage DevSecOps pipeline with SonarQube + Trivy + ECR + GitOps
- Teardown β Ordered destroy script
CI/CD Flow:
Code Push β Jenkins β SonarQube Analysis β Quality Gate β Trivy FS Scan
β Docker Build β Trivy Image Scan β Push to ECR
β Update K8s Manifest in Git β ArgoCD Auto-Deploy β EKS
DNS Flow (Automated):
Ingress Annotation β ExternalDNS β Route 53 A Record β ALB
platinum-consults.com β App ALB
grafana.platinum-consults.com β Grafana ALB
| Layer | Technology | Purpose |
|---|---|---|
| βοΈ Cloud | AWS (us-east-1) | EKS, ECR, ALB, Route 53, IAM, EBS, S3 |
| β Orchestration | Kubernetes (EKS) | Container orchestration, service discovery |
| βοΈ Frontend | React + Nginx | SPA served via multi-stage Docker build (~25MB) |
| π’ Backend | Node.js + Express | REST API with health checks, CRUD, Redis caching |
| π Database | PostgreSQL 15 | Persistent storage with PVC on EBS |
| π΄ Cache | Redis 7 Alpine | In-memory caching with TTL, LRU eviction |
| π§ CI/CD | Jenkins + JCasC | 9-stage automated DevSecOps pipeline, zero-click setup |
| π Code Quality | SonarQube | Static analysis, quality gates (auto-configured) |
| π‘οΈ Security | Trivy | Filesystem + image vulnerability scanning |
| π GitOps | ArgoCD | App-of-Apps pattern, automatic deployment from Git |
| π IaC | Terraform | Full stack β Jenkins, EKS, VPC, ALB, DNS, monitoring |
| π Monitoring | Prometheus + Grafana | Metrics, dashboards, custom alerts (Terraform-managed) |
| π DNS | Route 53 + ExternalDNS | Automatic DNS from Ingress annotations |
| π¦ Registry | Amazon ECR | Private Docker image storage |
| πͺ Ingress | AWS LB Controller | L7 load balancing, path-based routing |
cloud-native-eks/
βββ π Application-Code/
β βββ π backend/ # Node.js Express API
β β βββ server.js # CRUD API + health checks + Redis caching
β β βββ Dockerfile # Alpine-based, non-root user, healthcheck
β β βββ package.json
β βββ π frontend/ # React Single Page Application
β βββ src/App.js # Task manager with live health indicators
β βββ Dockerfile # Multi-stage build (Node β Nginx, ~25MB)
β βββ nginx.conf # SPA routing, security headers
βββ π EKS-Terraform/ # β Full EKS IaC (replaces eksctl)
β βββ main.tf # VPC, EKS cluster, node groups, OIDC
β βββ ebs-csi.tf # EBS CSI driver addon + IRSA
β βββ alb-controller.tf # ALB controller IAM + IRSA
β βββ helm-alb.tf # ALB controller Helm release
β βββ helm-monitoring.tf # Prometheus + Grafana Helm release
β βββ external-dns-iam.tf # ExternalDNS IAM + Route 53 hosted zone
β βββ helm-external-dns.tf # ExternalDNS Helm release
β βββ namespaces.tf # three-tier, monitoring, argocd
β βββ providers.tf # Kubernetes + Helm providers
β βββ variables.tf # All configurable values
β βββ outputs.tf # Cluster endpoint, kubectl command
β βββ backend.tf # S3 remote state
βββ π Jenkins-Server-TF/
β βββ main.tf # EC2, SG, IAM role + EKS inline policy
β βββ tools-install.sh # 13 tools + 102 plugins pre-installed
β βββ π jcasc/
β βββ jenkins.yaml # JCasC config
β βββ setup-jcasc.sh # One-command secret injection
βββ π Jenkins-Pipeline-Code/
β βββ Jenkinsfile-Backend # 9-stage DevSecOps pipeline
β βββ Jenkinsfile-Frontend # 9-stage DevSecOps pipeline
βββ π Kubernetes-Manifests-file/
β βββ π Database/
β β βββ postgres.yaml # Secret + PVC + Deployment + Service
β β βββ redis.yaml # Deployment + Service
β βββ π Backend/ & Frontend/
β β βββ deployment.yaml # Deployment + Service
β βββ ingress.yaml # ALB + ExternalDNS annotation
β βββ grafana-ingress.yaml # Grafana ALB + ExternalDNS subdomain
β βββ monitoring-alerts.yaml # Custom PrometheusRule (5 alerts)
βββ π argocd/
β βββ app-of-apps.yaml # β Root app (one kubectl apply)
β βββ π apps/ # Child apps auto-created
βββ π assets/
β βββ architecture.png # Architecture diagram
β βββ app-live.png # Live app screenshot
β βββ argocd-dashboard.png # ArgoCD all apps synced
β βββ grafana-dashboard.png # Grafana three-tier metrics
β βββ jenkins-pipelines-backend.png # Backend pipeline 9 stages green
β βββ jenkins-pipelines-frontend.png # Frontend pipeline 9 stages green
β βββ route53-records.png # ExternalDNS auto-created records
β βββ sonarqube-quality-gate.png # Both projects passed
βββ π docs/
β βββ DEPLOYMENT-GUIDE.md
β βββ ISSUES-REPORT.md
βββ bootstrap.sh # β One-command prerequisite setup
βββ destroy.sh # β Ordered teardown script
βββ README.md
- AWS Account with IAM user
- AWS CLI v2 configured
- Terraform >= 1.9.0
- vCPU quota β₯ 20
- Git & GitHub account with PAT
- Domain name with ability to change nameservers
# 1. Bootstrap
bash bootstrap.sh
# 2. Deploy Jenkins
cd Jenkins-Server-TF && terraform init && terraform apply -auto-approve
# 3. Setup Jenkins (one interactive command)
ssh -i test.pem ubuntu@<jenkins-ip>
sudo bash /opt/setup-jcasc.sh
# 4. Deploy EKS + everything
cd EKS-Terraform && terraform init && terraform apply -auto-approve
# 5. Deploy apps
kubectl apply -f argocd/app-of-apps.yamlπ Full Deployment Guide |
β οΈ Issues Report
| # | Stage | Tool | Purpose |
|---|---|---|---|
| 1 | π§Ή Cleanup | Jenkins | Fresh workspace |
| 2 | π₯ Checkout | Git | Clone repo |
| 3 | π SonarQube | sonar-scanner | Code quality |
| 4 | β Quality Gate | SonarQube | Pass/fail |
| 5 | π‘οΈ Trivy FS | Trivy | Source scan |
| 6 | π³ Docker Build | Docker | Build image |
| 7 | π‘οΈ Trivy Image | Trivy | Image CVEs |
| 8 | π€ Push ECR | AWS ECR | Private registry |
| 9 | π Update Manifest | sed + git | Trigger ArgoCD |
| Component | Access |
|---|---|
| Grafana | grafana.platinum-consults.com |
| Prometheus | Internal (ClusterIP) |
| Alertmanager | Internal (ClusterIP) |
| Alert | Severity |
|---|---|
| π΄ PodDown | Critical |
| π‘ HighCPUUsage | Warning |
| π΄ PodCrashLooping | Critical |
| π΄ PostgreSQLDown | Critical |
| π΄ RedisDown | Critical |
17 issues across 4 deployments β Full Report
| # | Challenge | Solution |
|---|---|---|
| 1 | eks:DescribeClusterVersions denied |
EKS inline policy in Terraform |
| 2 | Instance profile creds cached | Export credentials directly |
| 3 | npm ci build failure |
npm install --omit=dev |
| 4 | ArgoCD CRD too large | --server-side --force-conflicts |
| 5 | ArgoCD overwrote pods | Push to Git before ArgoCD |
| 6 | Pods Pending (pod limit) | t3.xlarge (58 pods/node) |
| 7 | vCPU quota limit | Request increase to 20 |
| 8 | Quality Gate timeout | Webhook via private IP |
| 9 | SCM credential empty | Username with password type |
| 10 | sonar-scanner not found | jenkins-plugin-manager JAR |
| 11 | ALB not provisioning | Broader IAM in Terraform |
| 12 | ImagePullBackOff | sed regex to correct tags |
| 13 | Ingress ADDRESS empty | Delete and reapply |
| 14 | JCasC sonarGlobalConfiguration | Groovy init script |
| 15 | Plugin dependency hell | jenkins-plugin-manager JAR |
| 16 | SonarQube rejects localhost | Private IP for webhook |
| 17 | Grafana wrong datasource | Clean old configmaps, Terraform manages monitoring |
| Phase | Before | After |
|---|---|---|
| Prerequisites | 6 CLI commands | bash bootstrap.sh |
| Jenkins | 15+ UI clicks | terraform apply + setup-jcasc.sh |
| EKS + networking | eksctl + 8 commands | terraform apply (41 resources) |
| Monitoring | Manual helm + config | Terraform Helm provider |
| DNS | Console clicking | ExternalDNS (automatic) |
| Apps | 3 ArgoCD UI forms | kubectl apply -f app-of-apps.yaml |
| Teardown | 8 commands | bash destroy.sh |
| Check | Tool | Result |
|---|---|---|
| Code Quality | SonarQube | β Passed |
| Source CVEs | Trivy FS | β Clean |
| Image CVEs | Trivy Image | β Scanned |
| Secrets | JCasC + K8s Secrets | β No hardcoded |
| IAM | IRSA per service | β Least privilege |
| Database | ClusterIP | β Not exposed |
bash destroy.shIbrahim β DevOps Engineer
MIT License β see LICENSE for details.
Happy Deploying! π







