Module 1.3: Helm - Kubernetes Package Manager
Complexity:
[MEDIUM]- Essential exam skill for 2025Time to Complete: 40-50 minutes
Prerequisites: Module 0.1 (working cluster), basic YAML knowledge
What You’ll Be Able to Do
Section titled “What You’ll Be Able to Do”After this module, you will be able to:
- Deploy applications using Helm charts (install, upgrade, rollback, uninstall)
- Customize Helm releases with values files and —set overrides
- Debug a failed Helm release by inspecting release history and template rendering
- Explain the Helm architecture (charts, releases, repositories) and when to use Helm vs raw manifests
Why This Module Matters
Section titled “Why This Module Matters”Helm is new to the CKA 2025 curriculum. You will be tested on it.
Before Helm, deploying a complex application meant managing dozens of YAML files. A typical web app needs Deployments, Services, ConfigMaps, Secrets, Ingress, ServiceAccounts, RBAC rules… all maintained separately, all needing updates together.
Helm packages all these resources into a single chart. Install with one command. Upgrade with one command. Rollback with one command. It’s why Helm is called “the package manager for Kubernetes”—same concept as apt/yum/brew, but for K8s resources.
The App Store Analogy
Think of Helm like an app store. Instead of manually downloading and configuring software piece by piece, you search for what you need (nginx, prometheus, mysql), click install, and everything is set up correctly. Want to customize? Adjust the settings (values). Want to update? Click upgrade. Something broke? Rollback to the previous version.
What You’ll Learn
Section titled “What You’ll Learn”By the end of this module, you’ll be able to:
- Install and manage applications with Helm
- Search for and use public charts
- Customize deployments with values
- Upgrade and rollback releases
- Understand chart structure (for troubleshooting)
Part 1: Helm Concepts
Section titled “Part 1: Helm Concepts”1.1 Core Terminology
Section titled “1.1 Core Terminology”| Term | Definition |
|---|---|
| Chart | A package of Kubernetes resources (like a .deb or .rpm) |
| Release | An instance of a chart running in your cluster |
| Repository | A collection of charts (like apt repository) |
| Values | Configuration options to customize a chart |
1.2 How Helm Works
Section titled “1.2 How Helm Works”┌────────────────────────────────────────────────────────────────┐│ Helm Architecture ││ ││ You ││ │ ││ │ helm install myapp bitnami/nginx ││ ▼ ││ ┌──────────┐ ┌─────────────┐ ┌────────────────────┐ ││ │ Helm │────►│ Chart │────►│ Kubernetes API │ ││ │ CLI │ │ (template) │ │ (creates resources)│ ││ └──────────┘ └─────────────┘ └────────────────────┘ ││ │ ││ │ Values (customization) ││ │ --set replicas=3 ││ │ -f myvalues.yaml ││ ▼ ││ ┌──────────────────────────────────────────────────────────┐ ││ │ Release stored as Secret in cluster │ ││ │ (tracks version, values, manifests for rollback) │ ││ └──────────────────────────────────────────────────────────┘ ││ │└────────────────────────────────────────────────────────────────┘1.3 Helm 3 vs Helm 2
Section titled “1.3 Helm 3 vs Helm 2”Helm 3 (current) removed Tiller—a server component that ran in the cluster. Now Helm talks directly to the Kubernetes API using your kubeconfig. This is simpler and more secure.
# Helm 3 (current) - no Tiller neededhelm install myapp ./mychart
# Helm 2 (deprecated) - required Tiller# Don't use this anymoreDid You Know?
Helm release information is stored as Secrets in your cluster. Run
kubectl get secrets -l owner=helmto see them. This is how Helm tracks what’s installed and enables rollback.
Part 2: Installing Helm
Section titled “Part 2: Installing Helm”2.1 Install Helm CLI
Section titled “2.1 Install Helm CLI”# macOSbrew install helm
# Linux (script)curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Linux (package manager)# Debian/Ubuntucurl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/nullecho "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.listsudo apt-get updatesudo apt-get install helm
# Verify installationhelm version2.2 Add a Repository
Section titled “2.2 Add a Repository”# Add the Bitnami repository (popular, well-maintained charts)helm repo add bitnami https://charts.bitnami.com/bitnami
# Add other common repositorieshelm repo add ingress-nginx https://kubernetes.github.io/ingress-nginxhelm repo add prometheus-community https://prometheus-community.github.io/helm-charts
# Update repository indexhelm repo update
# List configured repositorieshelm repo listPart 3: Working with Charts
Section titled “Part 3: Working with Charts”3.1 Searching for Charts
Section titled “3.1 Searching for Charts”# Search in Artifact Hub (online registry)helm search hub nginx
# Search in your added repositorieshelm search repo nginx
# Show all versions of a charthelm search repo bitnami/nginx --versions
# Get info about a specific charthelm show chart bitnami/nginxhelm show readme bitnami/nginxhelm show values bitnami/nginx # See all configurable values3.2 Installing a Chart
Section titled “3.2 Installing a Chart”# Basic installhelm install my-nginx bitnami/nginx# ^^^^^^^^ ^^^^^^^^^^^^^# release chart name# name
# Install in specific namespacehelm install my-nginx bitnami/nginx -n web --create-namespace
# Install with custom valueshelm install my-nginx bitnami/nginx --set replicaCount=3
# Install with values filehelm install my-nginx bitnami/nginx -f myvalues.yaml
# Install specific versionhelm install my-nginx bitnami/nginx --version 15.0.0
# Dry-run (see what would be created)helm install my-nginx bitnami/nginx --dry-run
# Generate manifests only (don't install)helm template my-nginx bitnami/nginx > manifests.yaml3.3 Listing and Inspecting Releases
Section titled “3.3 Listing and Inspecting Releases”# List all releaseshelm list
# List in all namespaceshelm list -A
# List including failed releaseshelm list --all
# Get status of a releasehelm status my-nginx
# Get values used for a releasehelm get values my-nginx
# Get all values (including defaults)helm get values my-nginx --all
# Get the manifests that were installedhelm get manifest my-nginxGotcha: Namespace Matters
Helm releases are namespaced. If you installed in namespace
web, you must specify-n webfor all subsequent commands, or you’ll get “release not found.”
Part 4: Customizing with Values
Section titled “Part 4: Customizing with Values”Pause and predict: You run
helm install my-app bitnami/nginx --set replicaCount=3 -f values.yamlwherevalues.yamlcontainsreplicaCount: 5. How many replicas will you get? Think about which source of values takes priority.
4.1 Values Hierarchy
Section titled “4.1 Values Hierarchy”Values can be set in multiple ways. Priority (highest to lowest):
--setflags on command line-fvalues files (later files override earlier)- Default values in chart’s
values.yaml
# Example: Multiple ways to set replicashelm install my-nginx bitnami/nginx \ -f base-values.yaml \ -f production-values.yaml \ --set replicaCount=5 # This wins4.2 Using —set
Section titled “4.2 Using —set”# Simple valuehelm install my-nginx bitnami/nginx --set replicaCount=3
# Nested valuehelm install my-nginx bitnami/nginx --set service.type=NodePort
# Multiple valueshelm install my-nginx bitnami/nginx \ --set replicaCount=3 \ --set service.type=NodePort \ --set service.nodePorts.http=30080
# Array valueshelm install my-app ./mychart --set 'ingress.hosts[0]=example.com'
# String that looks like number (use quotes)helm install my-app ./mychart --set 'version="1.0"'4.3 Using Values Files
Section titled “4.3 Using Values Files”replicaCount: 3
service: type: NodePort nodePorts: http: 30080
resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m"
ingress: enabled: true hostname: myapp.example.com# Use the values filehelm install my-nginx bitnami/nginx -f myvalues.yaml4.4 Viewing Default Values
Section titled “4.4 Viewing Default Values”# See all configurable optionshelm show values bitnami/nginx
# Save to file for referencehelm show values bitnami/nginx > nginx-defaults.yamlExam Tip
During the CKA exam, use
helm show values <chart>to quickly see what can be customized. Don’t memorize chart values—learn to look them up.
Part 5: Upgrading and Rolling Back
Section titled “Part 5: Upgrading and Rolling Back”5.1 Upgrading a Release
Section titled “5.1 Upgrading a Release”# Upgrade with new valueshelm upgrade my-nginx bitnami/nginx --set replicaCount=5
# Upgrade with values filehelm upgrade my-nginx bitnami/nginx -f newvalues.yaml
# Upgrade to new chart versionhelm upgrade my-nginx bitnami/nginx --version 16.0.0
# Upgrade or install if not existshelm upgrade --install my-nginx bitnami/nginx
# Reuse values from previous release + new valueshelm upgrade my-nginx bitnami/nginx --reuse-values --set replicaCount=5Stop and think: You run
helm upgrade my-app bitnami/nginxwithout--reuse-valuesand without specifying any values. What happens to all the custom values you set during the original install? Where does Helm get the values for this upgrade?
5.2 Release History
Section titled “5.2 Release History”# View upgrade historyhelm history my-nginx
# Output:# REVISION STATUS CHART DESCRIPTION# 1 superseded nginx-15.0.0 Install complete# 2 superseded nginx-15.0.0 Upgrade complete# 3 deployed nginx-15.0.1 Upgrade complete5.3 Rolling Back
Section titled “5.3 Rolling Back”# Rollback to previous revisionhelm rollback my-nginx
# Rollback to specific revisionhelm rollback my-nginx 1
# Dry-run rollbackhelm rollback my-nginx 1 --dry-runWar Story: The Accidental Upgrade
An engineer ran
helm upgrade my-app ./chartwithout specifying values, accidentally resetting everything to defaults. Production database credentials? Gone. Custom resource limits? Gone. The fix washelm rollback my-app 1, but it took 20 minutes to figure out what happened. Lesson: Always use--reuse-valuesor explicitly specify all values on upgrade.
Part 6: Uninstalling
Section titled “Part 6: Uninstalling”# Uninstall a releasehelm uninstall my-nginx
# Uninstall but keep history (allows rollback)helm uninstall my-nginx --keep-history
# Uninstall in specific namespacehelm uninstall my-nginx -n webPart 7: Chart Structure (For Understanding)
Section titled “Part 7: Chart Structure (For Understanding)”You don’t need to create charts for CKA, but understanding structure helps troubleshooting.
mychart/├── Chart.yaml # Metadata (name, version, description)├── values.yaml # Default configuration├── charts/ # Dependencies (subcharts)├── templates/ # Kubernetes manifest templates│ ├── deployment.yaml│ ├── service.yaml│ ├── ingress.yaml│ ├── _helpers.tpl # Template helpers│ └── NOTES.txt # Post-install message└── README.md # DocumentationWhat would happen if: You delete the Kubernetes Secret that stores a Helm release’s metadata (the ones labeled
owner=helm). Can you still runhelm upgradeorhelm rollbackon that release?
7.1 How Templates Work
Section titled “7.1 How Templates Work”# templates/deployment.yaml (simplified)apiVersion: apps/v1kind: Deploymentmetadata: name: {{ .Release.Name }}-nginxspec: replicas: {{ .Values.replicaCount }} template: spec: containers: - name: nginx image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"Values from values.yaml or --set replace the {{ }} placeholders.
7.2 Debugging Templates
Section titled “7.2 Debugging Templates”# See what YAML would be generatedhelm template my-nginx bitnami/nginx -f myvalues.yaml
# Install with debug infohelm install my-nginx bitnami/nginx --debug --dry-runPart 8: Common Exam Scenarios
Section titled “Part 8: Common Exam Scenarios”8.1 Install an Application
Section titled “8.1 Install an Application”# Task: Install nginx with 3 replicas exposed on NodePort 30080
# Solution:helm repo add bitnami https://charts.bitnami.com/bitnamihelm repo update
helm install web bitnami/nginx \ --set replicaCount=3 \ --set service.type=NodePort \ --set service.nodePorts.http=300808.2 Upgrade with New Configuration
Section titled “8.2 Upgrade with New Configuration”# Task: Upgrade the existing nginx release to use 5 replicas
# Solution:helm upgrade web bitnami/nginx --reuse-values --set replicaCount=5
# Verify:kubectl get deployment8.3 Rollback After Failed Upgrade
Section titled “8.3 Rollback After Failed Upgrade”# Task: Rollback to the previous working version
# Solution:helm history webhelm rollback web
# Verify:helm status webDid You Know?
Section titled “Did You Know?”-
Helm hooks let you run jobs before/after install, upgrade, or delete. Charts use this for database migrations, certificate generation, etc.
-
Helm uses Go templates. The
{{ }}syntax is Go’s template language. Understanding basic Go templating helps when debugging complex charts. -
ChartMuseum is an open-source Helm repository server. Organizations use it to host private charts.
Common Mistakes
Section titled “Common Mistakes”| Mistake | Problem | Solution |
|---|---|---|
Forgetting -n namespace | Release not found | Always specify namespace |
Not using --reuse-values | Values reset on upgrade | Use --reuse-values or specify all values |
| Wrong repo URL | Chart not found | Check helm repo list, helm repo update |
| Ignoring dry-run | Unexpected resources created | Always --dry-run first for complex changes |
| Not checking helm status | Don’t know if install succeeded | Run helm status <release> after install |
-
During the CKA exam, you need to install a chart but you don’t know the exact parameter name for setting the Service type to NodePort. The exam environment has no internet access. How do you find the correct parameter name, and what command do you use?
Answer
Run `helm show values` to display all configurable values with their defaults and structure. You can pipe it through grep to narrow down: `helm show values bitnami/nginx | grep -i service` to find service-related parameters. This works entirely offline since the chart is already in your local repository cache. For the actual install, you'd use something like `helm install my-app bitnami/nginx --set service.type=NodePort`. The key exam skill is knowing that `helm show values` is your documentation when you can't access the internet. -
A teammate installed a Helm release last week, but now
helm listshows nothing andhelm status my-appreturns “release not found.” However,kubectl get deploy my-appshows the deployment still running. What are two possible explanations?Answer
First, the release may have been installed in a different namespace — Helm releases are namespaced, so you need `helm list -n` or `helm list -A` to find it. Second, someone may have run `helm uninstall my-app` without `--keep-history`, which removes the Helm release metadata (stored as Secrets labeled `owner=helm`) but doesn't delete the Kubernetes resources if they were modified outside Helm or if the uninstall partially failed. You can verify by checking `kubectl get secrets -l owner=helm -A` to see if any release secrets exist. The running deployment is now "orphaned" from Helm's perspective and must be managed directly with kubectl. -
You upgraded a production Helm release, and now the application is returning 500 errors. You need to revert immediately. The release has 4 revisions in its history. What commands do you run, and how do you verify the rollback succeeded?
Answer
First, check the history: `helm history my-app -n production` to see which revision was the last working one. Then roll back: `helm rollback my-app 3 -n production` (assuming revision 3 was the last good state, since revision 4 caused the issue). Verify with: `helm status my-app -n production` to confirm the release status is "deployed" at the expected revision, then `kubectl get pods -n production` to check pods are Running and not in CrashLoopBackOff. You can also run `helm get values my-app -n production` to confirm the values match the known-good configuration. Helm rollback creates a new revision (5) with the same config as revision 3, so your history is preserved. -
Your CI/CD pipeline runs
helm template my-app ./chart > manifests.yaml && kubectl apply -f manifests.yamlinstead ofhelm install. A colleague suggests usinghelm install --dry-runfor validation instead. What critical difference would this catch thathelm templatemisses?Answer
`helm template` renders templates locally without connecting to the Kubernetes cluster. It cannot validate whether the API resources actually exist on the cluster (e.g., if you reference a CRD that isn't installed), whether resource names conflict with existing objects, or whether the cluster's API version supports the resources in the chart. `helm install --dry-run` connects to the cluster and runs server-side validation, catching issues like "no matches for kind 'ServiceMonitor'" (missing CRD) or invalid API versions. However, neither approach actually creates resources. For the CI/CD pipeline, using `helm install` or `helm upgrade --install` is better than the template-and-apply pattern because it also gives you Helm's release tracking, history, and rollback capabilities.
Hands-On Exercise
Section titled “Hands-On Exercise”Task: Deploy and manage an nginx application using Helm.
Steps:
- Add the Bitnami repository:
helm repo add bitnami https://charts.bitnami.com/bitnamihelm repo update- Search for nginx charts:
helm search repo nginx- View default values:
helm show values bitnami/nginx | head -50- Install nginx with custom values:
helm install my-web bitnami/nginx \ --set replicaCount=2 \ --set service.type=ClusterIP \ -n helm-demo --create-namespace- Verify the installation:
helm list -n helm-demohelm status my-web -n helm-demokubectl get all -n helm-demo- Upgrade to 3 replicas:
helm upgrade my-web bitnami/nginx \ --reuse-values \ --set replicaCount=3 \ -n helm-demo- Check history:
helm history my-web -n helm-demo- Rollback to revision 1:
helm rollback my-web 1 -n helm-demokubectl get pods -n helm-demo # Should show 2 pods- Get the values used:
helm get values my-web -n helm-demohelm get values my-web -n helm-demo --all- Cleanup:
helm uninstall my-web -n helm-demokubectl delete namespace helm-demoSuccess Criteria:
- Can add repositories and search for charts
- Can install charts with custom values
- Can upgrade releases
- Can view history and rollback
- Understand the relationship between releases and Kubernetes resources
Practice Drills
Section titled “Practice Drills”Drill 1: Helm Speed Test (Target: 3 minutes)
Section titled “Drill 1: Helm Speed Test (Target: 3 minutes)”Complete these tasks as fast as possible:
# 1. Add bitnami repo (if not added)helm repo add bitnami https://charts.bitnami.com/bitnami
# 2. Search for redishelm search repo redis
# 3. Show available values for redishelm show values bitnami/redis | head -50
# 4. Install redis with custom replica counthelm install my-redis bitnami/redis --set replica.replicaCount=2 --set auth.enabled=false
# 5. List releaseshelm list
# 6. Uninstallhelm uninstall my-redisDrill 2: Values File Practice (Target: 5 minutes)
Section titled “Drill 2: Values File Practice (Target: 5 minutes)”# Create a values filecat << 'EOF' > nginx-values.yamlreplicaCount: 3service: type: NodePort nodePorts: http: 30080resources: requests: memory: "64Mi" cpu: "50m" limits: memory: "128Mi" cpu: "100m"EOF
# Install with values filehelm install web bitnami/nginx -f nginx-values.yaml
# Verify values appliedkubectl get pods # Should show 3 replicaskubectl get svc # Should show NodePort 30080
# Get values usedhelm get values web
# Cleanuphelm uninstall webrm nginx-values.yamlDrill 3: Upgrade and Rollback Race (Target: 5 minutes)
Section titled “Drill 3: Upgrade and Rollback Race (Target: 5 minutes)”# Install initial versionhelm install rollback-test bitnami/nginx --set replicaCount=2
# Upgrade to 3 replicashelm upgrade rollback-test bitnami/nginx --reuse-values --set replicaCount=3
# Verifykubectl get pods | grep rollback-test | wc -l # Should be 3
# Check historyhelm history rollback-test
# Rollback to revision 1helm rollback rollback-test 1
# Verify rollbackkubectl get pods | grep rollback-test | wc -l # Should be 2
# Cleanuphelm uninstall rollback-testDrill 4: Troubleshooting - Wrong Values (Target: 5 minutes)
Section titled “Drill 4: Troubleshooting - Wrong Values (Target: 5 minutes)”# Setup: Install with "broken" valueshelm install broken-nginx bitnami/nginx --set image.tag=nonexistent-tag
# Observe the problemkubectl get pods # ImagePullBackOff
# YOUR TASK: Fix by upgrading with correct image tagSolution
# Check current valueshelm get values broken-nginx
# Fix with upgradehelm upgrade broken-nginx bitnami/nginx --reuse-values --set image.tag=1.25
# Verifykubectl get pods # Running!
# Cleanuphelm uninstall broken-nginxDrill 5: Dry Run and Template (Target: 3 minutes)
Section titled “Drill 5: Dry Run and Template (Target: 3 minutes)”# See what would be created without creatinghelm install dry-test bitnami/nginx --dry-run
# Generate YAML only (for inspection or GitOps)helm template my-nginx bitnami/nginx > nginx-manifests.yamlcat nginx-manifests.yaml | head -100
# Validate YAMLkubectl apply -f nginx-manifests.yaml --dry-run=client
# Cleanuprm nginx-manifests.yamlDrill 6: Multi-Release Management (Target: 5 minutes)
Section titled “Drill 6: Multi-Release Management (Target: 5 minutes)”# Install multiple releaseshelm install prod-web bitnami/nginx --set replicaCount=3 -n production --create-namespacehelm install dev-web bitnami/nginx --set replicaCount=1 -n development --create-namespacehelm install staging-web bitnami/nginx --set replicaCount=2 -n staging --create-namespace
# List all releases across namespaceshelm list -A
# Get status of specific releasehelm status prod-web -n production
# Cleanup allhelm uninstall prod-web -n productionhelm uninstall dev-web -n developmenthelm uninstall staging-web -n stagingkubectl delete ns production development stagingDrill 7: Challenge - Install Without Documentation
Section titled “Drill 7: Challenge - Install Without Documentation”Without looking at docs, complete this task:
Task: Install PostgreSQL with:
- Database name: myapp
- Username: appuser
- Password: secret123
- Storage: 5Gi
# Hint: Use helm show values to find the right parametershelm show values bitnami/postgresql | grep -A5 -i "auth\|primary\|persistence"Solution
helm install mydb bitnami/postgresql \ --set auth.database=myapp \ --set auth.username=appuser \ --set auth.password=secret123 \ --set primary.persistence.size=5Gi
# Verifykubectl get podskubectl get pvc
# Cleanuphelm uninstall mydbNext Module
Section titled “Next Module”Module 1.4: Kustomize - Configuration management without templates, Kubernetes-native customization.