This project showcases a production-ready cloud platform built with a modern separation-of-concerns architecture. It provisions a scalable and secure Amazon Elastic Kubernetes Service (EKS) cluster using Terraform and deploys the OpenTelemetry Demo microservices application utilizing GitOps principles with ArgoCD.
- Infrastructure layer: Handled by Terraform, employing official HashiCorp AWS modules for VPC (spanning 2 Availability Zones with a single NAT Gateway to reduce cost) and EKS (v1.30, utilizing
t3.largenodes suitable for resource-heavy observability tools). - Delivery layer: Handled by ArgoCD, pulling stable upstream manifests and syncing helm-based deployments with self-healing and automated pruning enabled.
flowchart TB
Internet((Internet))
subgraph GitHub[GitOps Source of Truth]
Repo[(GitHub Repository\nTerraform & YAML)]
end
subgraph AWS[AWS Cloud Region]
IGW[Internet Gateway]
ALB[Application Load Balancer]
subgraph VPC[Virtual Private Cloud]
subgraph AZ1[Availability Zone 1]
subgraph PubSub1[Public Subnet 1]
NAT[NAT Gateway]
end
subgraph PrivSub1[Private Subnet 1]
Node1[EKS Worker Node 1]
FrontendProxy[Frontend Proxy]
Frontend[Frontend App]
end
end
subgraph AZ2[Availability Zone 2]
subgraph PubSub2[Public Subnet 2]
end
subgraph PrivSub2[Private Subnet 2]
Node2[EKS Worker Node 2]
Backend[Backend Microservices]
Obs[Observability Stack\nGrafana, Jaeger, Prometheus]
ArgoCD[ArgoCD Controller]
LBC[AWS LBC]
end
end
end
end
%% Networking
Internet <--> IGW
IGW <--> ALB
ALB -->|Ingress Routing| FrontendProxy
%% NAT Flow
Node1 -.->|Outbound| NAT
Node2 -.->|Outbound| NAT
NAT -.-> IGW
%% Application Flow
FrontendProxy --> Frontend
Frontend --> Backend
Backend -.->|Telemetry| Obs
Frontend -.->|Telemetry| Obs
%% GitOps Flow
LBC -.->|Provisions| ALB
ArgoCD -.->|Monitors & Syncs| Repo
ArgoCD -.->|Deploys| LBC
ArgoCD -.->|Deploys Apps| FrontendProxy
%% Styling
classDef aws fill:#FF9900,stroke:#232F3E,stroke-width:2px,color:#232F3E,stroke-dasharray: 0;
classDef k8s fill:#326CE5,stroke:#fff,stroke-width:2px,color:#fff,stroke-dasharray: 0;
classDef git fill:#2dba4e,stroke:#fff,stroke-width:2px,color:#fff,stroke-dasharray: 0;
classDef pub fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray: 5 5;
classDef priv fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,stroke-dasharray: 5 5;
classDef az fill:#f4f4f4,stroke:#333,stroke-width:1px,stroke-dasharray: 5 5;
class ALB,IGW,NAT aws;
class ArgoCD,LBC,FrontendProxy,Frontend,Backend,Obs,Node1,Node2 k8s;
class Repo git;
class PubSub1,PubSub2 pub;
class PrivSub1,PrivSub2 priv;
class AZ1,AZ2 az;
- Automated Provisioning: Reduces deployment time from days to minutes. All infrastructure is codified, minimizing configuration drift and human error.
- GitOps Security & Reliability: Applications are managed via declarative source control. ArgoCD constantly monitors the cluster state and automatically heals discrepancies against the desired state defined in Git.
- Full-Stack Observability: The OpenTelemetry Demo provides immediate, actionable insights into microservice interactions, traces, and metrics, ensuring high availability and rapid debugging for business-critical applications.
This project strictly follows the industry-standard Separation of Concerns by acting as a dedicated Platform/GitOps Repository, completely separate from the application source code repository.
- Different Lifecycles: Application code (Java, Go, Node.js) changes rapidly (multiple times a day), while Platform code (Terraform, Kubernetes) changes deliberately and slowly. Separating them prevents minor application typos from triggering massive infrastructure pipelines.
- Security & Blast Radius: Application developers are granted full access to merge application code in their repo, but are restricted from modifying the VPC, tearing down EKS clusters, or changing IAM permissions in this Platform repo.
- The GitOps Standard: When application developers finish writing code, their CI pipeline builds a new Docker image and automatically opens a Pull Request in this Platform Repository to update the image tag. ArgoCD then detects the YAML change here and securely syncs it to the cluster.
You must have the AWS CLI, Terraform, and kubectl installed on your local machine.
If you are on a Mac, you can install them via Homebrew (Note: Terraform must be installed from HashiCorp's tap):
brew tap hashicorp/tap
brew install hashicorp/tap/terraform awscliOnce installed, configure your AWS credentials to link your terminal to your AWS account:
aws configure-
Navigate to the Terraform directory:
cd terraform -
Initialize Terraform modules and providers:
terraform init
-
Apply the configuration to provision the VPC and EKS cluster:
terraform apply -auto-approve
Note: This process typically takes 10-15 minutes.
-
Once complete, configure
kubectlto communicate with your new cluster:aws eks update-kubeconfig --region us-east-1 --name otel-demo-cluster
Because ArgoCD's Custom Resource Definitions (CRDs) are extremely large, we use Kubernetes Server-Side Apply to bypass annotation size limits.
- Create the
argocdnamespace:kubectl create namespace argocd
- Apply the initial ArgoCD manifests using Server-Side Apply:
kubectl apply --server-side=true --force-conflicts -k gitops/1-argocd-init
With ArgoCD running, apply the GitOps manifests. ArgoCD will automatically detect the Application Custom Resource, create the otel-demo namespace, and deploy all 25+ microservices.
kubectl apply -f gitops/2-apps/argocd-project.yaml
kubectl apply -f gitops/2-apps/opentelemetry-demo.yamlOur GitOps configuration explicitly instructs AWS to provision a public Elastic Load Balancer (ELB) for the application frontend proxy.
- Run the following command and wait for the
EXTERNAL-IPto populate with an AWS domain name (it usually takes 2-3 minutes):kubectl get svc frontend-proxy -n otel-demo -w
- Copy the Load Balancer URL. You can access the different components of the platform by appending the correct paths to your URL.
- Astronomy Shop Frontend:
http://<YOUR_AWS_ELB_URL>:8080/
- Grafana Dashboards:
http://<YOUR_AWS_ELB_URL>:8080/grafana/
- Jaeger Distributed Tracing:
http://<YOUR_AWS_ELB_URL>:8080/jaeger/ui/
This repository includes a GitHub Actions CI pipeline (.github/workflows/ci.yml) that triggers on every push or pull request to the main branch.
The pipeline ensures code quality and safety by running:
- Terraform Validation: Enforces formatting (
terraform fmt) and validates the AWS infrastructure code (terraform validate). - YAML Linting: Scans the
gitops/directory withyamllintto ensure all Kubernetes manifests are syntactically valid.
For a detailed step-by-step walkthrough of exactly how this architecture was built, including the real-world roadblocks encountered (like macOS dependency issues, ArgoCD CRD size limits, and local port conflicts) and how they were solved, please see the Deployment Journey & Troubleshooting Guide.
To optimize costs and enable advanced Layer 7 routing, the platform uses the AWS Load Balancer Controller instead of basic Classic Load Balancers.
- IAM Role (Terraform): An IAM Role for Service Accounts (IRSA) was provisioned in Terraform and linked to the EKS OIDC provider.
- ALB Controller (GitOps): An ArgoCD application (
gitops/2-apps/aws-lbc.yaml) automatically deploys the controller into thekube-systemnamespace. - Ingress Migration (GitOps): The OpenTelemetry Demo is configured to use a Kubernetes
Ingressresource with thealbingress class, instructing AWS to provision a modern Application Load Balancer.
Note
Strict Helm Schemas in GitOps: During the migration, the OpenTelemetry v2.2.0 Helm chart rejected the initial configuration due to a strict JSON Schema validation (the component key changed from frontendProxy to frontend-proxy). Thanks to ArgoCD, the deployment failed gracefully without taking down the existing ELB. Updating the manifest to strictly match the new schema allowed ArgoCD to provision the ALB perfectly.
Warning
AWS charges apply for resources running in this project. An EKS control plane, t3.large worker nodes, a NAT Gateway, and an ELB are not part of the AWS Free Tier. They cost approximately $0.35/hour ($250/month).
Ensure you destroy all resources when you are finished to prevent unexpected billing.
-
Delete the ArgoCD Applications First: ArgoCD application finalizers can block namespace deletion, and external resources (like the Application Load Balancer) must be gracefully deleted by the cluster before the cluster itself is destroyed.
kubectl delete -f gitops/2-apps/opentelemetry-demo.yaml kubectl delete -f gitops/2-apps/aws-lbc.yaml
(Wait ~3 minutes for the Load Balancer to fully delete in AWS before proceeding)
-
Destroy Infrastructure: Navigate back to the terraform directory and issue the destroy command:
cd terraform terraform destroy -auto-approve




