Using Quarkus Helm

Helm is the package manager for Kubernetes that help to find, share, and use software that is built for Kubernetes.

Under the hood, the Quarkus Helm extension uses Dekorate to generate the Helm chart manifests at build time.

Before getting started, make sure you’re using the right Quarkus Helm version that is compatible with the Quarkus version you’re using in your project. See the following table to see the compatibility among versions:

Quarkus Helm Version Quarkus Version

0.0.7

Quarkus 2.13+

0.0.6

Quarkus 2.12

Prerequisites

To complete this guide, you need:

  • roughly 10 minutes

  • JDK 11+ installed with JAVA_HOME configured appropriately

  • Apache Maven 3.8.1+

  • Docker installed

  • Helm command line installed

  • Have connected/logged to a Kubernetes cluster

Create a Quarkus application with the Helm extension

The Quarkus Helm extension will generate the Helm Chart of a Quarkus application.

In this example, we’ll create a Quarkus application with the Quarkus Helm and the Quarkus Kubernetes extensions by running the following command:

mvn io.quarkus.platform:quarkus-maven-plugin:2.13.0.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=helm-quickstart \
    -DclassName="org.acme.quickstart.GreetingResource" \
    -Dpath="/hello" \
    -Dextensions="resteasy-reactive,kubernetes,helm"
cd helm-quickstart

If you already have your Quarkus project configured, you can add the helm extension to your project by running the following command in your project base directory:

./mvnw quarkus:add-extension -Dextensions="helm"

This command will add the following dependency to your pom.xml file:

<dependency>
    <groupId>io.quarkiverse.helm</groupId>
    <artifactId>quarkus-helm</artifactId>
    <version>0.0.7</version>
</dependency>

Once we add the Quarkus Helm extension to your project, you can now generate the Helm resources by running the following Maven command:

./mvnw clean package

Depending on the Quarkus Kubernetes extensions that you are using in your project, the Helm resources will include some resources or others. For example, if your project use the Quarkus Kubernetes extension, then the helm resources will include the following templates at target/helm/kubernetes/<chart name>/:

  • Chart.yaml

  • values.yaml

  • /charts

  • /templates

  • /templates/deployment.yaml

  • /templates/ingress.yaml

  • /templates/service.yaml

  • /templates/NOTES.txt

The <chart name> is set from either the property quarkus.helm.name or the @HelmChart annotation or the Quarkus application.

Helm Usage

Let’s now see how to use the previously generated Helm resources on a Kubernetes cluster.

First, you need to build the application container image and push it into a container registry. For doing this, Quarkus provides some container image extensions to ease up this step. Let’s add the Quarkus container image docker extension in this example:

./mvnw quarkus:add-extension -Dextensions="container-image-docker"

Now, we can generate the Helm resources and build/push the application container image at once by running the following Maven command:

./mvnw clean package -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true -Dquarkus.container-image.registry=<your container registry> -Dquarkus.container-image.group=<your container registry namespace>

Make sure the application container image is public and available to be used by your Kubernetes cluster.

Finally, let’s use Helm to deploy it into the cluster:

helm install helm-example ./target/helm/kubernetes/<chart name>

The above command will use the default values, which are located in ./target/helm/kubernetes/<chart name>/values.yaml. To override the default values, pass as parameter you own value file --values /path/to/another.values.yaml or set them using --set key1=val1 --set key2=val2.

How can I update my deployment?

  • Either via the upgrade option of Helm command line:

After making changes to your project and regenerating the Helm resources and the application container image, then you need to upgrade your deployment:

helm upgrade helm-example ./target/helm/kubernetes/<chart name>
  • Or via the set option of Helm command line:

helm upgrade helm-example ./target/helm/kubernetes/<chart name> --set app.replicas=1

How can we delete my deployment?

helm uninstall helm-example

Alias name

The alias name is the name used to keep all the properties linked as:

app:
  replicas: 3

The alias name in the above example is "app" which is the default value. You can modify it using the property "quarkus.helm.values-root-alias=myAppName" and then the generated Helm resources will look like:

myAppName:
  replicas: 3

Mapping Values

By default, the Quarkus Helm extension will generate the Helm values file (values.yaml) by mapping the following pre-configured properties:

  • The Kubernetes/Openshift replicas

  • The Kubernetes/Openshift image

  • The Kubernetes/Openshift Env Var values (only for plain values - secrets or configmaps are not supported yet)

  • The Kubernetes ingress host

  • The Openshift S2i builder image

If you would like to automatically map any other pre-configured properties, please submit a feature request at this repository, and we’ll work on it.

For example, if you set 3 replicas for your deployment:

quarkus.helm.name=my-chart
quarkus.helm.description=Description of my Chart

# Set replicas to 3
quarkus.kubernetes.replicas=3

The extension will generate the next Helm values file at target/helm/kubernetes/<chart name>/values.yaml:

app:
  replicas: 3

And the Deployment file at target/helm/kubernetes/<chart name>/templates/deployment.yaml will have a reference to this value:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helm-on-kubernetes-example
spec:
  replicas: '{{ .Values.app.replicas }}'

This is done transparently to users.

Mapping user properties using YAMLPath expressions

As we have introduced in the previous section, the Quarkus Helm extension will automatically map some properties like the replicas or the images to the Values helm file. Still, some users might need to map more properties. For example, let’s see the following YAML resource:

apiVersion: v1
kind: Service
metadata:
  name: helm-on-kubernetes-example

The property at metadata.name, with value helm-on-kubernetes-example, will not be replaced with {{ .Values.app.name }} in the Helm templates. However, the extension allows users to define YAMLPath expressions to map these properties into the Helm values file. Let’s see how to do it using the above example to map the property metadata.name with {{ .Values.app.name }}. You only need to add the following properties to your configuration:

quarkus.helm.name=my-chart
quarkus.helm.description=Description of my Chart

# Map all the metadata name resources
quarkus.helm.values[0].property=name
quarkus.helm.values[0].paths=metadata.name

The resulting values.yaml file will look like as:

app:
  name: helm-on-kubernetes-example

The app.name value is set automatically by the Quarkus Helm extension. However, users can provide other values using the value property:

quarkus.helm.name=my-chart
quarkus.helm.description=Description of my Chart

# Map all the metadata name resources
quarkus.helm.values[0].property=name
quarkus.helm.values[0].paths=metadata.name
## Overwrite value:
quarkus.helm.values[0].value=this-is-another-name

And the values.yaml file will now contain:

app:
  name: this-is-another-name

Mapping multiple properties at once

What about if the properties are located in different places, for example:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: helm-on-kubernetes-example ## (1)
spec:
  rules:
    - host: my-host
      http:
        paths:
          - backend:
              service:
                name: helm-on-kubernetes-example ## (2)
                port:
                  name: http
            path: /
            pathType: Prefix

From this example, we need to map the value helm-on-kubernetes-example which is used in two places: (1) metadata.name and (2) spec.rules..http.paths..backend.service.name to the same property name. For doing this, we need to provide a comma-separated list of YAMLPath expressions to be mapped to app.name:

quarkus.helm.name=my-chart
quarkus.helm.description=Description of my Chart

# Map all the metadata name resources
quarkus.helm.values[0].property=name
## Comma separated list of YAMLPath expressions:
quarkus.helm.values[0].paths=metadata.name,(kind == Ingress).spec.rules.http.paths.backend.service.name

Now, the extension will first map the expression metadata.name and then the expression (kind == Ingress).spec.rules.http.paths.backend.service.name (this expression only applies to Ingress resources).

Dependencies

Sometimes, your application requires of some other services to work. The typical scenario is when your application needs of a database to store the application data in. In this scenario, you need to declare the database service as a Helm dependency. For example, let’s declare the Postgres Bitnami Helm dependency as database instance:

Chart.yaml:

dependencies:
  - name: postgresql
    version: 11.6.22
    repository: https://charts.bitnami.com/bitnami
    alias: database # this is optional. The default value is the `name`.

Before installing or packaging your Helm chart, you need to download the dependencies (you can use the Helm command helm dependency update ./target/helm/kubernetes/<chart name>)

Next, you can configure the dependencies adding the dependency configuration into the values.yaml file. For example, following the previous Postgres Bitnami dependency:

values.yaml:

database: # the value in the `alias` property, or the `name` if unset.
  global:
    postgresql:
      auth:
        database: my_db_name
        postgresPassword: secret

Let’s now see how you can add this configuration using the Quarkus Helm extension, so the chart.yaml and the values.yaml files are properly populated using a Helm dependency. You simply need to add the following properties:

application.properties:

quarkus.helm.dependencies.0.alias=database
quarkus.helm.dependencies.0.name=postgresql
quarkus.helm.dependencies.0.version=11.6.22
quarkus.helm.dependencies.0.repository=https://charts.bitnami.com/bitnami

quarkus.helm.values.0.property=database.global.postgresql.auth.postgresPassword
quarkus.helm.values.0.value=secret
quarkus.helm.values.1.property=postgresql.global.postgresql.auth.database
quarkus.helm.values.1.value=my_db_name

The Quarkus Helm extension will check whether the property set in quarkus.helm.values.xxx.property starts with a dependency alias or name. If so, it will use directly the value set. Otherwise, it will interpret that the property is an application property and will add the prefix set in the property quarkus.helm.values-root-alias (default value is app).

Alternatively, you can provide the properties of your dependency using your custom values.yaml file. You need to place this file at src/main/helm (the path is configurable using the property quarkus.helm.input-directory).

src/main/helm/values.yaml:

database: # the value in the `alias` property, or the `name` if unset.
  global:
    postgresql:
      auth:
        database: my_db_name
        postgresPassword: secret

This configuration will be aggregated in the autogenerated values file at target/helm/kubernetes/<chart name>/values.yaml.

Dependencies Order

By default, Helm will start the Helm dependencies and the application at the same time. This might cause issues when running your application (as one of the dependencies might not have been started yet, for example, the database).

The good news is that you can force the dependency installation order using the Quarkus Helm extension by adding the property quarkus.helm.dependencies.XX.wait-for-service=<service name>:

quarkus.helm.dependencies.0.alias=database
quarkus.helm.dependencies.0.name=postgresql
quarkus.helm.dependencies.0.version=11.6.22
quarkus.helm.dependencies.0.repository=https://charts.bitnami.com/bitnami
quarkus.helm.dependencies.0.wait-for-service=chart-database:5432

The service name strongly depends on the Helm dependency to be installed, so you need to know the service name that the chart will expose beforehand.

This configuration will add the following init-containers in the Deployment resource of your Quarkus application:

src/main/helm/kubernetes/templates/deployment.yaml:

initContainers:
- image: alpine:3.16.2
  args:
  - -c
  - for i in $(seq 1 200); do nc -z -w3 chart-database && exit 0 || sleep 3; done; exit 1
  command:
  - sh

You can configure the image and the argument template to use with the properties quarkus.helm.dependencies.XX.wait-for-service-image, quarkus.helm.dependencies.0.wait-for-service-port-command-template and quarkus.helm.dependencies.0.wait-for-service-only-command-template.

Push to Helm Repositories

A Helm chart repository is a location where packaged charts can be used and shared across the community.

We can configure the Quarkus Helm extension to automatically push the generated Helm charts into Helm repositories using the following configuration:

# To enable pushing to a Helm repository
quarkus.helm.repository.push=true
# The Helm repository type. Options are: `CHARTMUSEUM`, `ARTIFACTORY`, and `NEXUS`.
quarkus.helm.repository.type=CHARTMUSEUM
quarkus.helm.repository.url=<chart museum url>
# Optional
quarkus.helm.repository.username=...
# Optional
quarkus.helm.repository.password=...

All the previous properties can be set via system properties at build time.

Let’s see a practical example. First, we need to deploy a Helm repository. The easiest way to set up one, it’s installing ChartMuseum via docker:

docker run --rm -u 0 -it -d -p 8080:8080 -e DEBUG=1 -e STORAGE=local -e STORAGE_LOCAL_ROOTDIR=/charts -v $(pwd)/charts:/charts chartmuseum/chartmuseum:latest

The ChartMuseum data will be stored in the "./charts" folder.

Next, we’re going to build the Helm chart with the push to a repository enabled and using the just created helm repository:

mvn clean install -Dquarkus.helm.repository.push=true -Dquarkus.helm.repository.url=http://localhost:8080/api/charts -Dquarkus.helm.repository.type=CHARTMUSEUM

For the local ChartMuseum, we don’t need to provide either the username or the password.

Finally, let’s install the Helm chart from the Helm repository:

helm repo add local http://localhost:8080
helm install --devel my-quarkus local/quarkus-hello-world

Helm Profiles

By default, all the properties are mapped to the same Helm values file values.yaml. However, the Quarkus Helm extension also supports the generation of Helm values by profiles. For example, let’s say we have two environments: one for testing and another one for production; each environment has a different ingress host where your Kubernetes applications will be exposed. We can configure our application as:

quarkus.kubernetes.ingress.expose=true
# Mapped to `values.yaml` by the preconfigured Ingress decorator
quarkus.kubernetes.ingress.host=my-host

# Helm Chart
quarkus.helm.name=my-chart
## Overwrite the value of `dekorate.kubernetes.host` to `values-<profile-name>.yaml`:
quarkus.helm.values[0].property=host
quarkus.helm.values[0].paths=(kind == Ingress).spec.rules.host
quarkus.helm.values[0].value=my-test-host
quarkus.helm.values[0].profile=test

This configuration will generate the values.yaml using the value set at the property quarkus.kubernetes.ingress.host:

app:
  host: my-host

But as you are now using a profile named test (see quarkus.helm.values[0].profile) in one of your mapped properties, it will also generate a values-test.yaml file with the content:

app:
  host: my-test-host

Configuration Reference

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

Enabled the generation of Helm files.

Environment variable: QUARKUS_HELM_ENABLED

boolean

true

The Chart API version. The default value is v2.

Environment variable: QUARKUS_HELM_API_VERSION

string

v2

Name of the Helm chart. If not set, it will use the application name.

Environment variable: QUARKUS_HELM_NAME

string

Alias of the root element in the generated values file.

Environment variable: QUARKUS_HELM_VALUES_ROOT_ALIAS

string

app

Notes template to be generated.

Environment variable: QUARKUS_HELM_NOTES

string

/NOTES.template.txt

Version of the Helm chart. If not set, it will use the application version.

Environment variable: QUARKUS_HELM_VERSION

string

The Helm chart single-sentence description.

Environment variable: QUARKUS_HELM_DESCRIPTION

string

Icon of the Helm chart. It must be a URL to an SVG or PNG image.

Environment variable: QUARKUS_HELM_ICON

string

Project’s home page of the Helm chart. It must be a URL.

Environment variable: QUARKUS_HELM_HOME

string

List of keywords to add to the chart.

Environment variable: QUARKUS_HELM_KEYWORDS

list of string

The Helm chart list of URLs to source code for this project.

Environment variable: QUARKUS_HELM_SOURCES

list of string

Extension of the Helm tarball file. Default is tar.gz.

Environment variable: QUARKUS_HELM_EXTENSION

string

tar.gz

If Helm tar file is generated.

Environment variable: QUARKUS_HELM_CREATE_TAR_FILE

boolean

false

The input folder in which to place the user-defined Helm files. These files will be used as inputs to populate the generated Helm files. At the moment, the only supported Helm file is the values.yaml file. It also supports absolute paths. By default, it will use the folder "src/main/helm".

Environment variable: QUARKUS_HELM_INPUT_DIRECTORY

string

src/main/helm

The output folder in which to place the Helm generated folder. The folder is relative to the target output directory in Quarkus that is also configurable using the property quarkus.package.output-directory. It also supports absolute paths. By default, it will be generated in the folder named "helm".

Environment variable: QUARKUS_HELM_OUTPUT_DIRECTORY

string

helm

If true, it will perform the upload to a Helm repository.

Environment variable: QUARKUS_HELM_REPOSITORY_PUSH

boolean

false

The deployment target to push. Options are: kubernetes, openshift, knative…​

Environment variable: QUARKUS_HELM_REPOSITORY_DEPLOYMENT_TARGET

string

${quarkus.kubernetes.deployment-target}

The Helm repository type. Options are: CHARTMUSEUM, ARTIFACTORY, and NEXUS.

Environment variable: QUARKUS_HELM_REPOSITORY_TYPE

chartmuseum, artifactory, nexus

The Helm repository URL.

Environment variable: QUARKUS_HELM_REPOSITORY_URL

string

The Helm repository username.

Environment variable: QUARKUS_HELM_REPOSITORY_USERNAME

string

The Helm repository password.

Environment variable: QUARKUS_HELM_REPOSITORY_PASSWORD

string

Name of the maintainer.

Environment variable: QUARKUS_HELM_MAINTAINERS__MAINTAINERS__NAME

string

required

Email of the maintainer.

Environment variable: QUARKUS_HELM_MAINTAINERS__MAINTAINERS__EMAIL

string

URL profile of the maintainer.

Environment variable: QUARKUS_HELM_MAINTAINERS__MAINTAINERS__URL

string

Name of the dependency.

Environment variable: QUARKUS_HELM_DEPENDENCIES__DEPENDENCIES__NAME

string

required

Version of the dependency.

Environment variable: QUARKUS_HELM_DEPENDENCIES__DEPENDENCIES__VERSION

string

required

Repository of the dependency.

Environment variable: QUARKUS_HELM_DEPENDENCIES__DEPENDENCIES__REPOSITORY

string

required

Alias of the dependency.

Environment variable: QUARKUS_HELM_DEPENDENCIES__DEPENDENCIES__ALIAS

string

Dependency condition.

Environment variable: QUARKUS_HELM_DEPENDENCIES__DEPENDENCIES__CONDITION

string

Dependency tags.

Environment variable: QUARKUS_HELM_DEPENDENCIES__DEPENDENCIES__TAGS

list of string

Instruct the application to wait for the service that should be installed as part of this Helm dependency. You can set only a service name or a combination of a service name plus the service port (service:port).

Environment variable: QUARKUS_HELM_DEPENDENCIES__DEPENDENCIES__WAIT_FOR_SERVICE

string

If wait for service is set, it will use this image to configure the init-containers within the deployment resource.

Environment variable: QUARKUS_HELM_DEPENDENCIES__DEPENDENCIES__WAIT_FOR_SERVICE_IMAGE

string

busybox:1.34.1

If wait for service is set, it will use this command to run the init-containers within the deployment resource.

Environment variable: QUARKUS_HELM_DEPENDENCIES__DEPENDENCIES__WAIT_FOR_SERVICE_PORT_COMMAND_TEMPLATE

string

for i in $(seq 1 200); do nc -z -w3 ::service-name ::service-port && exit 0; done; exit 1

If wait for service is set, it will use this command to run the init-containers within the deployment resource.

Environment variable: QUARKUS_HELM_DEPENDENCIES__DEPENDENCIES__WAIT_FOR_SERVICE_ONLY_COMMAND_TEMPLATE

string

until nslookup ::service-name; do echo waiting for service; sleep 2; done

The name of the property that will be present in the Helm values file.

Environment variable: QUARKUS_HELM_VALUES__VALUES__PROPERTY

string

required

A comma-separated list of YAMLPath expressions to map the Dekorate auto-generated properties to the final Helm values file.

Environment variable: QUARKUS_HELM_VALUES__VALUES__PATHS

list of string

The profile where this value reference will be mapped to. For example, if the profile is dev, then a values-dev.yml file will be created with the value.

Environment variable: QUARKUS_HELM_VALUES__VALUES__PROFILE

string

The value that the property will have in the Helm values file. If not set, the extension will resolve it from the generated artifacts.

Environment variable: QUARKUS_HELM_VALUES__VALUES__VALUE

string

The integer value that the property will have in the Helm values file. If not set, the extension will resolve it from the generated artifacts.

Environment variable: QUARKUS_HELM_VALUES__VALUES__VALUE_AS_INT

int

The boolean value that the property will have in the Helm values file. If not set, the extension will resolve it from the generated artifacts.

Environment variable: QUARKUS_HELM_VALUES__VALUES__VALUE_AS_BOOL

boolean

If not provided, it will use {{ .Values.. }}.

Environment variable: QUARKUS_HELM_VALUES__VALUES__EXPRESSION

string

References