This project demonstrates the deployment of a Spring Boot application with two REST APIs, Docker containerization, and Kubernetes orchestration using Google cloud. The system also includes MySQL as a database running inside Kubernetes using a StatefulSet.
- Java 17
- Spring Boot
- MySQL 8
- Docker
- Kubernetes(Google Kubernetes Engine)
- ConfigMap / Secret / StatefulSet / Deployment / Ingress
- Horizontal Pod Autoscaler (HPA)
https://github.com/dev-android1/k8s-docker-springboot
https://hub.docker.com/r/ashishdev1/springbootwithmysql
http://nagpapp.local/pool-status
GET /users
- Returns all user records from the database.
- Example response:
[
{
"id": 1,
"name": "Ashish",
"email": "ashish@gmail.com"
}
]POST /user
- create user in the database.
- Example request:
{
"name": "Ashish",
"email": "ashish@gmail.com"
}GET /welcome
- This API is used to check for latest deployment.
GET /pool-status
- This API is used to check for active and idle DB connection.
You can test these API after deployment using:
curl http://<ingress-ip>/<path>src/main
├── java/
│ ├── controller/UserController.java # 4 Rest APIs (getUser,postUser,welcome,pool-status)
│ ├── entity/User # Table entity
│ ├── exception/GlobalExceptionHandler # Exception Handler
│ └── StartupLogger.java #For Logging details on start
│
├── resources/
│ ├── application.properties # DB configuration and connection pooling
│ ├── data.sql # Initial records to be inserted on app launch
│ └── schema.sql # Table structure
# Build the JAR
./gradlew build
# Build Docker Image
docker build -t <yourdockerhub>/<name>:<version> .
# Push to DockerHub
docker push <yourdockerhub>/<name>:<version>
# For Google Cloud include platform if prev does not work
docker buildx build --platform linux/amd64 -t <yourdockerhub>/<name>:<version> --push .k8s/
├── app/
│ ├── deployment.yaml # Spring Boot Deployment (4 replicas)
│ ├── service.yaml # NodePort for API
│ ├── configmap.yaml # DB URL, port, etc. (plain text info)
│ ├── secrets.yaml # DB user/password (Base 64 encoded)
│ ├── ingress.yaml # Ingress (for external access via rules)
│ └── hpa.yaml # HPA definition (for load testing)
│
├── mysql/
│ ├── statefulset.yaml # MySQL StatefulSet (stable identity, 1 pod)
│ ├── service.yaml # Headless Service for MySQL
│ ├── configmap.yaml # MySQL config (plain text info)
│ ├── secret.yaml # MySQL secrets (Base64 encoded)
│ └── pvc.yaml # Persistent Volume Claim (For persistent storage)
gcloud container clusters create <cluster_name> \
--zone <region name> \
--num-nodes=2 \
--machine-type=e2-medium \
--disk-type=pd-standard \
--disk-size=30 \
--enable-ip-aliaskubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml
kubectl apply -f k8s/mysql/
kubectl apply -f k8s/app/kubectl get pods -o wide
kubectl get nodes -o widekubectl get ingressFirst get the target tag for firewall rule
gcloud compute instances list --filter="name~'gke-'" --format="table(name,networkInterfaces.networkIP,tags.items)"Put above tag name in below command
gcloud compute firewall-rules create allow-nodeport \
--allow tcp:30000-32767 \
--target-tags=<tag name> \
--network=default \
--direction=INGRESS \
--priority=1000 \
--description="Allow NodePort access to GKE nodes"
After this
kubectl get ingress# Copy ingress URL and paste into host file via accessing host file (/etc/host)
sudo nano /etc/hosts
add ingress ip : nagpapp.local
# Test API with host name defined in ingress.yaml (nagpapp.local)# name of pod can be get using kubectl get pods
kubectl delete pod <mysql-pod-name>kubectl set image deployment/springboot-api <docker-repo-name>=<docker-user-name>/<docker-repo-name>:<new version>kubectl rollout status deployment/springboot-apiCheck for metric server
kubectl get deployment metrics-server -n kube-systemIf it is not enabled then enable it
Enable Auto scaling
gcloud container clusters update <cluster-name> \
--zone <zone-name> \
--enable-autoscaling \
--min-nodes=4 \
--max-nodes=8 \
--node-pool=default-poolRun on terminal (Load generation via hey)
# hey is a load testing tool written in Go, used to simulate a large number of HTTP requests to test the performance of an API or web service.
brew install hey
hey -z 2m -c 20 http://<external-ip>:<port>/users
or
hey -z 2m -c 20 http://nagpapp.local/users-z 2m -- Run test for 2 min
-c 20 -- Use 20 concurrent user
kubectl delete -f k8s/app
kubectl delete -f k8s/mysql
gcloud container clusters delete <cluster-name> \
--region <region-name>minikube start --driver=dockerminikube addons enable ingress
minikube addons enable metrics-server# Deploy MySQL
kubectl apply -f k8s/mysql/
# Deploy API and HPA
kubectl apply -f k8s/app/minikube tunnel
kubectl get ingress127.0.0.1 nagpapp.local
Test:
curl http://nagpapp.local/usersUpdate the deployment:
kubectl set image deployment/springboot-api springboot-api=new-image:tagWatch pods:
kubectl rollout status deployment/springboot-api- Run the app and insert users.
- Delete the MySQL pod:
kubectl delete pod <mysql-pod-name>- Pod will restart, and data will be preserved (via PVC).
Load the API
while true; do curl http://nagpapp.local/users; doneOr:
hey -z 2m -c 20 http://nagpapp.local/usersWatch Pods and HPA
watch kubectl get hpaHPA will scale up pods if CPU > 50% for sustained time. It will scale down gradually when load reduces.
kubectl delete -f k8s/app
kubectl delete -f k8s/mysql
minikube stop
minikube deleteAshish Agrawal