Skip to content

Latest commit

 

History

History
97 lines (68 loc) · 3.86 KB

3_nativeImage.md

File metadata and controls

97 lines (68 loc) · 3.86 KB

3. Building Native Image

In this lab you will get familiar with building the Micronaut application and using Docker to build the native image.

Background

GraalVM Native Image allows you to ahead-of-time compile Java code to a standalone executable, called a native image. This executable includes the application, the libraries, the JDK and does not run on the Java VM, but includes necessary components like memory management and thread scheduling from a different virtual machine, called “Substrate VM”. Substrate VM is the name for the runtime components (like the deoptimizer, garbage collector, thread scheduling etc.). The resulting program has faster startup time and lower runtime memory overhead compared to a Java VM.

For more information you can refer to the official documentations https://www.graalvm.org/docs/reference-manual/aot-compilation/

1. Build the fatjar

Let's build the Micronaut application by going to the project directory (i.e. where the gradlew files are)

$ ./gradlew assemble

The builds the ./build/libs/complete-0.1.jar. As a standlone Micronaut application, you can run the application by using HotSpot JVM.

$ java -jar ./build/libs/complete-0.1.jar

2. Create Native Image inside Docker

Including Ruby engine

Since our example includes Ruby scripts, we need to modify the default Dockerfile (generated by Micronaut) to include the Ruby engine by GraalVM.

Edit the Dockerfile with your text editor (e.g. vim).

FROM oracle/graalvm-ce:19.0.0 as graalvm
COPY . /home/app/complete
WORKDIR /home/app/complete
RUN gu install native-image
#Install the GraalVM ruby engine
RUN gu install ruby 
#specify the guest language
RUN native-image --no-server --language:ruby -cp build/libs/complete-*.jar 

FROM frolvlad/alpine-glibc
EXPOSE 8080
COPY --from=graalvm /home/app/complete .
ENTRYPOINT ["./complete"]
Docker build

As we are accessing the compute instance with SSH, we will run the docker build as a back-end process and pipe the output into a log file. We can then tail the log file to check the progress.

$ sudo ./docker-build.sh >> log.out &
[1] 26493
$ sudo tail -f log.out

The building process will takes some time as it will process all the classes and dependencies of the application, including those from the JDK. It statically analyses these classes to determine which classes and methods are reachable and used during application execution. Then it passes all this reachable code as the input to the GraalVM compiler which ahead-of-time compiles it to the native binary.

Note: In case the SSH connection got disconnected due to whatever reason, you can safely reconnect and check the progress again by doing a tail on the log file.

After the docker image is successfully built, it should show up in the list of Docker images locally.

$ sudo docker images -a

3. Running the Container

We can now run the application by running the Docker container.

$ sudo docker run -p 8080:8080 complete

After the server is started, you can open another terminal and access the service.

$ curl localhost:8080/meetup/random 
{"name":"Autonomous Data Warehouse"}

$ curl localhost:8080/abs/java/-99
running abs in Java -> 99

$ curl localhost:8080/abs/ruby/-99
running abs in Ruby -> 99

4. Stopping the Container

Open another terminal and stop the running container.

$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
31f17c304311        complete            "./complete"        1 hours ago        Up 1 hours         0.0.0.0:8080->8080/tcp   zealous_saha

$ sudo docker stop 31f17c304311
31f17c304311