Hello! Welcome to the next practical step in our journey to mastering microservice deployments.
In our last lesson, we established the "why" and "what" of Helm. You learned that Helm is a package manager that saves us from the complexity of managing raw Kubernetes YAML files, and we dissected the basic structure of a Helm chart, including Chart.yaml, values.yaml, and the templates directory.
Today, we move from theory to practice. Our goal is to create a basic Helm chart to package and deploy a Spring Boot microservice on Kubernetes. This is a hands-on session where you'll build a reusable, versioned deployment package. For your interview preparation, this skill is non-negotiable. It demonstrates that you can not only write microservices but also manage their lifecycle in a modern, automated way—a key expectation for mid-senior roles.
Let's start building.
1. Prerequisites and Scaffolding Your Chart
Before we begin, ensure you have the following tools ready from our previous modules:
- A running local Kubernetes cluster (like Minikube or Docker Desktop's Kubernetes).
- The
kubectlCLI, configured to connect to your cluster. - The
helmCLI (version 3+). - A Docker image of a Spring Boot application you've built, pushed to a registry (like Docker Hub). If you don't have one handy, we can use a public example.
The first step in creating a chart is to generate its basic structure using the helm create command. This saves you from creating all the standard files and directories manually.
Run the following command in your terminal:
helm create my-spring-boot-app
This command creates a new directory named my-spring-boot-app with all the boilerplate files we discussed in the last lesson.
To understand the purpose of each generated file and the overall process we're about to follow, the following reading provides an excellent roadmap.
Deploy Spring Boot Applications with Helm | by Jan Weyrich
The article 'Deploy Spring Boot Applications with Helm' by Jan Weyrich outlines the exact steps we'll be taking. It's a great reference for the entire process, from creating the scaffold to packaging the chart.
Please read the introduction to the section 'What are the steps to create a Helm chart for a Spring Boot application?' and subsection 1, 'Create the chart scaffold'. This will reinforce the purpose of the command we just ran and set the stage for the next steps.
2. Customizing the Chart for Your Spring Boot App
The default chart is a generic starting point for a web application. Now, we need to tailor it specifically for our Spring Boot microservice. This involves editing Chart.yaml, values.yaml, and the templates.
Step 2.1: Editing Metadata in Chart.yaml
Open my-spring-boot-app/Chart.yaml. This file contains metadata about your chart. It's good practice to update the description and appVersion.
version: The version of the chart itself. You'd increment this if you change the chart's templates or default values.appVersion: The version of the application the chart deploys. This typically corresponds to your Docker image tag (e.g., "1.0.0").
Here's an example:
apiVersion: v2
name: my-spring-boot-app
description: A Helm chart for deploying my Spring Boot microservice
type: application
version: 0.1.0
appVersion: "1.0.0"
Step 2.2: Configuring values.yaml
This is the most important step for customization. The values.yaml file acts as the "API" for your chart, allowing you to configure the deployment without touching the underlying Kubernetes manifests. Let's adjust the default values for a typical Spring Boot application.
Open my-spring-boot-app/values.yaml and make the following changes:
-
Image Repository and Tag:
Updateimage.repositoryto point to the Docker image of your Spring Boot application. Theimage.tagcan be left empty if you want it to default to theappVersioninChart.yaml, which is a common and useful pattern.image: repository: your-dockerhub-username/your-spring-boot-app # <-- CHANGE THIS pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart's appVersion. tag: "" -
Service Port:
By default, Helm charts often assume a web server runs on port 80. Your Spring Boot application, however, runs on port 8080. If this isn't corrected, the KubernetesServicewill not be able to forward traffic to your application pod.service: type: ClusterIP port: 8080 # The port the service exposesWe also need to ensure the
targetPortin theservice.yamltemplate correctly points to our application's container port. The default template usually handles this by referencing a named port in thedeployment.yaml. -
Container Port and Health Probes:
In thedeployment.yamltemplate, we need to tell Kubernetes that our container listens on port 8080. The default templates usually have a placeholder for this. We also need to configure the liveness and readiness probes to use Spring Boot Actuator's health endpoints, which is a production best practice.Instead of modifying the templates directly, the default chart allows you to configure this from
values.yaml. Look for sections related toservice,ingress, and probes. The defaultvalues.yamlmight not expose all necessary probe settings, so we'll check thedeployment.yamltemplate.
Open my-spring-boot-app/templates/deployment.yaml. Find the ports and livenessProbe/readinessProbe sections within the container definition. They might look like this:
# templates/deployment.yaml
ports:
- name: http
containerPort: {{ .Values.service.port }} # This uses the value from values.yaml
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
The default path / is not ideal. For a Spring Boot application with Actuator, we should use /actuator/health/liveness and /actuator/health/readiness. Let's add this configuration to our values.yaml and update the template.
First, add a probes section to your values.yaml:
# values.yaml
# Add this new section
probes:
liveness:
path: /actuator/health/liveness
readiness:
path: /actuator/health/readiness
# ... existing values ...
Now, update templates/deployment.yaml to use these new values:
# templates/deployment.yaml
livenessProbe:
httpGet:
path: {{ .Values.probes.liveness.path }}
port: http
readinessProbe:
httpGet:
path: {{ .Values.probes.readiness.path }}
port: http
This change makes your chart much more robust and suitable for a real Spring Boot application.
3. Validating and Deploying Your Chart
With our chart customized, it's time to learn the commands to validate, inspect, and deploy it. These commands are your day-to-day toolkit for working with Helm.
Using Helm and Kubernetes | Baeldung on Ops
The Baeldung article 'Using Helm and Kubernetes' provides a clear, command-by-command guide to managing a chart's lifecycle. We will walk through these essential commands together.
Please read section 8, 'Managing Charts' (subsections 8.1 to 8.7, but focus on lint, template, install, ls, and uninstall). This will introduce you to the core Helm CLI commands we'll use to deploy and manage our application.
Let's apply what you just read. Navigate to the root directory of your chart (my-spring-boot-app).
-
Lint the Chart (
helm lint):
This command checks for syntax errors and adherence to best practices. It's the first thing you should run after making changes.helm lint . # Expected output: # ==> Linting . # [INFO] Chart.yaml: icon is recommended # 1 chart(s) linted, 0 chart(s) failed -
Render the Template (
helm template):
This is an incredibly useful command for debugging. It generates the final Kubernetes YAML by rendering your templates with the values fromvalues.yaml, but it only prints the output to your console—it doesn't deploy anything. This lets you inspect the final manifest before applying it to your cluster.helm template my-app-release .Inspect the output. Do you see
port: 8080in the Service? Is the image name correct in the Deployment? Are the probe paths set to the actuator endpoints? -
Install the Chart (
helm install):
This is the command that deploys your application. It creates a release, which is a running instance of your chart.helm install my-app-release .Helm will print out the status of the deployment and any notes included in the chart.
-
Check the Status (
helm lsandkubectl):
You can see all your active releases withhelm ls.helm lsAnd you can use
kubectlto verify that your Spring Boot application's pod is running.kubectl get pods # You should see a pod with a name like 'my-app-release-my-spring-boot-app-...' -
Uninstall the Release (
helm uninstall):
To tear down the entire application stack, simply uninstall the release. This removes all Kubernetes resources created by the chart.helm uninstall my-app-release
Test your understanding!
You need to add a configurable resource limit for memory to your Spring Boot application. The default should be 512Mi. How would you modify values.yaml and templates/deployment.yaml to achieve this?
Show answer
-
Modify
values.yaml:
The defaultvalues.yamlalready has aresourcessection. You would ensure it's configured as needed, or add it if it's missing.# values.yaml resources: # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following # lines, adjust them as necessary, and remove the curly braces after 'resources:'. limits: # cpu: 100m memory: 512Mi # Set the desired value requests: cpu: 100m memory: 256Mi -
Modify
templates/deployment.yaml:
The defaultdeployment.yamlis already set up to use these values. Theresourcesblock in the container spec typically looks like this:# templates/deployment.yaml resources: {{- toYaml .Values.resources | nindent 12 }}The
toYamlfunction converts theresourcesobject fromvalues.yamlinto YAML format, andnindent 12ensures it's correctly indented. This is a very common and efficient pattern in Helm charts. You wouldn't need to change the template at all if it's already using this pattern.
4. Externalizing Configuration with ConfigMaps
A truly production-ready chart shouldn't have configuration baked into the Docker image. Spring Boot's "externalized configuration" feature is a perfect match for Kubernetes ConfigMaps. Let's extend our chart to manage application properties.
We'll create a ConfigMap from values in our values.yaml and mount them as environment variables in our pod. Spring Boot will automatically pick them up.
Deploy Spring Boot Applications with Helm | by Jan Weyrich
Let's revisit the Jan Weyrich article. It has an excellent, practical walkthrough on integrating a ConfigMap into a Helm chart for a Spring Boot application. This is a key pattern for managing environment-specific settings.
Please read subsection 4, 'Edit the templates'. Focus on the part that introduces the ConfigMap template and how it's used to manage application.properties. Pay attention to the use of toYaml and the trick to force a pod restart when the configuration changes.
Let's implement this powerful pattern.
-
Add application properties to
values.yaml:
Add a new section for your application properties. Remember Spring Boot's relaxed binding rules:LOGGING_LEVEL_ORG_SPRINGFRAMEWORKin an environment variable maps tologging.level.org.springframeworkinapplication.properties. It's best practice to use the environment variable format in yourvalues.yamlto avoid any confusion.# values.yaml # Add this new section at the end of the file application: properties: WELCOME_MESSAGE: "Hello from Helm!" SPRING_DATASOURCE_URL: "jdbc:postgresql://localhost:5432/mydb" -
Create
templates/configmap.yaml:
Create a new filemy-spring-boot-app/templates/configmap.yamlwith the following content:{{- if .Values.application.properties }} apiVersion: v1 kind: ConfigMap metadata: name: {{ include "my-spring-boot-app.fullname" . }}-properties data: {{- toYaml .Values.application.properties | nindent 6 }} {{- end }}{{- if .Values.application.properties }}: This makes the creation of theConfigMapconditional.{{- toYaml .Values.application.properties | nindent 6 }}: This is the magic part. It takes the YAML block fromvalues.yamland renders it directly into thedatasection of theConfigMap.
-
Mount the ConfigMap in
deployment.yaml:
Finally, edittemplates/deployment.yamlto mount thisConfigMapas environment variables. Find thecontainerssection and add theenvFromblock:# templates/deployment.yaml containers: - name: {{ .Chart.Name }} # ... existing properties like securityContext, image, etc. envFrom: - configMapRef: name: {{ include "my-spring-boot-app.fullname" . }}-properties ports: # ... existing ports, probes, etc.Now, when you
helm installorhelm upgrade, these properties will be available as environment variables to your Spring Boot application.
Conclusion
Congratulations! You have successfully created and deployed your first Helm chart for a Spring Boot microservice. You've gone beyond a simple deployment by incorporating best practices like actuator-based health probes and externalized configuration via ConfigMaps.
Key Takeaways:
- You can scaffold a chart with
helm create. - Customizing a chart for Spring Boot involves key changes in
values.yaml: updating theimage.repository, setting theservice.portto8080, and configuring probes to use actuator endpoints. - The core Helm CLI commands for managing a release are
helm lint,helm template,helm install,helm ls, andhelm uninstall. - You can manage Spring Boot properties by creating a
ConfigMapfromvalues.yamland mounting it usingenvFromin yourDeployment.
In this lesson, we focused on the creation and initial deployment. In our next session, we will dive deeper into application lifecycle management by learning to manage application releases using Helm commands, including upgrade and rollback, which are critical for implementing zero-downtime deployment strategies.
Can't find a good explanation? Sign up and we'll make it for you
Sign up