A GitOps-driven deployment pipeline for a Spring Boot API on AWS EKS, using ArgoCD to continuously reconcile cluster state with a Git repository instead of relying on manual kubectl apply or push-based CI/CD deploys.
This project runs on infrastructure that is spun up on demand and torn down after use to avoid ongoing AWS costs — see Running it yourself to deploy it live.
GitHub (this repo)
│
│ manifests/ (Deployment, Service)
▼
ArgoCD (running in-cluster)
│ watches repo, detects drift, auto-syncs
▼
AWS EKS Cluster
│
├── VPC (2 AZs, public subnets)
├── Managed Node Group
└── Spring Boot API pods
│
pulls image from
▼
AWS ECR (private registry)
│
exposed via
▼
AWS Load Balancer (public endpoint)
Core idea: instead of CI/CD pushing changes directly into the cluster, ArgoCD runs inside the cluster and pulls desired state from Git. If the live cluster ever drifts from what's declared in Git — whether from a manual kubectl change or a failed deploy — ArgoCD detects it and reconciles automatically. Git is the single source of truth.
| Layer | Tool |
|---|---|
| Application | Spring Boot 4.0 (Java 21) |
| Containerization | Docker (multi-stage build) |
| Image Registry | AWS ECR |
| Infrastructure as Code | Terraform |
| Compute | AWS EKS (managed node group) |
| GitOps / CD | ArgoCD |
| Cloud | AWS (ap-south-1) |
.
├── src/ # Spring Boot application source
├── Dockerfile # Multi-stage build (JDK build → slim JRE runtime)
├── terraform/ # EKS cluster, VPC, IAM roles as code
│ ├── provider.tf
│ ├── variables.tf
│ ├── vpc.tf
│ ├── eks.tf
│ └── outputs.tf
├── manifests/ # Kubernetes manifests — the source of truth ArgoCD syncs from
│ ├── deployment.yaml
│ └── service.yaml
└── screenshots/ # Proof-of-work screenshots
└── self-heal-demo.png
- VPC: public subnets only across 2 Availability Zones, no NAT Gateway. Deliberate cost trade-off for a demo/learning cluster — a production setup would isolate workloads into private subnets (see my
aws-vpc-architectureproject for that pattern). - Node group: sized to comfortably run ArgoCD's full component set (7 pods) alongside the application — smaller instance types (e.g.
t3.micro) hit AWS's per-node pod limits before resource limits, which is a real constraint worth knowing about when sizing EKS node groups. - Terraform state: kept out of version control (
.gitignore) since it can contain sensitive resource metadata. - Image pulls: the EKS node IAM role has
AmazonEC2ContainerRegistryReadOnlyattached, so nodes authenticate to the private ECR repo automatically — no manual Kubernetes image-pull secret required.
- Application code changes → new Docker image built and pushed to ECR with a new tag
manifests/deployment.yamlupdated to reference the new image tag- Change is committed and pushed to this repo
- ArgoCD detects the diff between Git and the live cluster state
- ArgoCD auto-syncs and reconciles the cluster to match
With auto-sync and self-heal enabled, manually drifting the cluster from Git gets corrected automatically — no human intervention:
kubectl scale deployment gitops-demo-api -n default --replicas=3
NAME READY STATUS RESTARTS AGE
gitops-demo-api-5cd44b5f99-5fjqc 1/1 Terminating 0 4s
gitops-demo-api-5cd44b5f99-9xvrq 1/1 Running 0 38m
gitops-demo-api-5cd44b5f99-zkx4l 0/1 Terminating 0 4s
The manual scale-to-3 was reverted within ~5 seconds — the original pod (age 38m) was untouched while the two drift-induced pods were terminated, bringing the deployment back in line with Git's replicas: 1.
cd terraform
terraform init
terraform apply
aws eks update-kubeconfig --region ap-south-1 --name gitops-demo-cluster
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yamlThen create an ArgoCD Application pointing at this repo's manifests/ path, sync it, and the Service's LoadBalancer will provision a public endpoint automatically.
Remember to terraform destroy when done — the EKS control plane and node group bill continuously while running.
- Spring Boot API with health/demo endpoint
- Dockerfile (multi-stage build)
- Image built and pushed to ECR
- Terraform for EKS cluster, VPC, IAM roles
- Kubernetes manifests (Deployment, Service)
- ArgoCD installed and connected to this repo on live EKS cluster
- Private ECR image pulling via node IAM role (no manual secret needed)
- End-to-end sync verified with public LoadBalancer URL
- Self-heal drift demo captured on real AWS infrastructure
This project follows on from aws-eks-pipeline, which handles push-based CI/CD to EKS via Jenkins. This repo replaces that push model with a pull-based GitOps approach using ArgoCD.
