In the previous post, I created a todo application using Quarkus and Java. In this post, I am going to see how to create a GraalVM Native Image for the same.
First of all, package the application using native profile. The following command will create a linux executable file using maven native profile. Note that you should have a working container runtime (docker or podman) environment for this to work.
mvnw package -Pnative -Dquarkus.native.container-build=true
The second argument (quarkus.native.container-build) is needed only if GraalVM is not installed in your machine. After successful completion of this command, you will be able to find a todo*-runner executable file created in the target folder.
Now lets create a docker image for this executable file. Quarkus by default ships different types of docker files in the auto-generated code. Since our point of interest is a native image, we will make use of the native Dockerfile here.
docker build -f src/main/docker/Dockerfile.native -t quarkus/todo .
The above command creates a docker image out of the linux executable file. Now we can run this container using the docker run command.
docker run -p 8080:8080 quarkus/todo
Start up failed? Yes, there is still something missing, you can already see from the docker logs that the application cannot connect to mongodb database. Lets run a mongodb container and see if it works.
docker run -p 27017:27017 mongo:latest
With the above command, we are running a mongodb container. You can try connecting to this container from mongoshell or some other client application. The connection should normally work.
But the connection from our todo app container to mongodb container will still not work.
After some analysis I found that a communication from one docker container to another needs additional setup/configuration. There are different ways by which we can achieve this communication – like setting up a network, setting up a link or to create a docker compose file. I chose the most simplest solution, to use a docker-compose.yml file so that everything is in code.
Here is my docker-compose.yml file
version: '3.8'
services:
web:
build:
context: .
dockerfile: src/main/docker/Dockerfile.native
ports:
- 127.0.0.1:8080:8080
mongo:
image: mongo:4.4.4
ports:
- 127.0.0.1:27017:27017
The docker-compose file builds a docker image using Dockerfile.native file and runs it on port 8080. Also it runs a mongo image on port 27017. On top of this, I had to do a little change in my application.properties to change the host name in the connection string from localhost to the container name (mongo).
quarkus.mongodb.connection-string = mongodb://mongo:27017
Before changing the property, lets copy the application.properties file to test/resources directory so that the change will not impact the tests.
Again package the application using mvnw package -Pnative -Dquarkus.native.container-build=true command. A new todo*-runner file is created in target folder.
Now run docker-compose up command to build and run the docker image. Normally it takes only few milliseconds to bring up a native image application. Since we are doing docker build and mongodb start in the same docker-compose, the startup time might go for a couple of seconds.
Quarkus provides a way to test native image using @NativeImageTest annotation. Lets look at it in the future chapters. I hope this post was informative, please comment out to share your suggestions and feedback.
1 Comment