How to deploy a (native) Quarkus Application on Heroku

10.12.2019

Quarkus is a „container first“ framework for microservice development in Java (or alternatively Kotlin or Scala). With help of GraalVM Native Image, Quarkus applications can be compiled to native executables that run directly on the target OS, without JVM, with low memory footprint and blazing fast startup time.

Heroku is a Cloud Application Platform for building and hosting applications, while various languages can be used for development. It also allows to deploy and run self-built docker images.

Following the instructions from this blog post, we’ll create a native Quarkus application and deploy it in a docker container to the Heroku Runtime.

Prerequisites

The following needs to be installed on our development machine:

  • Java 8 or 11(+)
  • Maven
  • Docker
  • Heroku CLI

 

Creating the Quarkus app

(For more detailed instructions please consult the Quarkus website.)

We can bootstrap a quarkus project using the quarkus-maven-plugin:

$ mvn io.quarkus:quarkus-maven-plugin:1.0.1.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=hello-quarkus \
    -DclassName="org.acme.quickstart.GreetingResource" \
    -Dpath="/hello"

We change into the newly created project directory, and run the application in Quarkus Development Mode:

$ cd hello-quarkus
$ mvn quarkus:dev

Now we can test the application in another terminal. The application already contains a „hello“ REST resource. Request it with curl (or open http://localhost:8080/hello in a browser):

$ curl localhost:8080/hello
hello

Stop the Quarkus Dev Mode with Ctrl+C.

Next, we’ll build the application to a native executable:

$ mvn package -Pnative -Dquarkus.native.container-build=true

With -Pnative we activate a maven profile which creates the native executable. The parameter -Dquarkus.native.container-build=true tells Quarkus to build the application within a docker container. This way we don’t need to have GraalVM installed on our machine, since it’s present in the docker container used for the build. The resulting application will be a Linux executable (even if it’s built on Windows).

Now we go and grab a coffee, since the build will take a while (about 3 minutes on my laptop). The result is a file in the target directory named hello-quarkus-1.0-SNAPSHOT-runner. On Linux or WSL (Windows Subsystem for Linux) you can run it like this:

$ ./target/hello-quarkus-1.0-SNAPSHOT-runner

Now we build a docker image containing this application. The Quarkus app contains a dockerfile to do this, src/main/docker/Dockerfile.native (it’s content without comments is shown below):

FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY target/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

However we cannot use this out of the box, because Heroku requires that the application’s port can be set with the $PORT environment variable. Therefore we need to change the last line to
CMD ./application -Dquarkus.http.host=0.0.0.0 -Dquarkus.http.port=${PORT}. We can also get rid of the line above (EXPOSE 8080), since we don’t really need it. The resulting Dockerfile.native looks like this:

FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY target/*-runner /work/application
RUN chmod 775 /work
CMD ./application -Dquarkus.http.host=0.0.0.0 -Dquarkus.http.port=${PORT}

Using this we build a docker image named quarkus/hello-quarkus

$ docker build -f src/main/docker/Dockerfile.native -t quarkus/hello-quarkus .

… and run with docker:

$ docker run -i --rm --name hello_quarkus --env PORT=8081 -p 8081:8081 quarkus/hello-quarkus

Note how we specify the application’s port via the --env PORT=8081 parameter. Now we can request the „hello“ resource again, this time using port 8081:

$ curl localhost:8081/hello
hello

Deploying the app to Heroku

(The official documentation for this can be found on the Heroku website)

First we log in to our Heroku account:

$ heroku login

Next, we create a Heroku application (replace <app-name> by whatever you want; however it must be unique on Heroku. Leave out the --region eu part if you’re on the American continent; in this case the default region us will be used):

$ heroku create <app-name> --region eu

Log in to the Heroku container registry:

$ heroku container:login

We tag the previously built docker image and push it to the Heroku container registry (replacing <app-name> by the name of our Heroku app again):

$ docker tag quarkus/hello-quarkus registry.heroku.com/<app-name>/web
$ docker push registry.heroku.com/<app-name>/web

Finally, we instruct Heroku to run the image like so (don’t forget to replace <app-name>):

$ heroku container:release web -a <app-name>

Done! Now we can request the „hello“ resource from our app running on Heroku (replacing <app-name> again, you’ll guess):

$ curl https://<app-name>.herokuapp.com/hello
hello

Conclusion

It’s not too hard to deploy a Quarkus app to Heroku. Most of the time we could just follow the instructions from the official documentation. The only thing we needed to do was adjust the Dockerfile, to meet Heroku’s requirement that the application’s port can be set via the $PORT environment variable.

Zurück zur Übersicht

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*Pflichtfelder

*