Running in Minikube (Kubernetes) a Reactive App that uses Spring WebFlux and MongoDB
Step-by-step guide on how to run Book API in Minikube (Kubernetes)
In this article, we will demonstrate how to locally set up Minikube (Kubernetes) on our machines and deploy, within it, an instance of a Spring Boot Reactive application called Book API. Additionally, we’ll show you how to deploy an instance of the MongoDB database in Minikube, which the Book API relies on for storage.
You can find the complete code and implementation of Book API in the article linked below. Feel free to follow the steps explained in the article and get started.
So, let’s get started!
Prerequisites
To follow along with this guide, beside Java 17+ and Docker, please ensure that you have the Minikube, Kubectl and VirtualBox installed on your machine.
Updating Book API App
When we use Kubernetes to control our apps, it takes care of keeping the pods healthy. For example, it makes sure our apps only start handling requests when they’re ready. If a pod’s main process stops working, Kubernetes restarts the container.
To do this job, Kubernetes uses two probes: readiness and liveness. The readiness probe checks if an app is ready to get requests. The liveness probe checks if a pod is still going. This helps decide when to restart a container.
Now, let’s add the Actuator tool and enable the liveness and readiness probes.
Add the Actuator Dependency
In the pom.xml file, let’s include the Actuator dependency by adding the following code (highlighted in bold):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
...
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
...
</dependencies>
...
</project>It was added because it provides built-in endpoints for checking the application’s health, including specific ones for liveness and readiness probes.
Enable the Liveness and Readiness Probes
In the application.properties, let’s enable the liveness and readiness probes by adding the following code (highlighted in bold):
management.endpoint.health.probes.enabled=trueCreating YAML Deployment files
Create k8s folder
Inside the book-api root folder, let’s create a folder called k8s.
Create MongoDB YAML Deployment file
Inside the k8s folder, let’s create a file named mongodb.yaml and include the following content:
apiVersion: v1
kind: Service
metadata:
name: mongodb
labels:
app: mongodb
spec:
type: ClusterIP
ports:
- port: 27017
selector:
app: mongodb
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongodb
labels:
app: mongodb
spec:
replicas: 1
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongodb
image: mongo:7.0.4
ports:
- containerPort: 27017This YAML file sets up a mongodb service and deployment. The service makes the database accessible within the cluster via ClusterIP, and the deployment ensures that the specified MongoDB image is run within a pod with the given configuration.
Create Book API YAML Deployment file
Inside the k8s folder, let’s create the book-api.yaml with the content below:
apiVersion: v1
kind: Service
metadata:
name: book-api
labels:
app: book-api
spec:
type: LoadBalancer
ports:
- name: http
port: 8080
targetPort: 8080
selector:
app: book-api
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: book-api
spec:
replicas: 1
selector:
matchLabels:
app: book-api
template:
metadata:
labels:
app: book-api
spec:
containers:
- name: book-api
image: book-api:0.0.1-SNAPSHOT
imagePullPolicy: Never
ports:
- name: http
containerPort: 8080
env:
- name: MONGODB_HOST
value: mongodb
- name: MONGODB_PORT
value: "27017"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: http
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: httpThis YAML file sets up a Book API service and deployment. The service is a LoadBalancer, exposing the port 8080 for external access. The deployment creates a single pod with the book-api:0.0.1-SNAPSHOT image and configuration, connecting to a MongoDB database. The configuration includes liveness and readiness probes.
Start Environment
In a terminal, make sure you are in the book-api root folder.
Start Minikube
Run the following command to start Minikube:
minikube start --memory=8192 --cpus=2 --vm-driver=virtualbox
Create dev namespace
Once Minikube is up and running, let’s create a namespace called dev. For it, run the command below:
kubectl create namespace dev
To delete the
devnamespace, run:kubectl delete namespace dev
Deploy MongoDB
Let’s deploy MongoDB by running the following command:
kubectl -n dev apply -f k8s/mongodb.yaml
To delete the
mongodbdeployment, run:kubectl -n dev delete -f k8s/mongodb.yaml
Watching Deployment
We can watch the MongoDB deployment by running the following command:
kubectl -n dev get pods -w
To stop watching, press:
Ctrl+C
Please be patient as MongoDB Docker image will be pulled before we can proceed further. After a few seconds, the MongoDB instance should be up and running. To confirm this, you can use the following command:
kubectl -n dev get pods
You should see something like:
NAME READY STATUS RESTARTS AGE mongodb-65f498b766-2t2mm 1/1 Running 0 114s
Building Book API Docker image
In a terminal, let’s execute the following command to sets up our local Docker environment to use Minikube’s Docker daemon:
eval $(minikube docker-env)Make sure you are in the book-api root folder. To build the Book API Docker image, run the following command:
./mvnw clean spring-boot:build-image -DskipTests
After the completion of the above command, the Book API Docker image will be available within Minikube. You can verify this by executing the following command:
docker images
Let’s switch back to our local host Docker daemon by running the command below:
eval $(minikube docker-env -u)Deploying Book API
In a terminal, ensure that you are in the book-api root folder. Then, execute the following command to deploy the Book API:
kubectl -n dev apply -f k8s/book-api.yaml
To delete the
book-apideployment, run:kubectl -n dev delete -f k8s/book-api.yaml
After a few seconds, the Book API instance should be up and running. To confirm this, you can use the following command:
kubectl -n dev get pods -l app=book-api
You should see something like:
NAME READY STATUS RESTARTS AGE book-api-559ddd9bcd-dl52h 1/1 Running 0 13s
Testing Endpoints
In a terminal, run the following command to get the BOOK_API_HOST_PORT:
BOOK_API_HOST_PORT="$(minikube ip):$(kubectl get services -n dev book-api -o go-template='{{(index .spec.ports 0).nodePort}}')"
echo $BOOK_API_HOST_PORTLet’s retrieve all books:
curl -i $BOOK_API_HOST_PORT/api/booksAs there is no book registered, we should get:
HTTP/1.1 200 OK transfer-encoding: chunked Content-Type: application/x-ndjson
Let’s create a book:
curl -i -X POST $BOOK_API_HOST_PORT/api/books \
-H 'Content-Type: application/json' \
-d '{"title": "Spring in Action", "author": "Craig Walls and Ryan Breidenbach", "year": 1005}'It should return:
HTTP/1.1 201 Created
Content-Type: application/json
...
{"id":"657992b3a1e4811acc14e2b7","title":"Spring in Action","author":"Craig Walls and Ryan Breidenbach","year":1005}Note: In my case, the book ID is
657992b3a1e4811acc14e2b7. For you, it will be different.
In order to facilitate the writing of this article, we will export to an environment variable the book ID. For it, run the following command in the terminal where you are performing the calls to Book API endpoints:
BOOK_ID=<the-created-book-id>
Again, let’s retrieve all books:
curl -i $BOOK_API_HOST_PORT/api/booksThis time, it should return:
HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: application/x-ndjson
{"id":"657992b3a1e4811acc14e2b7","title":"Spring in Action","author":"Craig Walls and Ryan Breidenbach","year":1005}Let’s update the book year, as it should be 2005 and not 1005:
curl -i -X PATCH $BOOK_API_HOST_PORT/api/books/$BOOK_ID \
-H 'Content-Type: application/json' \
-d '{"year": 2005}'We should get:
HTTP/1.1 200 OK
Content-Type: application/json
...
{"id":"657992b3a1e4811acc14e2b7","title":"Spring in Action","author":"Craig Walls and Ryan Breidenbach","year":2005}Let’s retrieve the book:
curl -i $BOOK_API_HOST_PORT/api/books/$BOOK_IDWe should get as response:
HTTP/1.1 200 OK
Content-Type: application/json
...
{"id":"657992b3a1e4811acc14e2b7","title":"Spring in Action","author":"Craig Walls and Ryan Breidenbach","year":2005}Finally, let’s delete the book:
curl -i -X DELETE $BOOK_API_HOST_PORT/api/books/$BOOK_IDThe response should be:
HTTP/1.1 200 OK
Content-Type: application/json
...
{"id":"657992b3a1e4811acc14e2b7","title":"Spring in Action","author":"Craig Walls and Ryan Breidenbach","year":2005}In case, we try to retrieve a book that does not exist:
curl -i $BOOK_API_HOST_PORT/api/books/$BOOK_IDThe following response should be returned:
HTTP/1.1 404 Not Found
Content-Type: application/json
...
{"timestamp":"2023-12-13T11:19:06.586+00:00","path":"/api/books/657992b3a1e4811acc14e2b7","status":404,"error":"Not Found","requestId":"b6260034-7"}Shutdown
In a terminal, run the following command to delete completely Minikube:
minikube delete
Conclusion
In this article, we have walked through the steps of configuring Minikube for local Kubernetes development. Before deploying the Book API, we added the Actuator dependency and enabled its liveness and readiness probes.
In Minikube, we deployed a single instance of the Book API Reactive app, setting up a MongoDB database as the storage backend. At the end, we test the application endpoints to certify that it is running as expected.
Additional Readings
Support and Engagement
If you enjoyed this article and would like to show your support, please consider taking the following actions:
- 👏 Engage by clapping, highlighting, and replying to my story. I’ll be happy to answer any of your questions;
- 🌐 Share my story on Social Media;
- 🔔 Follow me on: Medium | LinkedIn | Twitter | GitHub;
- ✉️ Subscribe to my newsletter, so you don’t miss out on my latest posts.




