Skip to content

Intermediate · Kubernetes fundamentals · topic 24 of 53 · 30 min

Helm and Kustomize

Explanation

Helm is the package manager for Kubernetes. A chart is a package of YAML templates plus default values; installing a chart creates a release, and every upgrade or rollback adds a numbered revision. You change a chart's settings with values files (-f) and --set, without editing the templates. Kustomize, built into kubectl, is the template-free alternative using a base plus overlays.

Why packages for Kubernetes?

A real app needs many objects: a Deployment, a Service, an Ingress, a ConfigMap, an HPA, maybe a ServiceAccount. Now you need it in dev, staging and production, with different replica counts, image tags and host names. Copying five YAML files three times and editing them by hand leads to mistakes that only show up in production.

Helm solves this the way apt or npm do for software: it packages all the YAML of an app into one unit you can install, upgrade, roll back and remove with one command, and it lets you change settings without touching the YAML itself.

Think of it like this: A chart is like a printed form for a bank account opening: the layout is fixed (the templates), and you fill in the blanks (the values). Every customer uses the same form, and each filled-in copy is a separate account (a release).

The words

  • Chart: a package, a folder with Chart.yaml, values.yaml and a templates/ folder.
  • Values: the settings a chart accepts, with defaults in values.yaml.
  • Release: one installed copy of a chart in a cluster, with a name. Install the same chart twice and you have two releases.
  • Revision: every install, upgrade or rollback of a release gets a new number, so Helm can go back.
  • Repository: a place to share charts, either an HTTP server with an index or an OCI container registry.
output
shop-api/
  Chart.yaml          # name, chart version, app version
  values.yaml         # default settings
  templates/
    deployment.yaml
    service.yaml
    ingress.yaml
    _helpers.tpl      # small reusable template snippets
The layout of a chart.
yaml
# Chart.yaml
apiVersion: v2
name: shop-api
description: The shop API
version: 0.3.0        # the chart's own version (semver)
appVersion: "1.4.2"   # the version of the app it deploys
---
# values.yaml
replicaCount: 2
image:
  repository: registry.example.com/shop-api
  tag: "1.4.2"
service:
  port: 80
Chart.yaml describes the package; values.yaml holds the defaults.
yaml
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}
    spec:
      containers:
        - name: api
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
Text inside {{ }} is filled in by Helm. .Values comes from the values, .Release from the release, .Chart from Chart.yaml.

The everyday commands

bash
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update                                   # refresh the list of charts
helm install shop-api ./shop-api -n shop --create-namespace
helm upgrade --install shop-api ./shop-api -n shop -f values-prod.yaml --set image.tag=1.4.3
helm list -n shop                                  # releases and their revisions
helm history shop-api -n shop
helm rollback shop-api 2 -n shop                   # go back to revision 2
helm template shop-api ./shop-api -f values-prod.yaml   # print the YAML, change nothing
helm uninstall shop-api -n shop
upgrade --install installs if the release does not exist yet, so the same command works in CI every time.

Overriding values, and who wins

Helm starts from the chart's values.yaml, then merges each -f file in order (later files win), then applies --set values, which win over everything. Maps (nested keys) are merged key by key; lists are replaced as a whole.

SourcereplicaCountimage.tagimage.repository
values.yaml (chart defaults)21.4.2registry.example.com/shop-api
-f values-prod.yaml6(not set)(not set)
--set image.tag=1.4.3(not set)1.4.3(not set)
Final result61.4.3registry.example.com/shop-api
Tip: Run helm template (or helm upgrade with --dry-run) before a real upgrade to see exactly what YAML Helm will send. Many teams run helm lint and helm template in CI on every pull request.

Kustomize: the template-free alternative

Kustomize is built into kubectl. Instead of templates with blanks, you keep plain YAML in a base folder and small patches in one overlay folder per environment. kubectl apply -k overlays/prod builds the final YAML and applies it.

yaml
# overlays/prod/kustomization.yaml
resources:
  - ../../base
namespace: shop-prod
images:
  - name: registry.example.com/shop-api
    newTag: "1.4.3"
patches:
  - path: replicas.yaml   # a small patch that sets replicas: 6
Then: kubectl apply -k overlays/prod (or kubectl kustomize overlays/prod to just print it).
HelmKustomize
ApproachTemplates plus valuesPlain YAML plus patches
Install, upgrade, rollback historyYes, per releaseNo, it only builds YAML
Sharing with othersCharts in repositoriesFolders in Git
Extra toolThe helm CLIBuilt into kubectl
Careful: Common mistakes. (1) A typo in --set (like imgae.tag) is silently ignored by most charts, so the old tag stays; check with helm get values or helm template. (2) Editing objects with kubectl after Helm installed them: the next helm upgrade overwrites your change. (3) Putting passwords in values.yaml in Git: use a secret manager or an encrypted values file. (4) Confusing version (the chart) with appVersion (the app). (5) Running upgrades by hand with different -f files each time: keep the exact command in your CI pipeline so every upgrade is repeatable.

Helm 3 removed Tiller, the old server-side component, so Helm now talks to the API server with your own kubeconfig permissions. Helm 4 was released in late 2025; the core commands in this lesson work the same, but check the Helm docs for what changed.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Helm and Kustomize · 1/7

Helm and Kustomize

In this lesson you will learn Helm, the package manager for Kubernetes, and Kustomize, the alternative built into kubectl.

Prefer a video by a teacher? Find free videos on “helm charts tutorial values templates release rollback” on YouTube ↗

In real life: One chart, three environments at a private bank

A private bank's internal team deploys its loan-eligibility API with one Helm chart and three values files: values-dev.yaml (1 replica, debug logging), values-uat.yaml (2 replicas) and values-prod.yaml (6 replicas, production host name, stricter resources). The CI pipeline runs the same helm upgrade --install command for each environment, changing only the -f file and setting image.tag to the git SHA it just built. When a release breaks the EMI calculator in UAT, helm rollback restores the previous revision in seconds while the developers fix the bug.

bash
helm upgrade --install loan-api ./charts/loan-api -n loans-prod \
  -f charts/loan-api/values-prod.yaml --set image.tag=9f3c2ab
helm history loan-api -n loans-prod
The deploy step in the pipeline, the same for every environment except the values file.

Practice (0/3 done)

Task 1 · Question

Which command shows the YAML a chart would produce, without changing anything in the cluster?

Task 2 · Code · Python

Write deep_merge(base, override) that returns a NEW dict: keys from override replace keys in base, except when both values are dicts, which are merged recursively. Lists are replaced, not merged. Do not change the inputs. Then write final_values(defaults, files, set_values) that merges the chart defaults, then each dict in the list files in order, then set_values, like Helm does.

Task 3 · Practice

Create a tiny chart for a notice-board web app: a Chart.yaml, a values.yaml with replicaCount, image.repository, image.tag and service.port, and a templates/service.yaml that uses .Release.Name and .Values.service.port. Then write the commands to render it, install it as "notices" in namespace college, upgrade it with replicaCount=3 using --set, and roll back.

Quick quiz

Question 1

1.In Helm, what is a release?

Question 2

2.The chart default is replicaCount: 2, values-prod.yaml sets 6, and the command adds --set replicaCount=8. What is used?

Question 3

3.Which command installs a release if it does not exist and upgrades it if it does?

Question 4

4.How do you apply a Kustomize overlay with kubectl?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

In Helm, what is a release?

Answer: An installed copy of a chart in a cluster, with its own name

Installing the same chart twice with two names gives two releases.

The chart default is replicaCount: 2, values-prod.yaml sets 6, and the command adds --set replicaCount=8. What is used?

Answer: 8

--set has the highest priority, above values files and chart defaults.

Which command installs a release if it does not exist and upgrades it if it does?

Answer: helm upgrade --install

upgrade --install makes a CI deploy step that works on the first run and every run after.

How do you apply a Kustomize overlay with kubectl?

Answer: kubectl apply -k overlays/prod

The -k flag tells kubectl to build the kustomization in that folder and apply it.

Which section must every CloudFormation template have?Related

Answer: Resources

Resources is the only required section. All the others are optional.

From AWS CloudFormation

What does "declarative" mean in Kubernetes?Related

Answer: You describe the desired state and controllers make it happen

You write the result you want in YAML, and reconciliation loops keep the cluster matching it.

From Why Kubernetes, and how a cluster works

Which file should be committed to Git?Related

Answer: package-lock.json

The lock file guarantees the same versions everywhere; node_modules and secrets are not committed.

From Node.js basics

Which package manager do you use on Rocky Linux?Related

Answer: dnf

Rocky Linux and other RHEL-family systems use dnf. apt is for Debian and Ubuntu, apk for Alpine.

From The Linux filesystem and everyday commands

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Kubernetes fundamentals”. The module exam comes next.
  2. Module 5 exam: Kubernetes fundamentals · 13 questions · 20 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, CI/CD pipelines. 53 topics left in the course before the final exam.

← Previous: Namespaces, ConfigMaps, Secrets, resources and probes