Spring Boot + Kubernetes + MySQL
A production-style reference implementation demonstrating how to deploy a Spring Boot application with MySQL on Kubernetes, including containerization, Kubernetes deployments, persistent storage, secrets management, and service-to-database connectivity.
The project is designed to demonstrate the fundamentals of running a stateful database and a stateless Spring Boot application in Kubernetes.
π― Problem Statement
Running a Spring Boot application locally with MySQL is straightforward, but deploying the same application to Kubernetes introduces several architectural concerns:
- How should the Spring Boot application be packaged and deployed?
- How should the application communicate with MySQL inside the Kubernetes cluster?
- How can MySQL data survive pod/container restarts?
- How should database credentials be managed without hardcoding them in the application?
- How should Kubernetes manage application and database resources independently?
- How can a stateful component such as MySQL be deployed alongside a stateless application?
This project demonstrates a practical solution using:
- Spring Boot for the REST API
- Docker for application containerization
- Kubernetes for orchestration
- MySQL as the relational database
- PersistentVolumeClaim (PVC) for database persistence
- Kubernetes Secrets for database credentials
The goal is not only to run the application in Kubernetes, but to demonstrate the key architectural patterns required when moving a traditional Spring Boot + database application into a containerized environment.
ποΈ High-Level Architecture
The following diagram represents the overall deployment architecture:
flowchart TB
Client["Client / REST Client"]
subgraph Kubernetes["Kubernetes Cluster"]
Service["Kubernetes Service<br/>Spring Boot"]
App["Spring Boot Application<br/>Deployment / Pod"]
Secret["Kubernetes Secret<br/>DB Credentials"]
DBService["Kubernetes Service<br/>MySQL"]
MySQL["MySQL<br/>Deployment / Pod"]
PVC["PersistentVolumeClaim<br/>Persistent Storage"]
Service --> App
App --> DBService
DBService --> MySQL
Secret -.-> App
Secret -.-> MySQL
MySQL --> PVC
end
Client --> Service
Request Flow
Client
β
βΌ
Kubernetes Service
β
βΌ
Spring Boot Pod
β
β JDBC
βΌ
MySQL Kubernetes Service
β
βΌ
MySQL Pod
β
βΌ
PersistentVolumeClaim
Key Design Principles
Stateless application
Spring Boot runs as a Kubernetes workload. Application instances do not own persistent state, allowing Kubernetes to restart or recreate pods independently.
Stateful database
MySQL requires persistent storage. A Kubernetes PersistentVolumeClaim is used so database data is not tied to the
lifecycle of a MySQL pod.
Service discovery
The Spring Boot application connects to MySQL through a Kubernetes Service rather than using a pod IP. This allows Kubernetes to provide stable service discovery even when pods are recreated.
Secrets management
Database credentials are stored in Kubernetes Secrets instead of being embedded directly into the application deployment configuration.
π Deployment Architecture
The deployment consists of the following Kubernetes resources:
| Component | Kubernetes Resource | Purpose |
|---|---|---|
| Spring Boot | Deployment | Runs the application |
| Spring Boot | Service | Exposes the application |
| MySQL | Deployment | Runs MySQL |
| MySQL | Service | Provides stable database endpoint |
| Database storage | PersistentVolumeClaim | Persists MySQL data |
| Credentials | Secret | Stores database credentials |
π§° Technology Stack
| Technology | Purpose |
|---|---|
| Java 21 LTS | Application runtime |
| Spring Boot | REST API |
| Gradle | Build automation |
| Docker | Containerization |
| Kubernetes | Container orchestration |
| MySQL | Relational database |
| Kubernetes PVC | Persistent database storage |
| Kubernetes Secret | Credential management |
π Prerequisites
Install the following tools before starting:
- Docker Desktop with Kubernetes enabled
- Kubernetes CLI (
kubectl) - JDK 21 LTS
- Gradle 9.x
Verify the installation:
java -version
gradle -version
docker --version
kubectl version --client
Make sure Kubernetes is running:
kubectl cluster-info
You can use Docker Desktopβs built-in Kubernetes environment for local development.
π Getting Started
1. Clone the repository
git clone https://github.com/ashutoshsahoo/spring-boot-kubernetes-mysql.git
cd spring-boot-kubernetes-mysql
2. Create Kubernetes Secrets
Create the required database credentials:
kubectl apply -f deployment/secrets.yaml
Verify:
kubectl get secrets
3. Deploy MySQL
Deploy MySQL and its persistent storage:
kubectl apply -f deployment/mysql-deployment.yaml
Check the resources:
kubectl get pods
kubectl get svc
kubectl get pvc
Wait until the MySQL pod reaches Running state:
kubectl get pods -w
4. Build the Spring Boot Application
Build the application using Gradle:
gradle clean build -i --stacktrace
The generated JAR will be available under:
build/libs/
5. Build the Docker Image
Build the application container:
docker build -t ashutoshsahoo/spring-boot-kubernetes-mysql:<app-version> .
For example:
docker build -t ashutoshsahoo/spring-boot-kubernetes-mysql:1.0.0 .
Verify the image:
docker images | grep spring-boot-kubernetes-mysql
If you are using Docker Desktopβs Kubernetes environment, the Kubernetes cluster can use images available in the Docker environment without requiring an external container registry.
6. Deploy Spring Boot to Kubernetes
Deploy the application:
kubectl apply -f deployment/app-k8s.yaml
Check the deployment:
kubectl get deployment
Check the application pod:
kubectl get pods
Check the service:
kubectl get svc
π Verify the Deployment
A healthy deployment should show:
kubectl get pods
Example:
NAME READY STATUS RESTARTS
mysql-xxxxx 1/1 Running 0
spring-boot-xxxxx 1/1 Running 0
Check application logs:
kubectl logs <spring-boot-pod-name>
For example:
kubectl logs deployment/spring-boot-kubernetes-mysql
π§ͺ Test the Application
The application exposes the following REST endpoint:
GET /api/v1/pets
Test using curl:
curl -X GET \
http://localhost:31371/api/v1/pets \
-H "Accept: application/json" \
-H "Content-Type: application/json"
Expected response:
[
{
"name": "Puffball",
"owner": "Diane",
"species": "hamster",
"sex": "f",
"birth": "1999-03-30",
"death": null
}
]
π Kubernetes Resource Flow
The deployment can be visualized as:
βββββββββββββββββββββ
β Client β
βββββββββββ¬ββββββββββ
β
βΌ
βββββββββββββββββββββ
β Kubernetes β
β Service β
βββββββββββ¬ββββββββββ
β
βΌ
βββββββββββββββββββββ
β Spring Boot β
β Deployment β
β β
β REST API β
βββββββββββ¬ββββββββββ
β
β JDBC
βΌ
βββββββββββββββββββββ
β MySQL Service β
βββββββββββ¬ββββββββββ
β
βΌ
βββββββββββββββββββββ
β MySQL Pod β
βββββββββββ¬ββββββββββ
β
βΌ
βββββββββββββββββββββ
β PersistentVolume β
β Claim β
βββββββββββββββββββββ
ποΈ Project Structure
spring-boot-kubernetes-mysql/
β
βββ deployment/
β βββ app-k8s.yaml
β βββ mysql-deployment.yaml
β βββ secrets.yaml
β
βββ src/
β βββ main/
β βββ java/
β βββ resources/
β
βββ Dockerfile
βββ build.gradle
βββ gradle.properties
βββ settings.gradle
βββ README.md
deployment/
Contains the Kubernetes manifests required to deploy the application and database.
Dockerfile
Defines the container image used to package the Spring Boot application.
build.gradle
Defines application dependencies, build configuration and Gradle plugins.
πΎ Persistent Storage
MySQL is a stateful workload and therefore requires persistent storage.
This project uses a Kubernetes PersistentVolumeClaim to decouple database storage from the lifecycle of the MySQL pod.
MySQL Pod
β
βΌ
PersistentVolumeClaim
β
βΌ
Persistent Storage
This means that deleting/recreating the MySQL pod does not necessarily mean losing the database data, provided the underlying persistent volume remains available.
π Secrets Management
Database credentials are managed through Kubernetes Secrets.
Kubernetes Secret
β
ββββΊ Spring Boot
β
ββββΊ MySQL
This avoids putting database credentials directly into application source code.
For production environments, consider integrating a dedicated secrets-management solution such as HashiCorp Vault or a cloud-native secret manager.
π§Ή Cleanup
Delete the Spring Boot deployment:
kubectl delete -f deployment/app-k8s.yaml
Delete MySQL:
kubectl delete -f deployment/mysql-deployment.yaml
Delete the Kubernetes Secret:
kubectl delete -f deployment/secrets.yaml
Verify:
kubectl get pods
kubectl get svc
kubectl get pvc
kubectl get secrets
Depending on the storage configuration and reclaim policy, deleting the deployment may not automatically remove the underlying persistent storage.
π Code Analysis
The project can also be analyzed using SonarQube.
Configure the SonarQube URL and authentication token in:
gradle.properties
Then execute:
gradle clean build sonar --stacktrace
π― What This Project Demonstrates
This project provides hands-on experience with:
- Spring Boot application deployment on Kubernetes
- Docker containerization
- Kubernetes Deployments
- Kubernetes Services
- Kubernetes Secrets
- PersistentVolumeClaims
- Stateful workloads
- Stateless application deployment
- Kubernetes service discovery
- Spring Boot β MySQL connectivity
- Gradle-based builds
- Container image creation
- Kubernetes-based application lifecycle management
- SonarQube code analysis
π Possible Production Enhancements
For a production-grade deployment, the architecture can be further enhanced with:
- Kubernetes
StatefulSetfor MySQL - MySQL replication / high availability
- Helm charts
- Horizontal Pod Autoscaler (HPA)
- Readiness and liveness probes
- Resource requests and limits
- Ingress / Gateway API
- TLS termination
- External Secrets / Vault
- Prometheus and Grafana monitoring
- OpenTelemetry distributed tracing
- Centralized logging
- CI/CD using GitHub Actions
- Container image vulnerability scanning
- NetworkPolicies
- PodDisruptionBudgets
π References
- Spring Boot
- Kubernetes
- Docker
- MySQL
- Gradle
- SonarQube
β About
This repository is a practical reference implementation for deploying a Spring Boot application with MySQL on Kubernetes and understanding the architectural considerations involved in running both stateless and stateful workloads in a Kubernetes environment.