Three-tier Student Registration app (React + Vite / Spring Boot / MariaDB) fully orchestrated on Kubernetes β StatefulSet, Deployments, HPA, Secrets, PVC, and Ingress
A three-tier Student Registration CRUD Application deployed on Kubernetes. The stack β React (Vite) frontend, Spring Boot backend, and MariaDB database β is containerized and fully orchestrated using production-grade Kubernetes patterns: StatefulSet for the database, HPA for auto-scaling, Secrets for credentials, PVC for persistent storage, and Ingress for routing.
Browser
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Kubernetes Cluster β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Ingress Controller β β
β β Routes external traffic β frontend service β β
β βββββββββββββββββββββββββ¬βββββββββββββββββββββββββ β
β β β
β βββββββββββββββββββββββββΌβββββββββββββββββββββββββ β
β β Tier 1 β Frontend β β
β β React + Vite Deployment NodePort Service β β
β β HPA: auto-scales on CPU β β
β β VITE_API_URL β backend NodePort β β
β βββββββββββββββββββββββββ¬βββββββββββββββββββββββββ β
β β ClusterIP :8080 β
β βββββββββββββββββββββββββΌβββββββββββββββββββββββββ β
β β Tier 2 β Backend β β
β β Spring Boot Deployment ClusterIP Service β β
β β HPA: auto-scales on CPU β β
β β spring.datasource.url β db StatefulSet ClusterIPβ β
β βββββββββββββββββββββββββ¬βββββββββββββββββββββββββ β
β β ClusterIP :3306 β
β βββββββββββββββββββββββββΌβββββββββββββββββββββββββ β
β β Tier 3 β Database β β
β β MariaDB StatefulSet ClusterIP Service β β
β β Secret β credentials PVC β persistent data β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
student-app-kubernetes/
β
βββ frontend/ # React + Vite source + Dockerfile
β βββ src/
β βββ .env # VITE_API_URL=http://<backend-ip>:<nodeport>/api
β βββ Dockerfile
β βββ package.json
β
βββ backend/ # Spring Boot source + Dockerfile
β βββ src/
β βββ application.properties # DB connection via MariaDB ClusterIP
β βββ Dockerfile
β
βββ database-yaml/ # Kubernetes manifests β database tier
β βββ statefulset.yaml
β βββ service.yaml
β βββ secret.yaml
β βββ pv-pvc.yaml
β
βββ simple-deploy/ # Simplified starter manifests
β βββ deployment.yaml
β βββ service.yaml
β
βββ docker-compose.yml # Local development stack
βββ init.sql # Database schema initialisation
βββ README.md
| Tier | Resource | Purpose |
|---|---|---|
| Database | StatefulSet |
Stable pod identity + ordered startup for MariaDB |
| Database | Service (ClusterIP) |
Internal access on port 3306 |
| Database | Secret |
Store MariaDB credentials (base64 encoded) |
| Database | PersistentVolume + PVC |
Persistent storage β data survives pod restarts |
| Backend | Deployment |
Manage Spring Boot pods |
| Backend | Service (ClusterIP) |
Internal access on port 8080 |
| Backend | HPA |
Auto-scale pods based on CPU utilisation |
| Frontend | Deployment |
Manage React/Vite pods |
| Frontend | Service (NodePort) |
Expose frontend externally |
| Frontend | HPA |
Auto-scale pods based on CPU utilisation |
| Frontend | Ingress |
Route external HTTP traffic to frontend service |
- Kubernetes cluster (Minikube / EKS / k3s)
kubectlconfigured and connected to the cluster- Docker + DockerHub account (for building and pushing images)
Backend image:
cd backend/
# Edit application.properties β set the DB connection to the K8s service name
# spring.datasource.url=jdbc:mariadb://db-service:3306/student_db
docker build -t <your-dockerhub-username>/student-backend:latest .
docker login
docker push <your-dockerhub-username>/student-backend:latestFrontend image:
cd ../frontend/
# Edit .env β point to backend NodePort
# VITE_API_URL=http://<cluster-node-ip>:<backend-nodeport>/api
docker build -t <your-dockerhub-username>/student-frontend:latest .
docker push <your-dockerhub-username>/student-frontend:latest# Encode your credentials in base64
echo -n 'root' | base64 # β cm9vdA==
echo -n 'your_password' | base64 # β replace with your encoded valueEdit database-yaml/secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: db-secret
namespace: student-app
type: Opaque
data:
db-username: cm9vdA== # base64 of 'root'
db-password: <base64-encoded-pass> # never commit real passwords# Deploy database tier first (StatefulSet must be ready before backend starts)
kubectl apply -f database-yaml/
# Wait for the database pod to be Running
kubectl get pods -n student-app -w
# Deploy backend and frontend
kubectl apply -f backend-yaml/
kubectl apply -f frontend-yaml/# Check all resources
kubectl get all -n student-app
# Check HPA status
kubectl get hpa -n student-app
# Check Ingress
kubectl get ingress -n student-app
# List all services across namespaces
kubectl get svc -A# For Minikube
minikube service frontend-service -n student-app
# For NodePort on any cluster
http://<cluster-node-ip>:<frontend-nodeport>
# For Ingress
http://<ingress-external-ip>server.port=8080
spring.datasource.url=jdbc:mariadb://<db-statefulset-clusterip>:3306/student_db
spring.datasource.username=root
spring.datasource.password=<injected-via-k8s-secret>
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=trueIn production, inject
spring.datasource.passwordfrom the Kubernetes Secret usingvalueFrom.secretKeyRefin the Deployment manifest β never hardcode it inapplication.properties.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: backend-hpa
namespace: student-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: backend
minReplicas: 2
maxReplicas: 8
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70To run the full stack locally without Kubernetes:
docker compose up -d
# Frontend: http://localhost:3000
# Backend: http://localhost:8080
# Database: localhost:3306# Watch pod status live
kubectl get pods -n student-app -w
# Stream backend logs
kubectl logs -f deployment/backend -n student-app
# Describe a pod for debugging
kubectl describe pod <pod-name> -n student-app
# Scale backend manually
kubectl scale deployment backend --replicas=4 -n student-app
# Execute into the database pod
kubectl exec -it <db-pod-name> -n student-app -- mariadb -u root -p| Issue | Location | Fix |
|---|---|---|
Hardcoded DB password in application.properties |
backend/application.properties |
Inject via secretKeyRef in the backend Deployment manifest |
Hardcoded backend IP in frontend .env |
frontend/.env |
Use Ingress hostname or ClusterIP service name resolved at runtime |
Hardcoded credentials in README.md |
Repo root README.md |
Use placeholder values only β never commit real passwords to Git |
| Repo | Description |
|---|---|
| student-app-docker-compose | Same app running locally with Docker Compose |
| crud-app-aws-ec2-rds | Same app deployed on AWS EC2 + RDS |
| jenkins-cicd-pipelines | CI/CD pipeline that builds and pushes the Docker images |
| terraform-aws-iac | Terraform to provision the EKS cluster this runs on |
Sanket Ajay Chopade β DevOps Engineer