How to deploy Graalvm native image to production server?

I have always struggled with deployment. I would really like to learn how to setup a robust CI/CD pipeline I can use on every project that will deploy a graalvm native image to a production server.

I can build the image locally. I even created a GitHub action to build it there. Then what?

Honestly, I don’t care where it goes. I have used Railway for a while because it’s easy, but Java is not a first class citizen there and the documentation doesn’t cover this use case.

I would really love to see someone publish a detailed post or video about this critical part of the job of building apps. And/or, I’d be happy to pay someone for the training. I’ve wasted so much time on trying to figure this out myself. :confounded:

Here’s what I use to deploy my Vaadin Docs Assistant demo to fly.io docs-assistant/.github/workflows/deploy.yml at main · marcushellberg/docs-assistant · GitHub

With this, it builds and deploys the app whenever I commit to the main branch.

1 Like

Thanks! Maybe I’ll copy that. I was trying to do the same thing to Railway, but couldn’t get it to work.

Could you share some of your experiences or useful documentation?

I was able to build the executable, but I did not add any hints and couldn’t invest more time because it is not a high prio project. So when starting the server, some Spring Beans were not found and the server crashes on startup.

Hey Marcus, how do you control the vaadin-docs-assistant variable? When I compile locally it ends up being called Application and I don’t know why.

COPY --from=build /usr/src/app/target/vaadin-docs-assistant /app/vaadin-docs-assistant

And did you see my other post about modify the build args? Do you know how to do that?

This is really interesting. I think one of my confusions in the past has been that I try to use the github action to build the native image then send it to Railway, but here you are doing that in the Dockerfile. I’m trying that now.

The name vaadin-docs-assistant is defined in pom.xml. If you are using a standard starter and haven’t changed the application name in your maven file, it’s likely application or similar.

1 Like

Either should work. I prefer to have a build stage in the dockerfile so that the builds are the same regardless of where they run.

1 Like

Yes! I see it now. I added this at some point when I was trying to get the build args to work.

<properties>
        <java.version>23</java.version>
        <vaadin.version>24.5.0.beta5</vaadin.version>
        <eclipsestore.version>1.4.0</eclipsestore.version>
        <mainClass>dev.nathanlively.Application</mainClass>
        <imageName>Application</imageName>
    </properties>

My first attempt failed because it could reach the health endpoint. I notice that in your fly.toml you expose the port. Maybe I need something similar.

Disabling the health endpoint got he deploy to work but then EclipseStore made it crash.

Sadly, looks like this goal is still a bit beyond my skill level. The repo from Marcus helped a lot, but it’s still crashing with errors related to EclipseStore that I don’t understand. Maybe I’m not exposing some port. I don’t know.

Are you able to run the app as a native binary locally? If you’re having trouble with eclipsestore, it sounds like the issues aren’t with the deployment as much as the native compilation

Most likely, you need to give some runtime hints to the AOT compiler for it to pick up all the classes/resources that require reflection. Ahead of Time Optimizations :: Spring Framework

1 Like

Are you able to run the app as a native binary locally?

No, exact same issue locally. Maybe I’ll post the question to Stackoverflow.

you need to give some runtime hints to the AOT compiler

Probably. I did try using the tracing agent.

There are two ways to deal with this. If you are using reflection for objects in your own code, you can let the AOT compiler know about that with a @RegisterReflectionForBinding annotation (see docs).

If it fails on classes in other libraries, like eclipsestore, you’ll need to include some runtime hints, like I reported here for Spring AI. See the Spring docs here: Ahead of Time Optimizations :: Spring Framework

1 Like