Quote
Hello yβall guys, Alongside the return of kubewekend this weekend, weβre also going to learn how to build a complete Helm repository that you can use for your applications, homelab, or anything else you might need. Itβs time to settle in and set up your Helm repository together! π
π€ Why should you get one for yourself ?
Question
If you already or new to work with Kubernetes, you should figure out for yourself one or more way to deploy your application in Cluster, and
helm
is one of them. Before we go to details why should we go to find couple of solutions for your starting
I donβt know actual how many ways can be used for deploy application into Kubernetes, base on my knowledge, we have a list like
-
Using Manifest - as the βold but goldβ foundational method for deploying Kubernetes. Manifests are the root of all other deployment strategies, essential for setting up Kubernetes with its controllers and APIs. Their straightforward nature makes them easy to approach for beginners. Refer to more articles to deepen your understanding.
-
Not up for debate, Helm continues to prove itself as a top-tier tool in Kubernetes. By leveraging existing manifests to create a more generic and flexible deployment method, Helm has become widely adopted by countless companies (and Iβm not kidding!). Nowadays, when I consider
Kubernetes
deployment solutions, I have complete faith in Helm. -
Next, if you want to manage your manifests dynamically, youβll encounter Kustomize. It helps you customize your manifests using configurations defined in a
kustomization.yaml
file, allowing you to tailor your application for various environments. While I havenβt personally used it, itβs widely regarded as an excellent tool for getting started with Kubernetes. -
If you prefer JSON over YAML, Jsonnet (https://jsonnet.org/) is an excellent tool for you. Itβs designed for general configuration of anything in JSON, including Kubernetes components, making it ideal for those looking to deepen their Kubernetes strategies using JSON. Nowadays, Jsonnet is integrated as a library or SDK in various programming languages, offering a new way to make Kubernetes more engaging, especially when combined with tools like Tanka or Kapitan.
-
Nowadays, there is some things coolest release for CI/CD Integration, it will define your pipeline from build docker image to apply into Kubernetes. If you wanna set it up, you should reach to werf - Next gen for Kubernetes deployment with
helm
alternative with nelm -
Lastly, we have the GitOps concept - A framework that streamlines application and infrastructure deployment using Git workflows and CI/CD. It leverages tools like
Kustomize
,manifests
, orHelm
. Today, you have diverse and user-friendly options for implementing GitOps in your Kubernetes cluster. From my perspective, GitOps is perfect for modern teams that need rapid iteration; youβll absolutely love it. Here are some options you might consider- argo-cd : Β A declarative, GitOps continuous delivery tool for Kubernetes π (Recommended)
- flux2: Open and extensible continuous delivery solution for Kubernetes. Powered by GitOps Toolkit π (Recommended)
- Fleet: Deploy workloads from Git to large fleets of Kubernetes clusters by Rancher
- harness: an end-to-end developer platform
- Cyclops: an open-source dev tool that simplifies Kubernetes with an easy-to-use UI
As you can see, you will face off the huge marketplace in tools, technologies and that why you find the answer for finding first solution for Kubernetes
is pretty hard. If you wanna find alternative, read more
- Codefresh - GitOps Tools: 6 Tools You Need to Know
- Northflank - 7 Helm alternatives to simplify Kubernetes deployments
To unravel this complexity, weβll take it step by step, starting with the smallest piece: defining the manifest to showcase your desired workflow. In my case, I prefer working with Helm and Argo CD. Thatβs why Iβll create a template for my own Helm workspace, with the repository maintaining template versions. This will help me define my application to work seamlessly with our cluster concept, specifically within my Kubewekend project.
To achieve this, Iβll follow these steps to create my first Helm template and repository:
- Define my first Helm template version.
- Set up the repositories to host your Helm templates, leveraging options like GitHub Pages, OCI, or ChartMuseum.
- Create a workflow to release and maintain our versions, allowing Helm to access the repository and pull my Helm charts.
- **Integrate helm-docs to enhance reliability and establish trust in your Helm charts.
ποΈ Build your first helm chart template
Coming to hot topic, you wonder how to create a helm template, it looks pretty hard because you required to have knowledge about
- Kubernetes Workload: A couple of controllers, components for starting like
deployment
,serviceaccount
,ingress
, β¦ - Understanding the structure of Helm Chart like
Chart
,templates
,values
,_helper
, β¦
Info
But nowadays, you can easier to create general helm chart with only
helm
command. Find the way to installhelm-cli
in your host at Helm: Installation Guide
Now you can use create
function to create your first helm chart
helm create <chart-name>
After that, you will have the directory with full components to become a helm chart with structure
common
βββ charts
βββ Chart.yaml
βββ .helmignore
βββ templates
βΒ Β βββ deployment.yaml
βΒ Β βββ _helpers.tpl
βΒ Β βββ hpa.yaml
βΒ Β βββ ingress.yaml
βΒ Β βββ NOTES.txt
βΒ Β βββ serviceaccount.yaml
βΒ Β βββ service.yaml
βΒ Β βββ tests
βββ values.yaml
I will try to brief with short version about Helm Chart Template, otherwise you should read these articles - long version because it provides a lot of information for catching up this conceptual
Letβs start with Chart.yaml
. This essential file defines your chartβs metadata and is where information about your chart is displayed upon deployment. While Chart.yaml
offers extensive configuration options, you should primarily focus on the required fields. For more detailed information, refer to the official Helm documentation on The Chart.yaml File.
Here are key fields within Chart.yaml
:
apiVersion
: Defines your Chart API Version. For Helm 3, you should usev2
;v1
is for previous Helm versions.name
: Sets your Helm chartβs name. This name will correspond to your application when the component is rendered in the Kubernetes cluster.version
: Specifies your Helm chartβs version.description
: Provides the purpose of your Helm chart. This will serve as the title when your chart is released, aiding in distinguishing it within repositories containing multiple charts.type
: Indicates the type of chart, eitherapplication
orlibrary
. The default isapplication
. If you intend to create alibrary
chart, consult the Library Charts documentation.appVersion
: Represents the version of the application contained within this chart. While related to theversion
field, you can set them to be the same value if desired.
Next, you should take a look to templates/
directory, which is truly important where help your chart render to Kubernetes
workloads. In this part, it defines via Go Template with specific syntax, but believe me this gonna a pretty hard to understand for who start to use this one. When you use create
command, that will support you to create some basic workload and itβs completely able to deploy.
Let take a example, you can choose start from service.yaml
or ingress.yaml
to learn the connect between these files
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "common.fullname" . }}
labels:
{{- include "common.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.ingress.className }}
ingressClassName: {{ . }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- with .pathType }}
pathType: {{ . }}
{{- end }}
backend:
service:
name: {{ include "common.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
For more deep dive into this file, which consider linked with
_helper.tpl
- called viainclude
which let you define the information in your chart as function, you can add more logic inside for creating expected value when chart renderingvalues.yaml
- called via.Values
used to expose configuration that can be set at the time of deployment. The defaults for this object are defined in theΒ values.yamlΒ file
Other there, you will have NOTE.txt
or LICENSE
for let you define your chart information when it render or validate when you try publish your chart to public purpose. Like git
, you will have .helmignore
to let your what file not render or use by helm
Now you can preview your chart via debug mode, it has a couple of ways but you can try with two command
# Option 1: with `template`
helm template <name-app> ./path/to/your/Chart.yaml -f ./path/to/your/values.yaml --debug > install.yaml
# Option 2: with `install`
helm install --dry-run --debug ./path/to/your/Chart.yaml
# Others option at https://helm.sh/docs/chart_template_guide/debugging
To upgrade and learn more about the template, you can find to these repositories with can inspire you a lot
π§ Repository and Release your helm chart
Tip
If youβre satisfied with your Helm Chart and plan to share it with colleagues or others for reuse, you should consider setting up a self-hosted repository to publish it.
Setup Repository
Following the documentation of Helm
Info
AΒ chart repositoryΒ is an HTTP server that houses anΒ
index.yaml
Β file and optionally some packaged charts
Thatβs pretty ease to approach and with HTTP Server can serve GET request, that why almost platform like storage object, source code management are preferring for build Helm Repository.
When you work Helm repositories, there are two format need to support by your web server, include index.yaml
and <chart>.tgz
. The index.yaml will define the sitemap for your helping helm can pull specific chart in your repositories
To retrieve and understand why you will have twice of them, you can use helm
command
First of all, for create <chart>.tgz
, you have package
command which help package your chart as compress file. You can do for all project or specific
helm package ./path/to/your/chart
It will write these packages in current directory where you execute this command, but you can specific output location via --destination
or -d
option
After you have your package, currently you can create index.yaml
to indexing your repositories into sitemap which help helm
able to find your chart
helm repo index . --url <url-publish-chart>
For example, you will have this file like
apiVersion: v1
entries:
common:
- apiVersion: v1
appVersion: 1.16.0
created: "2025-06-25T15:31:03.454561644+07:00"
description: A Helm chart for Kubernetes
digest: 068866d02750b354c1edeece52293371db86ede2d24df6be245784e4cea09210
name: common
type: application
urls:
- common-0.1.0.tgz
version: 0.1.0
lib-common:
- apiVersion: v2
appVersion: 1.16.0
created: "2025-06-25T15:31:03.455217867+07:00"
description: A Helm chart for Kubernetes
digest: c249f7738b3dfb9aec6e42d5cc3f69c1d4160266197fc9d5b62a6c0a77458300
name: lib-common
type: application
urls:
- lib-common-0.1.0.tgz
version: 0.1.0
generated: "2025-06-25T15:31:03.453727327+07:00"
Now you can have enough condition to build your own repositories, and you should decide what platform to publish your chart. Some options are considered, like
- ChartMuseum: an open-sourceΒ Helm Chart RepositoryΒ server written in Go (Golang), with support for cloud storage backends
- GitHub Page or Own Webpage
- OCI Registry
To easier workaround and approach, I think most of us familiar with GitHub and GitHub Page are such wonderful option to start because itβs totally free and have large storage to help you publish your chart
Moving on GitHub Page, you have really many options to serve your page but for keeping anything basic, I think Jekyll is kinda suitable. One more reason I prefer Jekyll
because there are many action, plugin are written for GitHub Action, and Jekyll
is default framework static generator of GitHub Action to parse your README.md
or any markdown file into HTML. There are something about this framework you will interested
For making this kind work, you should is owner of repositories of GitHub and can access into settings
to turn on the GitHub Page. Read more at GitHub documentation
Tip
In my opinion, you should add
README.md
in/
directory of project, it will helpJekyll
convert your markdown intoindex.html
at./_site
when generating in actions
You can go live your page from source, because I prefer much with GitHub Actions that why I try to a workflow to handle release GitHub Page
But you can choose Deploy from a branch to let it set it up classic release your page instead of GitHub Action (required your definition π).
I will define workflow at ./github/workflows
directory, you can write a new file gh-page.yaml
for example, and use the basic code base of GitHub
name: Deploy GitHub Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["main"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
# Build job
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Build with Jekyll
uses: actions/jekyll-build-pages@v1
with:
source: ./
destination: ./_site
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
Actions will implement to process two jobs, including
- Build: Use
jekyll
to add build your markdown or another docs concept to html and save all of them in./_site
directory - Deploy: Upload the static contents for serving your page
You will have webpage for helm repository, and you can try to locate into directory where have your index.yaml
, e.g: https://kubewekend.xeusnguyen.xyz/kubernetes/charts
$ helm repo add kubewekend https://kubewekend.xeusnguyen.xyz/kubernetes/charts
$ helm search repo kubewekend
Workflow for auto releasing
But for more enhancement, we can reduce a lot of step like package
, index
for our repository with Chart Releaser
Talk a bit about Chart Releaser, if you read about above article, you will know about helm
provide us Actions and CLI, which cut of time to manually provide index.yaml
, instead of we can use tag
to release your Helm Chart, letβs go to deeper
First of all, we will create the releaser workflow for let GitHub know we will trigger release after merging into main
branch. I will create a new workflow named release.yaml
at ./github/workflows
directory
name: Release Charts
on:
push:
branches:
- main
paths:
- kubernetes/charts/**
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
release:
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Run chart-releaser
uses: helm/chart-releaser-action@v1.6.0
with:
skip_existing: true
charts_dir: kubernetes/charts
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
Letβs delve into the specifics of this workflow:
-
Trigger Condition: The workflow is triggered by pushes to the
main
branch, meaning any merge intomain
will initiate the workflow. -
Job Definition: We will execute a single job named
release
, configured with write permissions to your repository. -
Release Handling: This job will configure Git and invoke the
chart-releaser-action
to manage the release process. You can find detailed parameter configurations for thechart-releaser
CLI at this link. In my scenario, Iβll provide the following configurations to work with this action:skip_existing: true
: This setting allows the workflow to skip releasing a chart if the same version already exists and I havenβt incremented the version number. (Note: While automatic version bumping is possible, itβs not covered in this article.)charts_dir: kubernetes/charts
: Iβve specified my chartsβ location. You can omit this parameter if yourcharts
directory is located in the root of your repository.pages_branch (default: gh-pages)
: This action utilizes this branch to publish yourindex.yaml
and chart packages. You can choose any branch, but be cautious about settingmain
or a protected branch, as this could lead to failures if not properly configured for write access.
Success
Upon the successful completion of the action, your package will be released as a tag on your branch. You can verify this directly in your GitHub repository where youβve self-hosted this action. We only need to set up the action, and
chart-releaser
will handle the rest of the tasks, making it truly convenient! π
Your gh-pages
branch will now publish your index.yaml
. You can verify this by checking the branch URL of the .tgz
link to the release artifact; for example, common-0.1.0
will correspond to https://github.com/Xeus-Territory/kubewekend/releases/download/common-0.1.0/common-0.1.0.tgz
.
However, the setup isnβt complete, as your gh-pages
branch is currently publishing to the main
branch, meaning your webpage wonβt include the necessary routing for index.yaml
. This will cause your helm
commands to fail synchronization. To resolve this, we need to perform a few steps:
- Adjust GITHUB-TOKEN Permissions: Change your
GITHUB_TOKEN
environment settings to specifically target thegh-pages
branch. This will allowgh-pages
to deploy as your default site, rather than themain
branch. - Establish Workflow Dependency: Make your
gh-pages.yaml
workflow dependent on another workflow. Specifically, yourrelease
job should run first, and yourgh-pages.yaml
workflow will execute only after the release process is successfully completed.
Now, you can modify your gh-pages.yaml
action to depend on the state of release.yaml
by using the workflow_run
trigger.
name: Deploy GitHub Pages
on:
workflow_run:
workflows: [Release Charts]
types:
- completed
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
# Build job
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Build with Jekyll
uses: actions/jekyll-build-pages@v1
with:
source: ./
destination: ./_site
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
Your index.yaml
will push by action into root directory, it means you should update your chart url with new version
# Remove the old one
helm repo remove kubewekend
# Add new repo kubewekend
helm repo add kubewekend https://kubewekend.xeusnguyen.xyz
π¦Έ Make your Chart to Hero
Quote
As this journey concludes, itβs vital to capture your inspiration and insights, whether through documentation, paragraphs, or other forms. Your chart can truly shine by not only offering a repository to pull from, but also by providing a high-quality
README.md
that clearly outlines its default parameters and core concepts. This kind of detailed documentation is incredibly valuable in todayβs landscape! π
You have several excellent options to enhance your Helm chart repository, and helm-docs is a standout. This tool automatically generates Markdown documentation for your charts, offering flexibility in how you use it:
- Locally: Naturally, you can run
helm-docs
directly on your local machine. - In CI/CD: For a more advanced setup, integrate it into your Continuous Integration/Continuous Delivery pipeline. This can be complex, but it ensures documentation is always up-to-date with your releases.
- Pre-Commit Hook: For an incredibly efficient workflow, integrate
helm-docs
as a pre-commit hook. This ensures your documentation is generated before you even commit your changes, keeping it perfectly in sync. - Containerized (Docker): Since
helm-docs
can run in a Docker container, you can use it consistently across any environment
Now we have all of arsenal, letβs delve to build your Chart documentation
Info
This tools is written in gotemplate, it will parse your definition in go version (default:
README.md.gotmpl
) toREADME.md
First of all, we should install helm-docs for practicing a bit, you can read more about Installation but I will choose download from source with go
(Requirement: You need have go
in your host to trigger)
go install github.com/norwoodj/helm-docs/cmd/helm-docs@latest
But if you not have go
, you can setup that via bundle version for deb
, rpm
, darwin
or windows
version at Release v1.14.2 (Latest)
Next, you go to directory of your Chart where we define Chart.yaml
and we put the template file in there README.md.gotmpl
{{ template "chart.header" . }}
{{ template "chart.deprecationWarning" . }}
{{ template "chart.badgesSection" . }}
{{ template "chart.description" . }}
{{ template "chart.homepageLine" . }}
{{ template "chart.maintainersSection" . }}
{{ template "chart.sourcesSection" . }}
{{ template "chart.requirementsSection" . }}
{{ template "chart.valuesSection" . }}
{{ template "helm-docs.versionFooter" . }}
This is default version, I try to copy from helm-docs
source with provide a good quality documentation, like version
, valuesSection
, β¦ You can refer that at Markdown Rendering for more options and detail describing
Info
The tool also includes theΒ sprig templating library, so those functions can be used in the templates you supply
Now you can use helm-docs
command for doing this magic function and your result will be written into README.md
in same folder where you put your template
helm-docs --chart-search-root kubernetes/charts --template-files=README.md.gotmpl
I will provide two option for specific in my situation, including
--chart-search-root
: Pointing to where conclude my Chart need to render--template-files
: Setup your default nametemplate-files
to help render your Chart
Info
You can handle render multiple charts with a new update, you can choose specific them if you have requirement
Externally helm-docs
offer pre-commit
hook for automatically trigger this action. To sync up this action before you commit, you can define the .pre-commit-config.yaml
at root directory
---
repos:
- repo: https://github.com/norwoodj/helm-docs
rev: "v1.14.2"
hooks:
- id: helm-docs
args:
# Make the tool search for charts only under the `charts` directory
- --chart-search-root=kubernetes/charts
- --template-files=README.md.gotmpl
This one look pretty same as command we run in local, it does and you can choose another option from docker
to built
version. Read more at: Pre-commit hook
For install your hook in your project, you can install pre-commit
and run command
# Install pre-commit hook
pre-commit install
pre-commit install-hooks
Success
Now your commit requires pass the commit condition before it able to committing, thatβs really make your
README.md
automatically update because we usually forget them π
π€Ύ Conclusion
Success
Thatβs all for this article, hope you find the good way and define for yourself the path to own your first
helm
chart repository. This will become the condition or value for next action when you want to create or manage your application in Kubernetes Cluster with Helm and GitOps
Quote
After week to week, finally I truly comeback for writing something, BTW it costs me a lot of time to practicing, learning and completing this article. So we always see a new in next features, technologies is not stopping so I need to run and ready for all of these challenges. I hope yβall guys will always stay safe, learn and upgrade yourself and see yeah on next weekend. BTW, hope you can double-check my post Dueweekly Tech: 16-06-2025 to 29-06-2025 in this week