Certified Kubernetes Administrator (CKA) #21 Helm and Kustomize: Managing Manifests
In #20 Networking 3 we covered CoreDNS and NetworkPolicy and wrapped up the networking domain. Before moving on to troubleshooting, this post organizes two tools that manage a bundle of manifests in a way that is repeatable and variable per environment. Those tools are Helm and Kustomize.
These two tools don’t carry much weight in CKA. Still, both are the standard tools for managing manifests in practice, and on the exam they can appear as short tasks like “install the given chart” or “change the image tag with a kustomization.” Getting just the core commands and directory structure into your hands is enough.
Why we need manifest management tools #
So far we’ve written manifests by hand and applied them with kubectl apply -f. In practice, though, you have to deploy the same app to dev, staging, and prod environments with slight differences each time. Replica count, image tag, resource limits, and environment variables differ per environment. If you copy the manifests once per environment, duplication piles up and changes get missed.
Two approaches split off to solve this problem.
- Helm: Turns manifests into templates and renders them by injecting values. It packages by chart, manages versions, and handles install, upgrade, and rollback as commands.
- Kustomize: Leaves the original manifests (base) untouched and composes them by layering only the per-environment differences as overlays. It works with pure YAML — no template syntax — and is built into kubectl.
The two tools have different philosophies but the same goal: producing manifests for multiple environments from a single definition.
Helm #
Helm is the Kubernetes package manager. Just as apt or brew handle packages, Helm installs and upgrades Kubernetes apps by the unit of a chart. A chart is a directory holding templated manifests and default values (values.yaml).
Registering a chart repository #
To use a public chart, you first register the repository and refresh the index.
# Add a repository
helm repo add bitnami https://charts.bitnami.com/bitnami
# Refresh the index (the latest chart list of all registered repos)
helm repo update
# Check registered repositories
helm repo list
# Search for a chart
helm search repo nginxInstalling a chart #
helm install installs a chart on the cluster and tracks the result under a name called a release. You can install the same chart multiple times under different names.
# Order is <release name> <chart>
helm install my-nginx bitnami/nginx
# List installed releases
helm list
# Install into a specific namespace
helm install my-nginx bitnami/nginx -n web --create-namespaceInjecting values: –set and -f #
To override part of a chart’s defaults, you inject values. Pass one or two with --set, and several at once with a values file (-f).
# Override one or two values inline
helm install my-nginx bitnami/nginx --set replicaCount=3
# Override many at once with a values file
helm install my-nginx bitnami/nginx -f my-values.yaml
# The two methods can be combined, and --set takes priority
helm install my-nginx bitnami/nginx -f my-values.yaml --set image.tag=1.25In my-values.yaml, you only write the parts of the chart’s values.yaml structure you want to change.
replicaCount: 3
image:
tag: "1.25"
service:
type: NodePortRender only, without installing: helm template #
When you want to see what manifests a chart actually produces, use helm template. It renders the result to standard output without applying it to the cluster. This is useful for exam tasks like “verify the replica count of the Deployment this chart produces.”
# Render the result to the screen
helm template my-nginx bitnami/nginx --set replicaCount=3
# Save to a file to review
helm template my-nginx bitnami/nginx > rendered.yamlUpgrade and rollback #
When you change the values or chart version of an installed release, use helm upgrade. Each change is recorded under a revision number, and if something goes wrong you roll back to a previous revision.
# Upgrade by changing values (revision increments)
helm upgrade my-nginx bitnami/nginx --set replicaCount=5
# Install if the release doesn't exist, upgrade if it does
helm upgrade --install my-nginx bitnami/nginx
# Check the revision history
helm history my-nginx
# Roll back to the previous revision
helm rollback my-nginx
# Roll back to a specific revision
helm rollback my-nginx 2Status check and removal #
# Detailed release status
helm status my-nginx
# The actual manifests the release applied
helm get manifest my-nginx
# Delete the release (removes all related resources)
helm uninstall my-nginxhelm uninstall removes all the Kubernetes resources that release created in one shot. It’s cleaner than deleting them one by one with kubectl delete.
Kustomize #
Kustomize transforms manifests through pure YAML composition without template syntax. It keeps the original in base and the per-environment differences in overlays, then layers the two. Kustomize is built into kubectl, so you apply it directly with kubectl apply -k — no separate install needed.
kustomization.yaml #
Every Kustomize directory has a kustomization.yaml. This file declares which manifests (resources) to bundle and what transformations to apply.
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yamlbase/deployment.yaml and base/service.yaml are ordinary manifests. They’re exactly what you’d write by hand, with no special syntax.
The base and overlays structure #
You separate per-environment differences into overlay directories. The overlay’s kustomization.yaml references base and adds only the transformations on top of it.
myapp/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ └── service.yaml
└── overlays/
├── dev/
│ └── kustomization.yaml
└── prod/
└── kustomization.yamlThe prod overlay pulls in base and declares only the changes prod needs.
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namePrefix: prod-
commonLabels:
env: prod
images:
- name: nginx
newTag: "1.25.3"
replicas:
- name: web
count: 5This overlay prefixes the base Deployment name with prod-, adds an env: prod label to every resource, changes the image tag to 1.25.3, and sets the replicas to 5. It doesn’t touch base at all.
patchesStrategicMerge #
Changes that are hard to express with built-in transformations like images or replicas are handled with a patch. patchesStrategicMerge merges a partial manifest — containing only the fields to change — into base.
# part of overlays/prod/kustomization.yaml
patchesStrategicMerge:
- resources-patch.yaml# overlays/prod/resources-patch.yaml (only the fields to change)
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
template:
spec:
containers:
- name: web
resources:
requests: { cpu: "250m", memory: "256Mi" }
limits: { cpu: "500m", memory: "512Mi" }In a patch you only write the keys needed for identification (kind, name, container name) and the fields to change. Kustomize finds the matching location in base and merges them.
configMapGenerator #
You can generate a ConfigMap from files or literals instead of writing it directly. A ConfigMap made with configMapGenerator gets a content hash appended to its name, so when the content changes the name changes too. This has the advantage that Pods referencing it automatically get a rolling update.
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=info
- TIMEOUT=30
- name: app-files
files:
- config.propertiesApply and render: kubectl -k #
Kustomize is built into kubectl, so you can use it without a separate binary.
# Check the composed result on the screen (doesn't apply)
kubectl kustomize overlays/prod
# Apply the composed result directly
kubectl apply -k overlays/prod
# Delete the composed result
kubectl delete -k overlays/prodChecking the result first with kubectl kustomize and then applying it with kubectl apply -k is the safe flow. With aliases, you can type it short like k apply -k overlays/prod and k kustomize overlays/prod.
Helm vs. Kustomize #
The two tools solve the same problem in different ways.
| Category | Helm | Kustomize |
|---|---|---|
| Approach | Template + value injection | Pure YAML overlay |
| Syntax | Requires learning Go templates ({{ }}) | No extra syntax |
| Install | Install a separate binary | Built into kubectl (-k) |
| Packaging | Distribute, share, and version via chart | Directory structure |
| Release tracking | Managed by release and revision | None (stateless) |
| Rollback | Built-in helm rollback | None (revert via VCS) |
| Installing external apps | Rich set of public charts | Write manifests yourself |
| Best fit | Installing third-party apps, complex parameterization | Per-environment variation of your own apps |
In practice the two are sometimes used together: install external apps as Helm charts, and manage per-environment variation of your own apps with Kustomize. There’s no single right answer — follow your team’s standard.
CKA exam points #
- Helm and Kustomize carry little weight in CKA. Still, they can appear as short tasks, so it’s safe to memorize the core commands.
- For Helm, get
helm install,helm upgrade --install,helm list,helm rollback, andhelm template(for checking values) into your hands. The habit of verifying what gets produced withhelm templatebefore installing reduces wrong answers. - For Kustomize, just firmly remember
kubectl apply -kandkubectl kustomize. Before applying, check the composed result first withkubectl kustomize. - For a task like “change the image tag,” recall the overlay’s
images.newTagfor Kustomize and--set image.tagfor Helm, and you’ll be quick. - Whether the exam environment has the Helm binary and which charts are pre-registered is stated in the task. Read the instructions accurately first.
To get manifest management tools into your hands directly, the fastest path is to build a base/overlay with the scenarios in Kubernetes Hands-on Practice 2 and to install, upgrade, and roll back a chart.
Wrap-up #
What this post locked in:
- Manifest management tools produce manifests for multiple environments from a single definition. Helm does it with templates; Kustomize does it with overlays
- Helm. Register repos with
repo add/repo update, manage releases withinstall/upgrade/rollback, inject values with--setand-f, check the render before applying withhelm template, andhelm list/history/uninstall - Kustomize. Compose base and overlays with
kustomization.yaml, partial merge withpatchesStrategicMerge, generate ConfigMaps withconfigMapGenerator, apply withkubectl apply -k, check the composition withkubectl kustomize - The difference between the two. Template vs. overlay, separate install vs. built into kubectl, release tracking or not. The common choice is Helm for external apps and Kustomize for variation of your own apps
- Exam points. The weight is small but memorize the core commands. Verify with
helm templateandkubectl kustomizebefore applying
Next: Troubleshooting 1 #
With manifest management organized, we’ve finished the domain of handling tools. Now we enter troubleshooting (30%), the largest-weight area in CKA.
In #22 Troubleshooting 1: Pod and App, we’ll cover the app-level failures you run into most often. We’ll learn to distinguish the symptoms of Pending (can’t schedule), CrashLoopBackOff (container terminates repeatedly), ImagePullBackOff (image pull failure), and OOMKilled (memory limit exceeded), and get into our hands the procedure of tracing the cause with kubectl describe, kubectl logs, and events and fixing it.