Spring Boot MySQL Kubernetes Minikube Example
Spring Boot MySQL Kubernetes Minikube Example
Introduction
Kubernetes is one of the best and most popular
ways to deploy any application on the cloud today. There are many tutorials
based on hello world kind of applications online, but they cannot be used to
understand the full end to end implementation/deployment steps on Kubernetes.
Hence I decided to come up with this tutorial.
In this tutorial we will be deploying a
Spring Boot MySQL Microservice on Kubernetes. We will be using a local
minikube cluster to deploy this microservice.
If you are a beginner in Docker, Containers,
Docker Images and using Dockerfile, then I strongly recommend that you read
the blog posts below to understand more about them:
- Dropwizard Docker Example: This post gives you an overview of Docker, simple Docker commands, Dockerfile, dockerizing a simple application and Docker Hub
- Spring Boot MySQL Docker Compose Example: This post helps you to understand about multi-container Docker applications and how to run a microservice on Docker.
Kubernetes (K8s)
Kubernetes is an open-source
container-orchestration system for automating deployment, scaling, and
management of containerized applications. You must be wondering as to why it
is called K8s. K and s are the starting and ending
letters of Kubernetes and 8 stands for the eight letters between K and
s. It was originally designed and built by Google but now it is open
sourced. It works with a range of container tools, including
Docker.
Some of the significant features of Kubernetes are:
- Automated rollouts and rollbacks
- Service discovery and load balancing
- Horizontal scaling
- Self-healing
- Storage orchestration
- Secret and configuration management
- Batch execution
You can read more about it on:
Kubernetes Website.
Minikube
Minikube is a tool that helps to run
Kubernetes locally and easily. Minikube runs a single-node Kubernetes
cluster inside a Virtual Machine (VM) on the laptop for users looking to
try out Kubernetes.
Minikube provides us the following Kubernetes features:
- NodePorts
- DNS
- ConfigMaps, Secrets, PersistentVolumes
- Dashboards
- Container runtime
- Ingress
- Enabling Container Network Interface (CNI)
You can read more about Minikube on: Kubernetes Website.
Requirements to Run the Spring Boot MySQL Microservice on Docker:
Minikube should be setup and running in your machine. To setup and run
minikube, please refer to my post on: Minikube Setup.
Once Minikube setup is completed, the Spring Boot MySQL microservice can be run on it in a few simple steps.
2. GET API to get all employees:
- Kubectl
- VirtualBox
- Minikube
If you would like to understand the microservice we are running in this
post, please check my blog post on Spring Boot MySQL Integration by
going to the link: Spring Boot MySQL Integration Tutorial.
Please Note:
If you already have a Spring Boot and MySQL App container that you have
created, this example will not work for you unless you have a container
created using Docker Compose and have
environment variables defined in it. The app container needs to be
created using this: docker-compose.yml.
Once Minikube setup is completed, the Spring Boot MySQL microservice can be run on it in a few simple steps.
Step 1: Create required Kubernetes Secrets
Kubernetes Secrets helps us to manage and store sensitive
information like passwords, ssh keys and OAuth tokens. Secrets are stored in
etcd. etcd is a consistent and highly-available key value store used as
Kubernetes' backing store for all cluster data. Secrets can be stored in an
encrypted form by enabling encryption. To know more, please read:
Kubernetes Secrets Documentation.
In this post I am using Kubernetes Secrets to store MySQL database
credentials.
Please Note:
All minikube and kubectl commands are to be run in the
Minikube installation directory. For me this is:
/d/Programs/Kubernetes/Minikube.
Lets begin by stating Minikube. I have observed that the apiserver in
Minikube keeps shutting down if the memory allocated or CPUs allocated is
less. Hence I am allocating 4 GB memory and 2 CPUs for Minikube using the
command below:
MINGW64 /d/Programs/Kubernetes/Minikube $ minikube --memory 4096 --cpus 2 startCheck if minikube is running by using status command below:
MINGW64 /d/Programs/Kubernetes/Minikube $ minikube status minikube type: Control Plane host: Running kubelet: Running apiserver: Running kubeconfig: Configured
Secrets are created using kubectl commands below:
$ kubectl create secret generic mysql-root-pass --from-literal=password=r00t secret/mysql-root-pass created $ kubectl create secret generic mysql-user-pass --from-literal=username=ajtechdeveloper --from-literal=password=@jtechd3v3l0p3r secret/mysql-user-pass created $ kubectl create secret generic mysql-db-url --from-literal=database=softwaredevelopercentral --from-literal=url='jdbc:mysql://springbootmysql-app-mysql:3306/softwaredevelopercentral?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false' secret/mysql-db-url created
Step 2: Create MySQL Deployment yaml and deploy
To deploy MySQL Database we will use
Kubernetes Persistent Volume (PV) which is a piece
of storage in the Kubernetes cluster. A
PersistentVolumeClaim (PVC) is a request for storage by a user just
like a pod. Pods consume node resources whereas PVCs consume PV
resources. To know more, please read:
Kubernetes Persistent Volume Documentation.
For MySQL Database deployment, a yaml files needs to be created. We will use
both Kubernetes Secrets and Kubernetes Persistent Volume in this yaml file. If you observe in this yaml, I am using the image:
MySQL version 5.7 . You can understand the yaml file by reading the
comments that I have added. Here is the
file: mysql-deployment.yaml:
apiVersion: v1 kind: PersistentVolume # Create PersistentVolume which is required for MySQL Database metadata: name: mysql-pv labels: type: local spec: storageClassName: standard # Storage class. A PersistentVolume Claim requesting the same storageClass can be bound to this volume. capacity: storage: 250Mi accessModes: - ReadWriteOnce hostPath: # hostPath PersistentVolume is used for both development and testing. It uses a file (or)directory on the Node to emulate the network-attached storage path: "/mnt/data" persistentVolumeReclaimPolicy: Retain # Retain the PersistentVolume even after PersistentVolumeClaim is deleted. The volume is considered “released”. But it is not yet available for another claim because the previous claimant’s data remains on the volume. --- apiVersion: v1 kind: PersistentVolumeClaim # Create PersistentVolumeClaim to request a PersistentVolume storage metadata: # The claim name and labels name: mysql-pv-claim labels: app: springbootmysql-app spec: # Access mode and the resource limits storageClassName: standard # Request certain storage class accessModes: - ReadWriteOnce # ReadWriteOnce means that the volume can be mounted as read-write by a single Node resources: requests: storage: 250Mi --- apiVersion: v1 # The API version kind: Service # Type of kubernetes resource metadata: name: springbootmysql-app-mysql # Name of the resource labels: # Labels that will be applied to the resource app: springbootmysql-app spec: ports: - port: 3306 selector: # Selects any Pod with labels `app=springbootmysql-app,tier=mysql` app: springbootmysql-app tier: mysql clusterIP: None --- apiVersion: apps/v1 kind: Deployment # Type of kubernetes resource metadata: name: springbootmysql-app-mysql # Name of the deployment labels: # Labels applied to this deployment app: springbootmysql-app spec: selector: matchLabels: # This deployment applies to the Pods matching the specified labels app: springbootmysql-app tier: mysql strategy: type: Recreate template: # Template for Pods in this deployment metadata: labels: # Labels to be applied to the Pods in this deployment app: springbootmysql-app tier: mysql spec: # The spec for the containers that will be run inside the Pods in this deployment containers: - image: mysql:5.7 # The container image name: mysql env: # Environment variables passed to the container - name: MYSQL_ROOT_PASSWORD valueFrom: # Read environment variables from kubernetes secrets secretKeyRef: name: mysql-root-pass key: password - name: MYSQL_DATABASE valueFrom: secretKeyRef: name: mysql-db-url key: database - name: MYSQL_USER valueFrom: secretKeyRef: name: mysql-user-pass key: username - name: MYSQL_PASSWORD valueFrom: secretKeyRef: name: mysql-user-pass key: password ports: - containerPort: 3306 # The port that the container exposes name: mysql volumeMounts: - name: mysql-persistent-storage # This name should match the name specified in `volumes.name` mountPath: /var/lib/mysql volumes: # A PersistentVolume is mounted as a volume to the Pod - name: mysql-persistent-storage persistentVolumeClaim: claimName: mysql-pv-claimTo deploy this in Minikube, we use the kubectl command below:
$ kubectl apply -f /d/projects/gitprojects/SpringBootMySQL/deployments/mysql-deployment.yamlTo log into the MySQL database pod, get its pod name using the command below:
$ kubectl get pods NAME READY STATUS RESTARTS AGE springbootmysql-app-mysql-7fbc9f88cc-7kxgk 1/1 Running 3 7d17hPort forward the pod's port 3306 to your computer localhost (127.0.0.1) port 3306. Then you can use an installed existing MySQL client in your computer to log into the database. Use the command below for port forwarding:
$ kubectl port-forward springbootmysql-app-mysql-7fbc9f88cc-7kxgk 3306:3306 Forwarding from 127.0.0.1:3306 -> 3306 Forwarding from [::1]:3306 -> 3306 Handling connection for 3306The open a new windows command prompt window, navigate to the MySQL installation location bin folder and login to the database using the command below, use the password r00t when prompted:
D:\Programs\mysql-5.7.19-winx64\bin>mysql -u root -p -h 127.0.0.1Here are a few commands to execute after logging into the MySQL Database:
> show databases; > use softwaredevelopercentral;In this post, I am using a simple Employee Table to perform CRUD operations. Here is the script to create this table in the MySQL Database:
create table employee ( id int not null auto_increment primary key, name varchar(50), department varchar(50), salary int(20) );
Step 3: Create Spring Boot App Deployment yaml and deploy
If you observe in this yaml, I am using the image (ajtechdeveloper/springbootmysql-app:latest) that I created using Docker Compose and published to Docker Hub in the
post: Spring Boot MySQL Docker Compose Example. You can understand the yaml file by reading the comments that I have
added. Here is the file: springboot-app-server.yaml:
--- apiVersion: apps/v1 # The API version kind: Deployment # Type of Kubernetes resource metadata: name: springbootmysql-app-server # Name of the Kubernetes resource labels: # Labels that will be applied to this resource app: springbootmysql-app-server spec: replicas: 1 # No. of replicas (or) pods to run in this deployment selector: matchLabels: # The deployment applies to any pods mayching the specified labels app: springbootmysql-app-server template: # Template for creating the pods in this deployment metadata: labels: # Labels that will be applied to each Pod in this deployment app: springbootmysql-app-server spec: # Specification for the containers that will be run in the Pods containers: - name: springbootmysql-app-server image: ajtechdeveloper/springbootmysql-app:latest imagePullPolicy: IfNotPresent ports: - name: http containerPort: 4000 # The port that the container exposes resources: limits: cpu: 0.8 memory: "1Gi" # This Spring Boot App needs around 700 MB Memory env: # Environment variables supplied to the Pod - name: SPRING_DATASOURCE_USERNAME # Name of the environment variable valueFrom: # Get the value of environment variable from kubernetes secrets secretKeyRef: name: mysql-user-pass key: username - name: SPRING_DATASOURCE_PASSWORD valueFrom: secretKeyRef: name: mysql-user-pass key: password - name: SPRING_DATASOURCE_URL valueFrom: secretKeyRef: name: mysql-db-url key: url --- apiVersion: v1 # The API version kind: Service # Type of the kubernetes resource metadata: name: springbootmysql-app-server # Name of the kubernetes resource labels: # Labels that will be applied to this resource app: springbootmysql-app-server spec: type: NodePort # The service will be exposed by opening a Port on each node and proxying it. selector: app: springbootmysql-app-server # The service exposes Pods with label `app=springbootmysql-app-server` ports: # Forward incoming connections on port 4000 to the target port 4000 - name: http port: 4000 targetPort: 4000To deploy this in Minikube, we use the kubectl command below:
$ kubectl apply -f /d/projects/gitprojects/SpringBootMySQL/deployments/springboot-app-server.yamlTo check the details of all pods, services, deployments and replicasets in the Kubernetes cluster use the command below:
$ kubectl get allHere is the output:
$ kubectl get all NAME READY STATUS RESTARTS AGE pod/springbootmysql-app-mysql-7fbc9f88cc-7kxgk 1/1 Running 3 7d14h pod/springbootmysql-app-server-84488b465d-8dkk5 1/1 Running 1 6d17h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7d14h service/springbootmysql-app-mysql ClusterIP None <none> 3306/TCP 7d14h service/springbootmysql-app-server NodePort 10.106.245.185 <none> 4000:30657/TCP 6d17h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/springbootmysql-app-mysql 1/1 1 1 7d14h deployment.apps/springbootmysql-app-server 1/1 1 1 6d17h NAME DESIRED CURRENT READY AGE replicaset.apps/springbootmysql-app-mysql-7fbc9f88cc 1 1 1 7d14h replicaset.apps/springbootmysql-app-server-84488b465d 1 1 1 6d17hTo describe a pod, get the pod name and use the command below:
$ kubectl describe pod springbootmysql-app-server-84488b465d-8dkk5To check pod logs, get the pod name and use the command below:
$ kubectl logs --tail=2000 springbootmysql-app-server-84488b465d-8dkk5To check the service URL get the service name and use the command below:
$ minikube service springbootmysql-app-server |-----------|----------------------------|-------------|-----------------------------| | NAMESPACE | NAME | TARGET PORT | URL | |-----------|----------------------------|-------------|-----------------------------| | default | springbootmysql-app-server | http/4000 | http://192.168.99.100:30004 | |-----------|----------------------------|-------------|-----------------------------| * Opening service default/springbootmysql-app-server in default browser...Now the Spring Boot service APIs can be accessed using the url: http://192.168.99.100:30004/
API calls when the service is running:
1. POST API to create an employee
JSON Request Body:
{ "name": "Mary", "department": "Accounts", "salary": 10000 }
2. GET API to get all employees:
3. GET API to get employee by NAME
4. PUT API to update an employee
http://192.168.99.100:30004/employee
JSON Request Body:http://192.168.99.100:30004/employee
{ "id":1, "name": "Mary", "department": "Accounts", "salary": 12000 }
5. DELETE API to delete an employee by ID
Other than these APIs, this application has the following APIs:
1. GET API to Ping and test if the application is up and running:
2. POST API to Ping and test if the application is up and running:
JSON Request Body:
{ "input": "ping" }
Delete Service and Deployment
To delete service, get the service name and use the command below:
$ kubectl delete services springbootmysql-app-server
To delete deployment, get the deployment name and use the command below:
$ kubectl delete deployment springbootmysql-app-server
Stop Minikube
To stop Minikube, use the command below:$ minikube stop
Conclusion, Docker Hub Link and GitHub link:
This tutorial gives a comprehensive overview of running a Spring Boot MySQL microservice on Minikube. The code for the Spring Boot MySQL application used in this post is available on GitHub. The docker image used in this post is available on Docker Hub. Learn the most popular and trending technologies like Blockchain, Cryptocurrency, Machine Learning, Chatbots, Internet of Things (IoT), Big Data Processing, Elastic Stack, React, Highcharts, Progressive Web Application (PWA), Angular 5, GraphQL, Akka HTTP, Play Framework, Dropwizard, Docker, Netflix Eureka, Netflix Zuul, Spring Cloud, Spring Boot, Flask and RESTful Web Service integration with MongoDB, Kafka, Redis, Aerospike, MySQL DB in simple steps by reading my most popular blog posts at Software Developer Central.
If you like my post, please feel free to share it using the share button just below this paragraph or next to the heading of the post. You can also tweet with #SoftwareDeveloperCentral on Twitter. To get a notification on my latest posts or to keep the conversation going, you can follow me on Twitter or Instagram. Please leave a note below if you have any questions or comments.
If you like my post, please feel free to share it using the share button just below this paragraph or next to the heading of the post. You can also tweet with #SoftwareDeveloperCentral on Twitter. To get a notification on my latest posts or to keep the conversation going, you can follow me on Twitter or Instagram. Please leave a note below if you have any questions or comments.
This was an excellent tutorial for a beginner to learn how to create spring boot app and mysql within kubernetes.
ReplyDeleteWhile going through it, I discovered one minor typo and corrected this line:
kubectl create secret generic mysql-db-url --from-literal=database=softwaredevelopercentral --from-literal=url='jdbc:mysql://springbootmysql-app-mysql:3306/softwaredevelopercentral?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false'
Instead of springboot-app-mysql we want springbootmysql-app-mysql
Also I learned how to create the table without having to use the port forwarding step. You can access mysql within the docker bash:
kubectl exec --stdin --tty pod/YOUR-MYSQL-POD-NAME-HERE -c mysql -- /bin/bash
mysql -u root -p
the password is r00t which has 2 zeros
Once connected to mysql, you can continue to follow your steps to create the employee table. I was then able to use Postman to add employees.
Awesome tutorial - I learned a lot and enjoyed working through it!
Hi @brandon
DeleteThanks for your comment. Yes, there is a typo error, thanks for pointing that out. I have just corrected it.