Intermediate · Kubernetes fundamentals · topic 24 of 53 · 30 min
Helm and Kustomize
Explanation
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.
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.
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# 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# 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 }}"The everyday commands
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 shopOverriding 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.
| Source | replicaCount | image.tag | image.repository |
|---|---|---|---|
| values.yaml (chart defaults) | 2 | 1.4.2 | registry.example.com/shop-api |
| -f values-prod.yaml | 6 | (not set) | (not set) |
| --set image.tag=1.4.3 | (not set) | 1.4.3 | (not set) |
| Final result | 6 | 1.4.3 | registry.example.com/shop-api |
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.
# 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| Helm | Kustomize | |
|---|---|---|
| Approach | Templates plus values | Plain YAML plus patches |
| Install, upgrade, rollback history | Yes, per release | No, it only builds YAML |
| Sharing with others | Charts in repositories | Folders in Git |
| Extra tool | The helm CLI | Built into kubectl |
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
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.
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-prodPractice (0/3 done)
Which command shows the YAML a chart would produce, without changing anything in the cluster?
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.
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
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Services, Ingress and the Gateway APIKubernetes fundamentals · same module
- Pods, ReplicaSets and DeploymentsKubernetes fundamentals · same module
- AWS CloudFormationCloud Computing (AWS, Azure, Google Cloud) · Infrastructure as code
- Node.js basicsJavaScript Programming (language in depth) · Performance and Node.js
- Go in cloud and DevOps: Kubernetes, Terraform and PrometheusGo Programming (backend and cloud) · CLI tools and Go in cloud and DevOps
- IaC in a team: reviews, pipelines and policyCloud Computing (AWS, Azure, Google Cloud) · Infrastructure as code
Questions people ask about this
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.
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.
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
- This is the last topic of “Kubernetes fundamentals”. The module exam comes next.
- Module 5 exam: Kubernetes fundamentals · 13 questions · 20 min, without help. 5 topics of this module still to finish first.
- Then the next module, CI/CD pipelines. 53 topics left in the course before the final exam.
← Previous: Namespaces, ConfigMaps, Secrets, resources and probes