Optimising Performance with GraalVM: Running Spring Boot Native Image on Kubernetes
In the previous article, I explained how to migrate an existing Spring Boot application to use GraalVM native image, which can offer faster startup times and lower memory usage. In this article, we’ll take the next step and explore how to deploy the GraalVM built native executable on Kubernetes. By using Kubernetes, you can easily manage and scale your application, and take advantage of the platform’s built-in features like load balancing and auto-scaling. We’ll walk through the steps for creating a Docker image using a Dockerfile, pushing the image to a container registry, creating a Kubernetes deployment file, and exposing the application to the outside world.
Creating Dockerfile
#Use GraalVM Maven base image
FROM vegardit/graalvm-maven:22.3.1-java17
COPY src /home/app/src
COPY pom.xml /home/app
#Build a native executable
RUN mvn -f /home/app/pom.xml -Pnative native:compile
WORKDIR /home/app/target
#Expose port on which Spring Boot app will run
EXPOSE 9092
#Switch to non root user
USER 1001
#Entrypoint command present in Kubernetes deployment
- FROM: This step specifies the base image to use, which is
vegardit/graalvm-maven:22.3.1-java17
. This means that the Docker image will be built on top of the GraalVM Maven base image.I have used this image as it contains Maven pre-installed with GraalVM. - COPY: This step copies the source code of the Spring Boot application to the
/home/app/src
directory in the Docker image, and thepom.xml
file to the/home/app
directory. - RUN: This step uses the
mvn
command to build a native executable for the Spring Boot application, by specifying the Maven project file using the-f
option and the native profile using the-P
option. Thenative:compile
command tells Maven to compile the application to a native executable. - WORKDIR: This step sets the working directory to
/home/app/target
. - EXPOSE: This step exposes the port
9092
on which the Spring Boot application will run. This means that when the Docker container is run, this port will be available for other containers or for external clients to access the application. - USER: This step sets the user ID to
1001
, which is a non-root user. This is a best practice for security reasons, as running an application as a non-root user can reduce the risk of security vulnerabilities. - ENTRYPOINT: This step is not present in this Dockerfile, but it is mentioned in the description as being present in the Kubernetes deployment. The entrypoint is the command that is executed when the Docker container is run. In this case, it would be the command to start the Spring Boot application.
Running the application on Kubernetes
Build the Docker image using the Dockerfile. You can do this by running the following command in the same directory as the Dockerfile:
docker build -t your-image-name:version .
Push the Docker image to a container registry. This can be a public registry like Docker Hub or a private registry that you have set up for your organization. Make sure to authenticate with the registry before pushing the image.
docker push your-image-name
Create a Kubernetes deployment file that specifies the Docker image to use, the number of replicas to create, and any other configuration for the deployment. Here’s an example of a deployment file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: your-deployment-name
spec:
replicas: 1
selector:
matchLabels:
app: your-app-name
template:
metadata:
labels:
app: your-app-name
spec:
containers:
- name: your-container-name
image: your-image-name
command: ["./your-executable-name","-Djavax.net.ssl.trustStore=/opt/certs/truststore.jks","-Djavax.net.ssl.trustStorePassword=changeit"]
ports:
- containerPort: 9092
The Entrypoint command is provided in the command
key which basically runs the executable and additionally passes arguments to load a custom trust store and supplies the password of the trust store.
You can also add your poperties on ConfigMap and application passwords on Secrets.
Apply the deployment file to your Kubernetes cluster using the kubectl apply
command:
kubectl apply -f your-deployment-file.yaml
Verify that the deployment and pod have been created using the kubectl
command:
kubectl get deployments
kubectl get pods
To expose the application to the outside world, create a Kubernetes Service using the kubectl expose
command:
kubectl expose deployment your-deployment-name --type=LoadBalancer --port=80 --target-port=9092
If you liked the article please take a minute to offer me a clap 👏 or even buy me a coffee https://www.buymeacoffee.com/abhiandy