How to use environment variables to make a containerized Quarkus application more flexible

This blog post addresses the topic, how to use environment variables to make a containized Quarkus application more flexible. We will touch following technologies QuarkusOpenJ9 Java runtimeMicroProfileDockerfile definition and Code Engine.

When you run a containerized application on a container orchestration platform like KubernetesOpen Shift or with a serverless framework like Knative or Code Engine or on other platforms, it is helpful to pass endpoints to other applications to the containerized application by using environment variables. When the container will be restarted, these variables can be provided to the container and no adjustment in the source code is necessary. You can use configmaps or in Code Engine simple the environment variable itself.

We will follow along an application example for the implementation and the example source code you find in the Get started to deploy a Java Microservices application to Code Engine workshop. (or the direct link to the used file in the GitHub repository is provided in the blog post itself)

Start with the architecture of the example application

The following diagram shows the architecture of the example application, that runs on Code Engine. There is a web-app frontend application that serves the Javascript/Vue.js code to the browser. The web-app code running in the browser invokes a REST API of the web-api microservice. The web-api microservice in turn invokes a REST API of the articles microservice. Keycloak is used for the Identity and Access Management of that microservices based application. To see the results in the web application, users need to be authenticated and they need to have the role user.

Focus on one Microservice

In this blog post we will only focus on the implementation for the usage of the environment variables for the web-api microservice.

The web-api microservice uses two external endpoints internally to consume information, one to Keycloak and one to the articles microsservice. The Keycloak endpoint is managed by Quarkus with it’s OpenID Connect implementation. (Quarkus is OpenID Connect compliant). We will focus on the connection to the articels microsservice.

There for we will cover following topics in a row:

  1. Configuration of application.properties file of Quarkus
  2. Usage of the annotation @ConfigProperty in the Java class
  3. Invocation of the Quarkus Java application with the needed environment variables as parameters
  4. Write a Dockerfile and use a docker_entrypoint_*.sh file
  5. Run a Docker container with the environment variables locally
  6. Deploy the application example with the Code Engine command line, including the environment variables

CONFIGRATION OF APPLICATION.PROPERTIES FILE

The configuration src/resources/application.properties file contains configurations for your Quarkus application, some of them are predefined and you can define your own configurations, for more details visit the example Quarkus – Configuring your application.

In our case we only focus on these two properties quarkus.oidc.auth-server-url and cns.articles-url.
For both properties configurations we define the usage as you see in the following code: Using the environment variable value or if this value is not available use the default value.

${ENVIRONMENT_VARIABLE:"default-value"}.

...
quarkus.oidc.auth-server-url=${QUARKUS_OIDC_AUTH_SERVER_URL:"http://localhost:8282/auth/realms/quarkus"}
...
cns.articles-url=${CNS_ARTICLES_URL:"http://localhost:8082/articles"}

USAGE OF THE ANNOTATION @CONFIGPROPERTY

The following code extract of the ArticlesDataAccess.java class of the example shows the needed import from MicroProfile . With the @ConfigProperty annotation you can access the value of the environment variable and pass that value to the articles_url variable.

import org.eclipse.microprofile.config.inject.ConfigProperty;

@ApplicationScoped
public class ArticlesDataAccess {

    @ConfigProperty(name = "cns.articles-url") 
    private String articles_url;

INVOCATION OF THE QUAKUS JAVA APPLICATION

Now we need to provide the environment variables to the Quarkus application for the startup, we do that with the -D commandline parameter for our custom environment variable. The following code is an extract of the docker_entrypoint_start-quarkus.sh bash file. The bash script is used for Java startup inside the Dockerfile and contains following Java command.

java -Xmx128m \
     -Xscmaxaot100m \
     -XX:+IdleTuningGcOnIdle \
     -Xtune:virtualized \
     -Xscmx128m \
     -Xshareclasses:cacheDir=/opt/shareclasses \
     -Dcns.articles-url=${CNS_ARTICLES_URL} \
     -jar \
     /opt/app/app.jar

In the following code you see the invocation of the docker_entrypoint_start-quarkus.sh bash script in the Dockerfile and you see we use OpenJ9 as our the Java runtime for the container.

...
FROM adoptopenjdk/openjdk11-openj9:ubi-minimal
...
# Environment variables
COPY ./docker_entrypoint_start-quarkus.sh ./docker_entrypoint_start-quarkus.sh
RUN chmod 777 docker_entrypoint_start-quarkus.sh 
EXPOSE 8081
CMD ["/bin/sh","docker_entrypoint_start-quarkus.sh"]

RUN THE CONTAINER LOCALLY

Now we can start the container locally to verify does it work and pass the needed environment variables to the container, which are consumed by the Quarkus microservices application web-api.

export REPOSITORY=tsuedbroecker
docker run -it -p 8080:8081 -e CNS_ARTICLES_URL="http://localhost:8082/articles" -e QUARKUS_OIDC_AUTH_SERVER_URL="http://localhost:8282/auth/realms/quarkus"  "quay.io/$REPOSITORY/web-api-ce:v5"

DEPLOY TO CODE ENGINE

When we deploy the application to Code Engine we can simply pass the environment variables using the CLI and we don’t need to define an additional configmap as for Kubernetes, Open Shift or Knative.

ibmcloud ce application create --name web-api \
                               --image "quay.io/$REPOSITORY/web-api-ce:v6" \
                               --cpu 1 \
                               --env QUARKUS_OIDC_AUTH_SERVER_URL="$KEYCLOAK_URL/auth/realms/quarkus" \
                               --env CNS_ARTICLES_URL="http://articles.$NAMESPACE.svc.cluster.local/articles" \
                               --max-scale 1 \
                               --memory 2G \
                               --min-scale 0 \
                               --port 8081 

Summary

With the combination of QuarkusOpenJ9 Java runtimeMicroProfileDockerfile definition and Code Engine it’s pretty easy to pass environment variables to a containerized application.



I hope this was useful for you and let’s see what’s next?

Greetings,

Thomas

#Java, #codeengine, #microprofile, #Docker, #container, #quarkus, #environment

One thought on “How to use environment variables to make a containerized Quarkus application more flexible

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.