Deploying Quarkus/PostgreSQL and Angular/Nginx on Heroku as containers

Felipe Windmoller
6 min readJul 20, 2021

--

This is a simple tutorial explaining one way of deploying Quarkus/PostgreSQL and Angular/Nginx on Heroku as containers.

Let’s start!

Create the Docker images locally

Clone my demo project:

$ git clone https://github.com/felipewind/heroku-quarkus-angular-docker

Run the script

Run this script to build Quarkus, Angular and then to bring up the docker-compose:

$ ./run-with-local-build.sh

Or do it manually

Build the Quarkus project:

$ cd quarkus/
$ ./mvnw package

Build the Angular project:

$ cd angular/
$ npm install
$ ng build

Bring up the following docker-compose-yml:

$ docker-compose up --build

Images ready and containers running

Now, if everything worked well, you will have three Docker images created:

$ docker images
REPOSITORY TAG
heroku/quarkus-jvm 1.0
heroku/angular 1.0
postgres 13.3

And three containers running.

It’s possible to access the Quarkus Swagger UI at http://localhost:8080/q/swagger-ui/

And the Angular front end at http://localhost

Deploy Quarkus/PostgreSQL on Heroku

After creating your account on Heroku, click on option “Create new app” and chose any name you like.

Click on the Resource tab and select “Heroku Postgres”:

Select the plan you prefer (HobbyDev is free) and now your Heroku application has one PostgreSQL database:

Configuring Quarkus

All we have to do now is push our Quarkus image to the Heroku registry and release it! The executing container will communicate with the database and will expose its endpoints.

Here is the most important part! Our application must receive the database and HTTP port as configuration parameters. To achieve this, we must define these parameters on the application.properties:

This way, our Quarkus container will receive all these parameters from the Heroku environment on deploy time.

PORT parameter

The Heroku application can run two types of processes: WEB and WORKER. The WEB one will be able to receive calls from the outer world. Heroku passes one PORT environment parameter to the WEB container. Each release of your Quarkus container can have a different PORT value and your application must receive this variable dynamically.

Database parameters

We must set the configuration variables of the database so they will match with the Quarkus ones we defined.

Click on the “Settings” tab and then on the “Reveal Config Vars” button:

Heroku DATABASE_URL variable problem

Now we have a problem, the only variable PostgreSQL exposes is DATABASE_URL in a pattern that isn’t the same that Quarkus expects.

Pattern of DATABASE_URL from Heroku:

postgres://username:password@host:port/databasename

Pattern of JDBC variables of Quarkus:

quarkus.datasource.jdbc.url=jdbc:postgresql://host:port/databasename
quarkus.datasource.username=username quarkus.datasource.password=password

Heroku DATABASE_URL variable solution

In this story I explain better about this problem and the two ways that I found to solve it:

Shortly, you have two options

Manual extraction

Create the Quarkus variables on the Heroku Config Vars (DB_JDBC_URL, DB_JDBC_USER and DB_JDBC_PASSWORD) passing the values you extracted from the DATABASE_URL variable.

Using the bash script to extract

Create one variable called DB_HEROKU_SPLIT and set it to true:

The above DB_ECHO_VALUES is optional, if true, the data base values will be printed on the logs.

The heroku.sh script, that is on the root folder of the demo project, will automatically create the Quarkus data source variables from the Heroku DATABASE_URL. I put this script on the Docker file startup command.

Release the Quarkus image on Heroku

Heroku website has a good documentation on how to do this:

Install the Heroku CLI on your machine.

Login on registry.heroku.com:

heroku container:login

Tag your image (<app> is your Heroku app name):

docker tag heroku/quarkus-jvm:1.0 registry.heroku.com/<app>/web

Push it to the registry:

docker push registry.heroku.com/<app>/web 

Release it:

heroku container:release web --app <app>

Check the logs:

heroku logs --app <app> --tail

Click on the Open app button on the top right of your Heroku app managing:

And bingo! You will see the main page of your Quarkus application:

On the end of the URL, just add /q/swagger-ui/ and you will be able to test your app:

The Quarkus part is done !!!

Deploy Angular/Nginx on Heroku

The Angular process will be very similar to the Quarkus process we did before.

Create one new Heroku app to host your Angular front end.

PORT parameter

This app will need to receive the PORT parameter from Heroku and will need to communicate with the Quarkus back end.

On the Angular root folder, create the “nginx” folder and this “default.conf.template” file:

server {
listen $PORT default_server;
location / {
root /usr/share/nginx/html;
index index.html;
}
}

On the start of your Nginx container, include this command:

envsubst '$PORT' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf

API dynamic URL

You can put the URL from your back end directly on the environment.prod.ts file, but here I use a trick to set it dynamically.

The trick is to declare one template name on the environment.prod.ts file and replace this name on the docker command that starts your project.

environment.prod.ts:

export const environment = {
production: true,
apiUrl: 'HEROKU_API_URL'
};

On the Docker startup command, include this:

sed -i s#HEROKU_API_URL#$API_URL#g /usr/share/nginx/html/main.*.js

Create the API_URL variable on the Heroku Config Vars and set the URL of your back end project:

Dockerfile

Here is the complete Dockerfile containing the PORT and the dynamic API_URL trick:

Release the Angular container

Do the same steps of Quarkus (tag, push, release and check de logs) with your Heroku front and app name:

docker tag heroku/angular:1.0 registry.heroku.com/<app>/web
docker push registry.heroku.com/<app>/web
heroku container:release web --app angular-as-container
heroku logs --app angular-as-container --tail

Now click on the “Open app” button of your Angular Heroku app and you should see this simple CRUD front end:

Remember that the Heroku app will be dormant after 30 minutes of inactivity, so if your back end is asleep the HTTP GET requisition from your front end will take some time to answer.

Final words

I hope you enjoyed this tutorial!

If I told something wrong or you had some problem when following it, please just say it on the comments.

Credits

Tutorial explaining how to create one Quarkus application from scratch and how to deploy it on Heroku from a GitHub project:

About the idea of creating one dynamic URL on Angular:

StackOverflow question explaining how to configure the Nginx PORT:

Quarkus Guide to deploy on Heroku:

--

--

Felipe Windmoller

Staff Software Engineer at Banco do Brasil | Oracle Certified Professional, Java SE 8 and Java SE 17 | Mainframe and Cloud Developer