Use Helm Charts on Linux
Install Helm 3, manage chart repos, override values, render manifests locally with helm template, and package your own chart for Kubernetes.
Before you start
- ▸A running Kubernetes cluster (minikube, kind, or remote)
- ▸kubectl installed and configured with a valid kubeconfig
- ▸sudo or root access for package installation
- ▸Internet access to reach chart repositories and OCI registries
Helm is the de-facto package manager for Kubernetes. A Helm chart bundles all the Kubernetes manifests, defaults, and lifecycle hooks a workload needs into a single versioned artefact. This guide covers adding repos, installing and upgrading releases, overriding values, using helm template for local rendering, and packaging your own chart from scratch.
Prerequisites
- A working Kubernetes cluster (local via
minikube,kind, or a remote cluster) kubectlconfigured with a valid~/.kube/config- Helm 3 installed (see below)
- Internet access to pull chart repositories
Installing Helm 3
Helm 3 dropped the server-side Tiller component entirely. All state is stored as Kubernetes Secrets inside your cluster. Install it from your distro's package manager or the official script.
Debian / Ubuntu
curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" \
| sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt update && sudo apt install helm -y
Fedora / RHEL / Rocky
sudo dnf install helm -y
On RHEL 8/9 you may need the EPEL repository enabled first: sudo dnf install epel-release -y.
Arch Linux
sudo pacman -S helm
Verify the installation
helm version
Output will look similar to: version.BuildInfo{Version:"v3.14.x", ...}. Anything 3.x is fine for this guide.
Working with Chart Repositories
Helm repositories are simple HTTPS endpoints serving an index.yaml and chart tarballs. You manage them with helm repo.
Add and update repos
# Add the Bitnami repo as an example
helm repo add bitnami https://charts.bitnami.com/bitnami
# Add the official stable repo (community-maintained)
helm repo add stable https://charts.helm.sh/stable
# Sync local index cache from all configured repos
helm repo update
Search for charts
# Search across all added repos
helm search repo nginx
# Search Artifact Hub (the public index of public repos)
helm search hub postgresql
Inspect a chart before installing
helm show chart bitnami/nginx
helm show values bitnami/nginx
helm show values prints every configurable parameter with its default. Pipe it to a file when you want a full reference to edit from.
Installing and Upgrading Releases
A release is a named deployment of a chart into a namespace. Helm tracks each release's history as versioned Secrets.
Basic install
helm install my-nginx bitnami/nginx \
--namespace webapps \
--create-namespace
Override values inline
helm install my-nginx bitnami/nginx \
--namespace webapps \
--create-namespace \
--set service.type=ClusterIP \
--set replicaCount=2
Chaining --set flags works for simple scalar values. For nested keys use dot notation: --set ingress.enabled=true. For anything more complex, use a values file.
Override values with a file
# Dump defaults to a starting file
helm show values bitnami/nginx > my-values.yaml
# Edit what you need, then install
helm install my-nginx bitnami/nginx \
--namespace webapps \
--create-namespace \
-f my-values.yaml
You can layer multiple -f files; later files take precedence. This is useful for a base values file plus an environment-specific override.
Upgrade a release
helm upgrade my-nginx bitnami/nginx \
--namespace webapps \
-f my-values.yaml \
--version 15.4.0
Upgrade or install in one command
helm upgrade --install my-nginx bitnami/nginx \
--namespace webapps \
--create-namespace \
-f my-values.yaml
This pattern is common in CI/CD pipelines because it is idempotent.
View release history and roll back
helm history my-nginx -n webapps
helm rollback my-nginx 1 -n webapps
Rendering Manifests Locally with helm template
helm template renders a chart to plain YAML without touching the cluster. Use it to inspect what Helm will actually send to the API server, feed output to kubectl diff, or integrate with GitOps tools like Flux or Argo CD.
helm template my-nginx bitnami/nginx \
--namespace webapps \
-f my-values.yaml \
> rendered-manifests.yaml
# Diff against the live cluster state
helm template my-nginx bitnami/nginx -f my-values.yaml -n webapps \
| kubectl diff -f - -n webapps
Important: helm template skips cluster validation and hook logic. It is a rendering tool, not a dry-run substitute for all purposes. Use helm upgrade --dry-run --debug when you also want server-side validation.
helm upgrade --install my-nginx bitnami/nginx \
--namespace webapps \
-f my-values.yaml \
--dry-run --debug 2>&1 | less
Packaging Your Own Chart
Creating a chart is straightforward. The scaffold gives you a working example you then adapt.
Scaffold a new chart
helm create mychart
This produces a directory tree:
mychart/
Chart.yaml # metadata: name, version, appVersion
values.yaml # default values
charts/ # chart dependencies live here
templates/ # Go-template Kubernetes manifests
deployment.yaml
service.yaml
ingress.yaml
_helpers.tpl # reusable named templates
NOTES.txt # printed after helm install
Edit Chart.yaml
cat mychart/Chart.yaml
Set version (the chart version, semver) and appVersion (the upstream app version) appropriately. These are separate fields intentionally.
Edit values.yaml and templates
Define your configurable parameters in values.yaml with sensible defaults. Reference them inside templates using {{ .Values.myKey }}. Use _helpers.tpl for label blocks and name helpers shared across templates to keep things DRY.
Lint and test render
# Lint for common errors
helm lint mychart/
# Render locally to check output
helm template my-release mychart/ -f mychart/values.yaml
Declare dependencies
If your chart depends on another (e.g., PostgreSQL), declare it in Chart.yaml:
dependencies:
- name: postgresql
version: "13.x.x"
repository: https://charts.bitnami.com/bitnami
# Download declared dependencies into charts/
helm dependency update mychart/
Package and push
# Creates mychart-0.1.0.tgz
helm package mychart/
# Push to an OCI registry (Helm 3.8+)
helm push mychart-0.1.0.tgz oci://registry.example.com/helm-charts
OCI registries (Docker Hub, GitHub Container Registry, AWS ECR, Harbor) are the modern distribution method. Classic HTTP repos served by chartmuseum still work but OCI is the recommended path going forward.
Verification
# List all releases across all namespaces
helm list -A
# Show the status of a specific release
helm status my-nginx -n webapps
# Confirm Kubernetes objects are running
kubectl get all -n webapps
Troubleshooting
- "Error: INSTALLATION FAILED: cannot re-use a name that is still in use" — A release with that name already exists. Use
helm upgrade --installorhelm uninstallfirst. - Values not taking effect — Later
-ffiles and--setflags override earlier ones. Runhelm get values <release> -n <ns>to see the merged values actually applied. - Outdated chart versions in search — Run
helm repo updateto refresh the local index cache. - Template render errors — Run
helm template --debugto see the partially rendered output alongside the error location. - Dependency not found — Run
helm dependency updateinside the chart directory before packaging or installing locally.
Frequently asked questions
- What is the difference between helm install and helm upgrade --install?
- helm install fails if a release with that name already exists. helm upgrade --install is idempotent: it installs on first run and upgrades on subsequent runs, making it safe for CI/CD pipelines.
- How do I see the final merged values applied to a live release?
- Run helm get values <release> -n <namespace>. Add --all to include default values that were not overridden.
- Is helm template a safe dry run?
- It renders templates locally without cluster access, so it skips server-side validation and hook execution. For a true dry run that validates against the API server, use helm upgrade --install --dry-run --debug.
- Can I use Helm without a Kubernetes cluster for templating?
- Yes. helm template works entirely offline against local chart files. Some charts use lookup functions that query the cluster; those return empty results when no cluster is reachable, so keep that in mind.
- What is the difference between chart version and appVersion in Chart.yaml?
- version is the version of the Helm chart itself and follows semver. appVersion is the version of the upstream application being packaged (e.g., nginx 1.25.3). They are independent and should be bumped separately.
Related guides
Configure Prometheus Alertmanager
Configure Prometheus Alertmanager with routing trees, receivers, inhibition rules, grouping, Go templates, and PagerDuty/Slack on-call integrations.
Build an Intranet Server on Linux
Set up a complete small-office intranet on one Linux box: Nginx web server, dnsmasq local DNS, Samba file sharing, and a Wiki.js team wiki.
Build an nftables Firewall Script
Build a complete nftables firewall from scratch: tables, chains, sets, default-deny input policy, service allowlisting, and persistent systemd configuration.
Caddy as a Reverse Proxy
Set up Caddy as a reverse proxy with automatic HTTPS, load balancing, WebSocket passthrough, reusable snippets, and header control — no certbot required.