A production-grade, full-stack task management application deployed on AWS using Kubernetes, GitOps, CI/CD pipelines, and automated HTTPS — built end-to-end as a DevOps capstone project.
** Live URL:** https://app.kentaskapp.online
- Project Overview
- Architecture
- Tech Stack
- Project Phases
- Key Commands Reference
- Lessons Learned
- Author
This capstone project demonstrates a complete DevOps workflow — from bare infrastructure to a live, secured, production-accessible web application. The application is a full-stack Task Manager built with:
- React (Frontend)
- Flask (Backend API)
- PostgreSQL (Persistent Database)
Every layer of the stack was containerized, orchestrated on Kubernetes, and deployed through automated pipelines — reflecting real-world industry practices for cloud-native application delivery.
┌─────────────────────────────────────────────────────────────────┐
│ AWS Cloud (kOps Cluster) │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌────────────────────┐ │
│ │ React │───▶│ Flask (API) │───▶│ PostgreSQL DB │ │
│ │ Frontend │ │ Backend │ │ (Persistent Vol.) │ │
│ └──────────┘ └──────────────┘ └────────────────────┘ │
│ │ │
│ ┌─────▼──────────────────────────────┐ │
│ │ NGINX Ingress Controller │ │
│ │ + cert-manager (Let's Encrypt) │ │
│ └─────────────────────────────────────┘ │
│ │ │
│ ┌──────────▼──────────┐ │
│ │ ArgoCD (GitOps) │◀── GitHub (source of truth) │
│ └─────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ GitHub Actions CI/CD Pipeline │ │
│ │ (Build → Test → Push Image → Update Manifests) │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
| Category | Tool / Technology |
|---|---|
| Cloud Provider | AWS (EC2, S3, Route 53) |
| Infrastructure as Code | Terraform, kOps |
| Container Orchestration | Kubernetes |
| Frontend | React |
| Backend | Flask (Python) |
| Database | PostgreSQL |
| CI/CD | GitHub Actions |
| GitOps | ArgoCD |
| Ingress | NGINX Ingress Controller |
| TLS/SSL | cert-manager + Let's Encrypt |
| Containerization | Docker |
| Version Control | Git / GitHub |
The foundation of the project was provisioning a production-grade Kubernetes cluster on AWS.
What was done:
- Used Terraform to provision base AWS resources including S3 buckets (for kOps state store) and IAM roles
- Used kOps to bootstrap and manage a fully functional Kubernetes cluster on EC2
- Configured cluster networking (VPC, subnets, security groups) to support multi-service communication
Key decisions:
- kOps was chosen over EKS for deeper control over cluster configuration and to demonstrate understanding of Kubernetes internals
- Remote state was stored in S3 to enable reproducible infrastructure
With the cluster running, all application services were containerized and deployed as Kubernetes workloads.
What was done:
- Wrote
Deployment,Service, andPersistentVolumeClaimmanifests for each component (React, Flask, PostgreSQL) - Organized manifests under
k8s/base/following a clean GitOps-friendly directory structure - Deployed all resources into a dedicated
taskappnamespace for isolation
Apply manifests:
kubectl apply -f k8s/base/
kubectl get pods -n taskappCheck pod status:
kubectl get pods -n taskapp
# Expected output: all pods in Running stateExposing the application externally required proper routing through an Ingress controller.
What was done:
- Installed NGINX Ingress Controller on the cluster
- Configured Ingress rules to route traffic to the frontend and backend services based on URL path
- Set up Route 53 DNS records pointing
app.kentaskapp.onlineto the cluster's LoadBalancer
Ingress routing logic:
app.kentaskapp.online/ → React Frontend Service
app.kentaskapp.online/api/* → Flask Backend Service
Security was non-negotiable. The application was secured with a valid TLS certificate.
What was done:
- Installed cert-manager on the cluster
- Configured a
ClusterIssuerresource pointing to Let's Encrypt (production) - Annotated the Ingress resource to trigger automatic certificate provisioning
- Verified TLS handshake and certificate validity end-to-end
Result: The app is fully accessible over HTTPS at https://app.kentaskapp.online with a valid, auto-renewing certificate.
Every code push triggers an automated pipeline — no manual deployments.
What was done:
- Built a GitHub Actions workflow with the following stages:
- Build — Docker image is built from source
- Test — Application tests are run inside the container
- Push — Image is pushed to a container registry (Docker Hub / ECR)
- Update — Kubernetes manifests are updated with the new image tag
Pipeline file: .github/workflows/deploy.yml
# Simplified pipeline overview
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- Checkout code
- Build Docker image
- Run tests
- Push image to registry
- Update k8s manifest with new image tag
- Commit and push manifest changes (ArgoCD picks up from here)ArgoCD was deployed to ensure the cluster state always matches what's declared in Git — the single source of truth.
What was done:
- Installed ArgoCD on the cluster
- Created an ArgoCD
Applicationresource pointing to thek8s/directory in the GitHub repo - Configured auto-sync so any manifest change in Git is automatically applied to the cluster
- Accessed the ArgoCD UI to monitor application health and sync status
ArgoCD sync flow:
Developer pushes code
→ GitHub Actions builds & pushes image
→ Manifest updated in Git
→ ArgoCD detects diff
→ ArgoCD syncs cluster to match Git
→ New pods roll out automatically
Real-world deployments always involve debugging. Here's what was encountered and resolved:
| Issue | Root Cause | Fix Applied |
|---|---|---|
| API misconfiguration | Frontend was calling wrong API base URL | Updated environment variable in React build config |
| Database schema missing | PostgreSQL started without running migrations | Added an init container to run Flask DB migrations on startup |
| Kubernetes routing issues | Ingress rules not matching backend service path | Corrected pathType and path prefix in Ingress manifest |
Debugging commands used:
# Check pod logs
kubectl logs -n taskapp deployment/taskapp-backend
# Describe a pod for event details
kubectl describe pod -n taskapp <pod-name>
# Exec into a running container for live debugging
kubectl exec -it -n taskapp deployment/taskapp-backend -- /bin/sh
# Test the API endpoint directly
curl -X POST https://app.kentaskapp.online/api/auth/signup \
-H "Content-Type: application/json" \
-d '{"username": "testuser", "password": "testpass"}'With all services running, a thorough end-to-end validation was performed.
Validation checklist:
- ✅ All pods in
Runningstate across thetaskappnamespace - ✅ Frontend accessible via HTTPS at https://app.kentaskapp.online
- ✅ User signup and login working correctly
- ✅ Tasks created by a user persist in PostgreSQL across pod restarts
- ✅ CI/CD pipeline triggers successfully on new commits
- ✅ ArgoCD reflects healthy sync status
- ✅ TLS certificate valid and auto-renewal configured
# View all resources in the taskapp namespace
kubectl get all -n taskapp
# Apply all Kubernetes manifests
kubectl apply -f k8s/base/
# Stream logs from the backend
kubectl logs -n taskapp deployment/taskapp-backend -f
# Check ingress configuration
kubectl get ingress -n taskapp
# Check certificate status
kubectl get certificate -n taskapp
# Restart a deployment (e.g., after config change)
kubectl rollout restart deployment/taskapp-backend -n taskapp
# Test live API endpoint
curl -X POST https://app.kentaskapp.online/api/auth/signup \
-H "Content-Type: application/json" \
-d '{"username": "demo", "password": "demo123"}'- Infrastructure as Code pays off — Terraform + kOps made the cluster reproducible and easy to tear down and rebuild during testing
- GitOps keeps you sane — Having ArgoCD sync from Git means the cluster state is always auditable and rollbacks are trivial
- Debugging Kubernetes is a skill — Learning to use
kubectl describe,kubectl logs, and exec into pods was critical to resolving real issues fast - cert-manager is magic — Automating TLS certificate issuance and renewal removes an entire class of operational toil
- CI/CD discipline matters — Every broken pipeline is a learning moment; investing in a solid workflow early saves hours later
Kennedy Nwachukwu — DevOps Engineer / Cloud Infrastructure Enthusiast
Built with real infrastructure, real debugging, and real deployment challenges — not just tutorials.
Live App: https://app.kentaskapp.online
This project was completed as a capstone demonstrating end-to-end DevOps practices including Infrastructure as Code, container orchestration, CI/CD automation, GitOps, and production-grade security configurations.