Skip to content
EgyKode

Cloud DevOps Capstone

Three microservices taken from raw source code to a running, monitored, GitOps-managed deployment on AWS EKS.

  • terraform
  • ansible
  • aws
  • kubernetes
  • kustomize
  • docker
  • jenkins
  • argocd
  • trivy
  • sonarqube
  • prometheus
  • grafana

Author

Waleed Darwesh

Cloud & DevOps Engineer

Why it exists

This is where the curriculum lands. Three services in three languages — Node 22, Python 3.12 and Java 21 — plus a stateful MySQL, carried through every layer of the path: Terraform provisions the AWS infrastructure, Ansible configures the build host, Jenkins builds and gates, Argo CD reconciles, Prometheus watches. Nothing in it is aspirational, and that is the part worth copying: the Terraform plans against a live AWS account with zero errors, all 48 Kubernetes objects render through Kustomize and validate against the real 1.31 schemas, and every phase directory carries its own README explaining the code line by line. A project that claims to work and a project that has been made to prove it are different artifacts.

What's inside

  • Four Terraform modules — VPC across 2 AZs with NACLs and flow logs, EKS 1.31 with OIDC and three IRSA roles, ECR with immutable tags, a Jenkins host with IMDSv2 enforced, and an ACM certificate terminating TLS at the load balancer
  • 9 Ansible roles with Vault and AWS dynamic inventory — the build host is configured with no manual step
  • 48 Kubernetes objects rendered by Kustomize: a MySQL StatefulSet on EBS CSI, three HPAs, three PodDisruptionBudgets, RBAC, quotas, and eight default-deny NetworkPolicies
  • A 9-stage Jenkins pipeline driven by a Groovy shared library, so logic lives in one place rather than in every Jenkinsfile
  • Trivy runs before the push — an image with a fixable CRITICAL CVE never reaches the registry
  • Argo CD sync waves order the rollout: database, then backends, then frontend, then the load balancer
  • Jenkins, SonarQube, Argo CD and Grafana reach you through the cluster’s load balancer behind IP allowlists — with a scheduled GitHub Action rewriting the allowlist when your address changes, so the tooling is neither public nor unreachable
  • Pod Security Standard `restricted` — non-root, read-only root filesystem, all capabilities dropped, enforced at admission
  • kube-prometheus-stack with 12 alert rules whose annotations link to a runbook, plus black-box probes that need no change to the app
  • Zero static AWS keys anywhere: IAM instance profile for CI, IRSA for workloads

Decisions worth explaining

Why use EKS here, rather than building a self-managed cluster with kubeadm?
Because they answer different questions. kubeadm teaches you what a control plane is; EKS is what most teams should actually run. Having learned both, you can say why you would pick one — which is the question an interviewer asks.
Why Kustomize rather than Helm for the applications?
The manifests are deployed to one cluster in one shape, so the templating a chart buys you goes unused, and Argo CD reads Kustomize natively. Helm is still here for kube-prometheus-stack, where the chart is doing real work that someone else maintains.
The upstream README describes the services incorrectly. What do you follow?
The code. Upstream states that auth-service is Java and roadmap-service is Python; `auth-service/app.py` is Flask and `roadmap-service/pom.xml` is Spring Boot, so it is the other way round. Its config key is `DB_USER`, not `DB_USERNAME`. Every manifest, Dockerfile and pipeline here follows what the code does — and reading the source rather than the documentation is most of the job.
What did running a real plan catch that validation did not?
An `Invalid count argument` in the EKS access-entry resource, where `count` depended on an ARN that is unknown until apply. `terraform validate` cannot see it because nothing is wrong with the syntax. It is the argument for planning against a live account before you claim something works.
What does it cost to run?
About $231/month in us-east-1 if left running: $73 for the EKS control plane, $61 for two t3.medium nodes, $34 for the Jenkins host, $33 for a NAT Gateway, $17 for the ALB. `single_nat_gateway`, ECR lifecycle expiry and log retention caps are built in, and `make tf-destroy` tears it down. The control plane bills hourly whether or not anything is deployed.
Why does the teardown order matter?
Delete the Argo CD Application first so its finalizer cascades, then the Ingress so the ALB is released. Destroy the VPC while the load balancer still exists and its ENIs block the deletion — `terraform destroy` hangs for twenty minutes and then fails. The StorageClass uses `reclaimPolicy: Retain`, so the MySQL volume survives on purpose.