There are several Maven plugins in the open source community that integrate with Helm. However, you’ll come to find that these plugins are used to generate Helm charts. Generating Helm charts from scratch suffices for personal usage or small teams, but consider the cases where Helm is used at scale across multiple teams within an organization. While you could expect each team to generate and maintain their own Helm charts, it’s more reasonable for a platform or DevOps team to create a Helm chart repository for use across the enterprise. Creating a Helm chart repository provides many advantages, including:
- Incorporating best practices that might be missed by Helm chart generators
- Adding templating to integrate with services such as Vault or an APM. A generic Helm chart generator would be very unlikely to provide these integrations in a way that makes sense for your organization
- Providing versioned Helm chart releases. As the platform team adjusts its standards or implements new features, users can avoid copy-pasting changes and instead simply upgrade to the latest version of the chart
Because of the advantages of using managed Helm charts, I decided to write a Maven plugin, helm-maven-plugin, for installing Helm charts from a Helm chart repository within the Maven lifecycle. This blog post will explore the helm-maven-plugin and show you how to use it in an enterprise setting.
Helm Maven Plugin
First, to use this plugin, you need to install the Helm CLI on your local machine. For instructions on installing Helm, refer to Helm’s installation instructions.
Once Helm is installed on your local machine, you’re ready to get started! The plugin comes with two Maven goals:
helm:upgrade
– Install/Upgrade a Helm chart to Kuberneteshelm:uninstall
– Uninstall an existing Helm release
The helm:upgrade
goal is invoked automatically during Maven’s install lifecycle phase. This goal installs a Helm chart to Kubernetes or upgrades an existing Helm release if one already exists.
The helm:uninstall
goal is not bound to a lifecycle phase, so it is executed by running the command mvn helm:uninstall
from the command line.
For complete documentation on the helm-maven-plugin goals, visit the project’s readme. For a set of example POMs, visit the project’s examples.
Let’s walk through an example of using this plugin in practice.
Example Usage
I have a real-world example on GitHub at https://github.com/deweya/helm-maven-plugin-example. The application in this repo is just a simple Spring Boot microservice, but you can use helm-maven-plugin for any Java application on Kubernetes.
To deploy a container image using Helm, you first need to build the image and push it to a registry. For this reason, in the POM.xml file, I added the docker-maven-plugin to the build plugins and positioned it before helm-maven-plugin. An overview of docker-maven-plugin is out of scope, but you can review their project at https://github.com/fabric8io/docker-maven-plugin.
Then, of course, I added helm-maven-plugin to the POM’s build plugins. Below shows the XML used for adding and configuring the plugin:
<plugin> <groupId>com.austindewey</groupId> <artifactId>helm-maven-plugin</artifactId> <version>1.1.1</version> <configuration> <releaseName>spring-demo-app</releaseName> <chart> <name>onechart</name> <version>0.36.0</version> <repository> <url>https://chart.onechart.dev</url> </repository> </chart> <values> <files> <file>values.yaml</file> </files> <set> <image.repository>${image}</image.repository> <image.tag>${project.version}</image.tag> </set> </values> </configuration> <executions> <execution> <id>helm-upgrade</id> <goals> <goal>upgrade</goal> </goals> </execution> </executions> </plugin>
Let’s explain this XML piece by piece.
Configuration Overview
First, I added the Maven GAV. As of writing, the latest version of the helm-maven-plugin is 1.1.1, but you can view the list of versions in the project’s changelog.
<groupId>com.austindewey</groupId>
<artifactId>helm-maven-plugin</artifactId>
<version>1.1.1</version>
Next, I added the plugin’s configuration. You can view all of the available configurations in the readme, and you can see different ways of configuring the plugin in the examples.
Let’s look at the first part of the configuration:
<releaseName>spring-demo-app</releaseName>
Every Helm release needs a release name, so I provided one using the releaseName
element. If one is not provided, the release name defaults to the project.name
POM setting.
After the release name, I provided the chart
element, which determines the Helm chart we want to install as well as the repository that it comes from:
<chart>
<name>onechart</name>
<version>0.36.0</version>
<repository>
<url>https://chart.onechart.dev</url>
</repository>
</chart>
This example installs version 0.36.0 of the chart onechart from the repository https://chart.onechart.dev (this is a generic Helm chart for deploying basic Kubernetes applications).
I suspect most users will install charts directly from an HTTP(S) URL, as demonstrated above. However, there are other ways to install Helm charts. Here are all of the ways that helm-maven-plugin takes into account:
- Installing directly from an HTTP(S) URL (as demonstrated). This will be done if the
repository.url
element containshttp://
orhttps://
. - Installing from an OCI registry. This will be done if the
repository.url
element containsoci://
. - Installing from a repository that was previously added using
helm repo add
. This will be done if therepository.name
element is used instead ofrepository.url
. - Installing from a local chart on the file system. This will be done if the previous conditions are not reached.
After the chart configuration, I added the values
element for adding Helm values:
<values>
<files>
<file>values.yaml</file>
</files>
<set>
<image.repository>${image}</image.repository>
<image.tag>${project.version}</image.tag>
</set>
</values>
The values.files
element is the equivalent of passing the --values
flag from the command line. Here, I’m using this values file from the example repository.
The values.set
element is the equivalent of passing the --set
flag. Here, I added two values inline for setting the image repository and tag. Here, you’ll notice I used interpolation, referencing the image property (defined in the POM’s properties) and the project’s version. I demonstrated it this way because this is how I imagine users will keep the image and tag consistent between the project name, the docker-maven-plugin, and the helm-maven-plugin.
Finally, I added the executions to bind the helm-maven-plugin’s upgrade
goal with Maven’s install
phase:
<executions>
<execution>
<id>helm-upgrade</id>
<goals>
<goal>upgrade</goal>
</goals>
</execution>
</executions>
The upgrade
goal binds to the install
phase by default, but I could have been explicit by adding the <phase>install</phase>
element. When I run mvn clean install
, the Maven will automatically install/upgrade the Helm chart to your Kubernetes environment!
There is not a logical lifecycle phase that the uninstall goal pairs well with, so I left that goal out of the executions config. So, to uninstall a release, you can execute the goal directly by running mvn helm:uninstall
.
Let’s see how helm-maven-plugin works in practice.
Helm Maven Plugin in Action
With the above plugin configuration, I am ready to use Maven to build my project:
$ mvn clean install
This command, of course, runs the project’s tests and produces the jar file. Then, since my example POM includes the docker-maven-plugin, the container image is built and pushed to my registry in Docker Hub. Finally, Maven invokes the upgrade goal of helm-maven-plugin, producing the following log output:
[INFO] --- helm-maven-plugin:1.1.1:upgrade (helm-upgrade)
[INFO] Installing/Upgrading release "spring-demo-app"
Release "spring-demo-app" does not exist. Installing it now.
NAME: spring-demo-app
LAST DEPLOYED: Sat May 21 12:50:07 2022
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
[INFO] -----------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -----------------------------------------------------------
[INFO] Total time: 30.554 s
[INFO] Finished at: 2022-05-21T12:50:07-04:00
[INFO] -----------------------------------------------------------
As you can see, the release spring-demo-app was deployed to the default
namespace. The target namespace can be changed using the plugin’s namespace
element in the POM.
A quick check on the default namespace will reveal that Maven successfully installed the chart!
$ kubectl get pods
NAME READY STATUS RESTARTS
spring-demo-app-88d5cb6-dhd2x 1/1 Running 0
$ helm list
NAME NAMESPACE REVISION
spring-demo-app default 1
Though the chart installation was successful, you’ll sometimes notice that your pod will display the 0/1
ready state, indicating that it is still starting up. You can tell Maven to wait until your pod is ready by setting the plugin’s wait
element to true
in the POM.
When it is time to uninstall your release, you can invoke the uninstall
goal directly:
$ mvn helm:uninstall
Afterward, you’ll see output similar to the following:
[INFO] Uninstalling release "spring-demo-app"
release "spring-demo-app" uninstalled
[INFO] -----------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -----------------------------------------------------------
[INFO] Total time: 2.298 s
[INFO] Finished at: 2022-05-21T12:59:50-04:00
[INFO] -----------------------------------------------------------
Thanks for Reading
If you or your organization uses Helm chart repositories to deploy Java applications to Kubernetes, helm-maven-plugin can help provide you with a simple developer experience. If you are interested, feel free to check out the plugin’s documentation or leave a GitHub issue. I’d be happy to answer any questions or listen to any feedback you might have. Thanks for reading, and I’ll see you next time.