Master Kubernetes the Easy Way: Introduction to Helm for Beginners
Why Every DevOps Engineer Must Learn Helm
📘 Helm for Kubernetes – Course Syllabus
Course Overview
Helm is the package manager for Kubernetes. It simplifies deploying, upgrading, and managing complex applications on Kubernetes. This course provides a hands-on, structured learning path — starting from basics, then moving to chart creation, customization, best practices, and real-world deployments in Azure AKS.
Learning Objectives
By the end of this course, students will be able to:
✅ Understand what Helm is and why it is used in Kubernetes.
✅ Install and configure Helm in different environments.
✅ Explore the structure of Helm charts and how they work.
✅ Create custom Helm charts from scratch.
✅ Manage releases: install, upgrade, rollback, and uninstall.
✅ Customize charts for Dev, Staging, and Production environments.
✅ Apply best practices for Helm chart development.
✅ Use Helm advanced templating functions for dynamic manifests.
✅ Deploy real-world projects in Kubernetes using Helm.
✅ Integrate Helm with CI/CD pipelines and GitOps tools.
Target Audience
DevOps Engineers
Cloud Administrators
Developers working with Kubernetes
Students preparing for Cloud & DevOps interviews
Prerequisites
Basic understanding of Kubernetes (pods, deployments, services).
Familiarity with YAML.
Access to a Kubernetes cluster (e.g., Minikube, Kind, or Azure AKS).
Course Modules
Module 1: Introduction to Helm
What is Helm?
Why use Helm in Kubernetes?
Helm vs Kubernetes manifests
Key concepts: Chart, Values, Release, Repository
Hands-on: Deploy Nginx using a Helm chart
Module 2: Installing & Configuring Helm
Installing Helm on Linux, Windows, macOS
Setting up Helm in Azure Cloud Shell
Adding and updating repositories
Verifying Helm installation
Hands-on: Install Bitnami Nginx chart
Module 3: Exploring Helm Chart Structure
Anatomy of a chart:
Chart.yaml
,values.yaml
,templates/
,_helpers.tpl
Understanding templating basics (
{{ .Values }}
)Editing default chart values
Hands-on: Create a chart and explore its files
Module 4: Creating Your First Helm Chart
Helm create command
Writing
deployment.yaml
with valuesWriting
service.yaml
with valuesAdding dependencies (MySQL, Redis)
Hands-on: Create a chart for Nginx + MySQL
Module 5: Deploying & Managing Releases
Installing a release
Upgrading a release (new values, new image tag)
Rolling back to previous version
Managing releases across namespaces
Hands-on: Multiple releases for Dev/Prod
Module 6: Customizing Helm Charts
Using
values-dev.yaml
,values-prod.yaml
Overriding values from CLI (
--set
,-f
)Secrets and ConfigMaps with Helm
Ingress rules per environment
Autoscaling with Helm charts
Hands-on: Deploy app with different configs in Dev/Prod
Module 7: Best Practices for Helm Development
Chart linting (
helm lint
)Validating charts with
kubectl dry-run
Using dependencies properly
Unit testing Helm charts (
helm unittest
)RBAC & Security for Helm
Hands-on: Secure chart with RBAC + test configs
Module 8: Advanced Templating
Loops (
range
) for multiple resourcesConditionals (
if/else
) for optional resourcesPipelines (
upper
,default
) for transformationsHelpers (
_helpers.tpl
) for reusabilityCombining loops + conditionals
Hands-on: Build dynamic configs with templates
Module 9: Real-World Project in Azure
Setting up AKS cluster
Creating namespaces for Dev, Staging, Prod
Deploying API + MySQL with Helm
Managing upgrades, rollbacks, scaling
Integrating Helm with CI/CD (Azure DevOps, GitHub Actions)
Hands-on: End-to-end deployment project
Module 10: Wrap-Up & Advanced Practices
GitOps with Helm (ArgoCD, Flux)
Helm repository management
Security & compliance best practices
CI/CD pipelines with Helm
Final project: Deploy full microservice app with Helm in Azure
Course Deliverables
Lecture slides (concepts + architecture diagrams)
Hands-on labs (Helm exercises in AKS/Minikube)
Cheat sheet (Helm commands, templates, values)
Capstone project (deploy a real-world microservice app in Azure using Helm)
Assessment
Chapter-wise exercises (10 per chapter → 100 total).
Mini-project: Create and deploy a custom Helm chart.
Final project: End-to-end multi-environment deployment with Helm in Azure.
Helm Chart Tutorial: Step-by-Step with Real Examples
(Azure Lab Setup + Hands-On)
Chapter 1: Setting Up the Lab Environment in Azure Cloud
Before we dive into Helm, we need a Kubernetes cluster + environment in Azure. Helm works on top of Kubernetes, so our lab setup is critical.
Step 1: Create Resource Group in Azure
Resource groups organize your resources.
az group create --name helm-lab-rg --location eastus
Step 2: Create Azure Kubernetes Service (AKS) Cluster
We’ll provision a small AKS cluster (3 nodes, Standard_B2s VM size).
az aks create \
--resource-group helm-lab-rg \
--name helmLabCluster \
--node-count 3 \
--node-vm-size Standard_B2s \
--generate-ssh-keys
Step 3: Connect kubectl to AKS
az aks get-credentials --resource-group helm-lab-rg --name helmLabCluster
Verify cluster is running:
kubectl get nodes
✅ You should see 3 nodes in Ready status.
Step 4: Install Helm on Your Machine
On your local machine (Cloud Shell or local terminal):
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Verify installation:
helm version
✅ You should see something like version.BuildInfo{Version:”v3.14.0” ...}
Step 5: Verify Helm with Kubernetes
Test Helm’s connection with the cluster.
kubectl create ns helm-test
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install my-nginx bitnami/nginx --namespace helm-test
Check pods:
kubectl get pods -n helm-test
✅ Nginx pod should be running.
Example Config Files for Lab Setup
Azure CLI Config (resource group + cluster)
# aks-config.yaml
resourceGroup: helm-lab-rg
clusterName: helmLabCluster
nodeCount: 3
nodeSize: Standard_B2s
location: eastus
Sample Helm Values Override for Nginx
# nginx-values.yaml
service:
type: LoadBalancer
port: 80
replicaCount: 2
Run:
helm upgrade my-nginx bitnami/nginx -f nginx-values.yaml -n helm-test
✅ What You Achieved
AKS cluster created in Azure
Helm installed & connected
First Helm deployment (Bitnami Nginx)
Chapter 2: What Is Helm and Why Use It?
🔹 What Is Helm?
Helm is a package manager for Kubernetes — think of it like apt/yum for Linux or pip for Python.
A Helm chart = a package that defines a Kubernetes application.
A release = an instance of that chart running in your cluster.
Helm makes Kubernetes deployments repeatable, versioned, and manageable.
🔹 Why Use Helm?
Simplifies Complex Deployments – Instead of writing 10 YAML files for an app, you just install a chart.
Reusable & Versioned – Same chart can be reused across environments (dev, staging, prod).
Customization via Values – Override settings (replicas, images, ports) without touching YAML.
Rollback Easily – If something breaks, one command restores the previous version.
Ecosystem of Prebuilt Charts – Thousands of ready-to-use charts exist (e.g., MySQL, Redis, Nginx).
✅ 5 Real-World Examples of Helm in Action
Example 1: Deploying Nginx
Without Helm → You need 3 YAML files (Deployment, Service, ConfigMap).
With Helm → Just one command:
helm install my-nginx bitnami/nginx
Customize with values:
# nginx-values.yaml
service:
type: LoadBalancer
replicaCount: 3
Apply:
helm upgrade my-nginx bitnami/nginx -f nginx-values.yaml
Example 2: Installing MySQL Database
Instead of writing StatefulSets, PVs, PVCs manually:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install my-mysql bitnami/mysql
Override values:
# mysql-values.yaml
auth:
rootPassword: mysecurepassword
database: myappdb
primary:
persistence:
size: 10Gi
Upgrade with:
helm upgrade my-mysql bitnami/mysql -f mysql-values.yaml
Example 3: Multi-Environment Deployment
You can use different values files for dev/staging/prod.
# values-dev.yaml
replicaCount: 1
resources:
requests:
cpu: 200m
memory: 256Mi
# values-prod.yaml
replicaCount: 5
resources:
requests:
cpu: 500m
memory: 1Gi
Deploy to environments:
helm upgrade myapp ./mychart -f values-dev.yaml # dev
helm upgrade myapp ./mychart -f values-prod.yaml # prod
Example 4: Rollback to Previous Release
Suppose you upgrade your app and it breaks.
helm history my-nginx
helm rollback my-nginx 1
✅ Instantly returns to version 1
.
Example 5: Continuous Delivery with Helm
Integrate Helm into CI/CD pipelines.
For example, in GitHub Actions:
- name: Deploy with Helm
run: |
helm upgrade myapp ./mychart \
--install \
--namespace production \
-f values-prod.yaml
✅ Every commit automatically upgrades your app in Kubernetes.
🔑 Key Takeaways
Helm = package manager for Kubernetes apps.
Charts make complex apps simple.
Easy to install, upgrade, rollback, and customize.
Works perfectly for multi-environment setups.
Can be integrated into CI/CD pipelines.
Chapter 3: Installing & Configuring Helm
🔹 Step 1: Install Helm (Different Environments)
Example 1: Install Helm on Linux (Ubuntu/Debian)
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Verify:
helm version
Example 2: Install Helm on Windows (PowerShell + Chocolatey)
choco install kubernetes-helm
Verify:
helm version
Example 3: Install Helm on macOS (Homebrew)
brew install helm
Verify:
helm version
Example 4: Install Helm in Azure Cloud Shell
Azure Cloud Shell already has kubectl
. Just install Helm:
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Check version:
helm version
Example 5: Install Helm on a GitHub Actions Runner (CI/CD)
In .github/workflows/deploy.yaml
:
- name: Install Helm
run: |
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm version
🔹 Step 2: Add Helm Repositories
Repositories are like “app stores” for Helm.
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
Check:
helm search repo nginx
🔹 Step 3: Configure Helm for Your Cluster
Make sure Helm can talk to Kubernetes.
kubectl config current-context
helm list -A
✅ If this works, Helm is connected to AKS.
🔹 Step 4: Install a Test App (Nginx)
helm install my-nginx bitnami/nginx --namespace helm-lab --create-namespace
Check pods:
kubectl get pods -n helm-lab
🔹 Step 5: Verify & Manage Configurations
Helm stores configs in releases.
Check what’s installed:
helm list -n helm-lab
Inspect values:
helm get values my-nginx -n helm-lab
Upgrade values:
helm upgrade my-nginx bitnami/nginx -n helm-lab --set replicaCount=3
Rollback:
helm rollback my-nginx 1 -n helm-lab
✅ What You Achieved
Installed Helm on Linux, Windows, macOS, Cloud Shell, GitHub Actions
Configured Helm repositories
Verified Helm-Kubernetes connection
Deployed & managed your first Helm app
Chapter 4: Exploring the Structure of a Helm Chart
🔹 What Is a Helm Chart?
A Helm chart is basically a directory with files that describe how to deploy an application on Kubernetes.
When you run helm create mychart
, Helm scaffolds a default chart with this structure:
mychart/
│── Chart.yaml
│── values.yaml
│── charts/
│── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── _helpers.tpl
│ └── ingress.yaml
🔹 Key Files & Folders
Chart.yaml → Metadata (name, version, description, maintainers)
values.yaml → Default configuration values (replicas, image, service type)
charts/ → Dependency charts (e.g., MySQL for WordPress)
templates/ → Kubernetes manifests with Go templating (
{{ }}
syntax)_helpers.tpl → Reusable template helpers
✅ 5 Examples of Helm Chart Structure
Example 1: Chart.yaml (Metadata File)
apiVersion: v2
name: my-nginx
description: A Helm chart for deploying Nginx
type: application
version: 0.1.0
appVersion: “1.23.0”
maintainers:
- name: Bavi
email: bavi@example.com
👉 This tells Helm what the chart is, versioning info, and who maintains it.
Example 2: values.yaml (Configuration Defaults)
replicaCount: 2
image:
repository: nginx
tag: “1.23.0”
pullPolicy: IfNotPresent
service:
type: LoadBalancer
port: 80
👉 Instead of hardcoding values in templates, you define them here.
This makes your chart reusable across environments.
Example 3: templates/deployment.yaml (Application Deployment)
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-deployment
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ .Release.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: “{{ .Values.image.repository }}:{{ .Values.image.tag }}”
ports:
- containerPort: {{ .Values.service.port }}
👉 Notice {{ .Values... }}
→ this injects data from values.yaml
.
Example 4: templates/service.yaml (Expose Application)
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-service
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.port }}
selector:
app: {{ .Release.Name }}
👉 Service type (ClusterIP, NodePort, LoadBalancer) is driven by values.yaml
.
Example 5: _helpers.tpl (Reusable Functions)
{{/*
Return the full name of the app
*/}}
{{- define “my-nginx.fullname” -}}
{{ .Release.Name }}-{{ .Chart.Name }}
{{- end }}
👉 Reusable snippets prevent duplication across templates.
🔹 Running a Custom Chart
Let’s generate and test our first custom chart:
helm create my-nginx
cd my-nginx
Deploy:
helm install test-nginx ./my-nginx
Check:
kubectl get all
Upgrade replicas:
helm upgrade test-nginx ./my-nginx --set replicaCount=3
✅ What You Learned
Chart.yaml → metadata
values.yaml → configurable defaults
templates/ → Kubernetes YAML with templating
charts/ → dependencies
_helpers.tpl → reusable helpers
How Helm injects values dynamically into Kubernetes manifests
Chapter 5: Creating Your First Helm Chart
🔹 Step 1: Scaffold a New Chart
Helm provides a create
command to generate boilerplate:
helm create myapp
cd myapp
This creates the chart structure we saw in Chapter 4.
🔹 Step 2: Understand the Default Files
Inside myapp/
:
Chart.yaml
→ chart metadatavalues.yaml
→ default valuestemplates/
→ Kubernetes manifests (Deployment, Service, Ingress)
🔹 Step 3: Customize Your Chart
We’ll now go through 5 examples, each one more advanced.
Example 1: Nginx Chart
Edit
values.yaml
:
replicaCount: 2
image:
repository: nginx
tag: “1.23.0”
service:
type: LoadBalancer
port: 80
Install:
helm install nginx-release ./myapp
Verify:
kubectl get pods,svc
✅ Nginx service exposed via LoadBalancer.
Example 2: Redis Chart
Change
values.yaml
:
image:
repository: redis
tag: “7.0”
service:
type: ClusterIP
port: 6379
Install:
helm install redis-release ./myapp
Verify:
kubectl get pods
kubectl exec -it <redis-pod> -- redis-cli ping
✅ Should return PONG.
Example 3: MySQL Chart
Update
values.yaml
:
image:
repository: mysql
tag: “8.0”
service:
type: ClusterIP
port: 3306
mysqlRootPassword: mysecurepassword
mysqlDatabase: appdb
Add environment variables in
templates/deployment.yaml
:
env:
- name: MYSQL_ROOT_PASSWORD
value: {{ .Values.mysqlRootPassword | quote }}
- name: MYSQL_DATABASE
value: {{ .Values.mysqlDatabase | quote }}
Install:
helm install mysql-release ./myapp
✅ MySQL ready with appdb
.
Example 4: WordPress with Dependency (MySQL)
Edit
Chart.yaml
:
dependencies:
- name: mysql
version: 9.4.0
repository: “https://charts.bitnami.com/bitnami”
Run:
helm dependency update
Update
values.yaml
:
wordpressUsername: admin
wordpressPassword: admin123
service:
type: LoadBalancer
Install:
helm install wordpress-release ./myapp
✅ WordPress + MySQL deployed together.
Example 5: Custom Microservice (Node.js API)
Suppose you have a Docker image: bavi/my-api:1.0.0
.
Edit
values.yaml
:
replicaCount: 3
image:
repository: bavi/my-api
tag: “1.0.0”
service:
type: ClusterIP
port: 8080
Update
templates/deployment.yaml
:
containers:
- name: {{ .Chart.Name }}
image: “{{ .Values.image.repository }}:{{ .Values.image.tag }}”
ports:
- containerPort: {{ .Values.service.port }}
Install:
helm install api-release ./myapp
✅ Your Node.js API is running inside AKS.
🔹 Step 4: Upgrade & Rollback
Upgrade image version:
helm upgrade api-release ./myapp --set image.tag=1.0.1
Rollback if failed:
helm rollback api-release 1
🔹 Step 5: Uninstall
helm uninstall nginx-release
helm uninstall redis-release
✅ What You Achieved
Created a Helm chart (
helm create
)Customized values for 5 real apps: Nginx, Redis, MySQL, WordPress, Node.js API
Used dependencies (WordPress + MySQL)
Performed upgrade/rollback lifecycle
Chapter 6: Deploying and Managing Releases
🔹 What Is a Helm Release?
A release = one instance of a chart running in your cluster.
You can install the same chart multiple times under different release names.
Each release is tracked, versioned, and upgradeable.
✅ 5 Real-World Examples
Example 1: Installing Multiple Releases of the Same Chart
Let’s install two Nginx instances with different configs.
helm install nginx-dev ./myapp --set replicaCount=1
helm install nginx-prod ./myapp --set replicaCount=5
Check:
helm list -A
👉 You’ll see both nginx-dev
and nginx-prod
releases.
Example 2: Managing Releases Across Namespaces
Releases can live in separate namespaces.
kubectl create namespace dev
kubectl create namespace prod
helm install api-dev ./myapp -n dev
helm install api-prod ./myapp -n prod
Check:
helm list -n dev
helm list -n prod
👉 Same chart, but deployed to different namespaces.
Example 3: Upgrading a Release (New Image Version)
Suppose you release a new API version (1.0.1
).
helm upgrade api-prod ./myapp -n prod --set image.tag=1.0.1
Check rollout:
kubectl rollout status deployment/api-prod-deployment -n prod
👉 Production updated with zero downtime.
Example 4: Rollback to Previous Release
Something broke in 1.0.1
? Roll back instantly.
helm history api-prod -n prod
helm rollback api-prod 1 -n prod
👉 Restores the first version of the release.
Example 5: Managing Release Versions
Helm tracks release history. You can inspect:
helm history nginx-prod -n prod
Shows revision numbers, chart version, app version, status.
Delete a release:
helm uninstall nginx-prod -n prod
👉 Removes resources from cluster but keeps history (unless --keep-history=false
).
🔹 Extra: Lifecycle Workflow in Enterprises
Install → Dev environment (
helm install
)Upgrade → QA/Stage (
helm upgrade --reuse-values
)Promote to Prod → (
helm upgrade -f values-prod.yaml
)Rollback if needed → (
helm rollback
)Cleanup old releases → (
helm uninstall
)
✅ What You Achieved
Installed multiple releases of the same chart
Deployed across namespaces (dev/prod)
Upgraded to new versions
Rolled back failed updates
Managed release history & lifecycle
Chapter 7: Customizing Helm Charts for Different Environments
🔹 Why Customize?
Different environments have different needs:
Dev → minimal replicas, smaller resource requests.
Staging → near-production replica counts, but not full scale.
Prod → high availability, monitoring, scaling enabled.
Helm lets you separate logic (templates) from configuration (values.yaml).
✅ 5 Real-World Examples
Example 1: Dev vs Prod Values
Two separate values files:
values-dev.yaml
replicaCount: 1
image:
repository: bavi/my-api
tag: “dev”
resources:
requests:
cpu: 100m
memory: 128Mi
values-prod.yaml
replicaCount: 5
image:
repository: bavi/my-api
tag: “stable”
resources:
requests:
cpu: 500m
memory: 1Gi
Deploy:
helm upgrade api ./myapp -f values-dev.yaml -n dev
helm upgrade api ./myapp -f values-prod.yaml -n prod
👉 Same chart, two very different environments.
Example 2: Secrets Management
Use Helm to inject secrets securely.
values.yaml
secret:
dbPassword: “mySuperSecret123”
templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: {{ .Release.Name }}-db-secret
type: Opaque
data:
password: {{ .Values.secret.dbPassword | b64enc | quote }}
👉 Different environments can have different DB passwords without touching templates.
Example 3: Autoscaling Configuration
Enable HPA (Horizontal Pod Autoscaler) in Prod only.
values-prod.yaml
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
cpuTargetPercentage: 75
templates/hpa.yaml
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ .Release.Name }}-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ .Release.Name }}-deployment
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.cpuTargetPercentage }}
{{- end }}
👉 HPA deployed only in production.
Example 4: Ingress Customization
Different environments need different ingress domains.
values-dev.yaml
ingress:
enabled: true
hostname: dev.myapp.com
values-prod.yaml
ingress:
enabled: true
hostname: myapp.com
templates/ingress.yaml
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ .Release.Name }}-ingress
spec:
rules:
- host: {{ .Values.ingress.hostname }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ .Release.Name }}-service
port:
number: {{ .Values.service.port }}
{{- end }}
👉 Automatically switches hostname per environment.
Example 5: Feature Flags per Environment
Enable/disable app features with Helm.
values.yaml
features:
enableDebug: false
templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-config
data:
ENABLE_DEBUG: “{{ .Values.features.enableDebug }}”
Deploy in Dev:
helm upgrade myapp ./myapp --set features.enableDebug=true -n dev
👉 Debugging enabled in Dev, disabled in Prod.
🔹 Best Practices for Environment Customization
Use separate values files (
values-dev.yaml
,values-staging.yaml
,values-prod.yaml
).Never hardcode secrets → use
b64enc
or external secret managers.Use conditionals (
if
) in templates for environment-specific resources.Keep
values.yaml
as base config, override with env-specific files.
✅ What You Achieved
Learned how to customize Helm charts per environment
Used values overrides, secrets, HPA, ingress, and feature flags
Built charts that adapt automatically to Dev/Staging/Prod
Chapter 8: Best Practices for Helm Chart Development
🔹 Why Best Practices Matter
Prevent chart drift across environments.
Ensure charts are reusable and maintainable.
Catch errors early with linting & testing.
Integrate into DevOps pipelines.
Improve security and compliance.
✅ 5 Best Practices with Examples
Example 1: Linting and Validating Charts
Before deploying, always validate your charts.
helm lint ./myapp
👉 Catches syntax errors, missing fields, bad references.
For stricter validation, render manifests and validate with kubectl
:
helm template ./myapp | kubectl apply --dry-run=client -f -
✅ Ensures manifests are valid before applying.
Example 2: Dependency Management
Use requirements.yaml
(Helm v2) or Chart.yaml
(Helm v3) for dependencies.
Chart.yaml
dependencies:
- name: mysql
version: 9.4.0
repository: “https://charts.bitnami.com/bitnami”
- name: redis
version: 17.3.0
repository: “https://charts.bitnami.com/bitnami”
Update dependencies:
helm dependency update
👉 This ensures your chart is portable and includes subcharts.
Example 3: Testing Charts with Helm Unittest
Install plugin:
helm plugin install https://github.com/quintush/helm-unittest
Create a test in tests/deployment_test.yaml
:
suite: test deployment
templates:
- deployment.yaml
tests:
- it: should set correct replica count
set:
replicaCount: 3
asserts:
- equal:
path: spec.replicas
value: 3
Run:
helm unittest ./myapp
✅ Ensures templates behave as expected.
Example 4: GitOps Workflow with ArgoCD/Flux
Instead of helm install
manually, use GitOps:
values-prod.yaml stored in Git repo.
ArgoCD watches repo and applies automatically:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
spec:
project: default
source:
repoURL: https://github.com/bavi/helm-charts
path: myapp
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: prod
syncPolicy:
automated:
prune: true
selfHeal: true
👉 Every Git commit = automatic Helm deployment.
Example 5: Security & RBAC
Limit Helm’s permissions with RBAC.
rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: helm-service-account
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: helm-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: helm-service-account
namespace: kube-system
Install Helm with service account:
helm install myapp ./myapp --service-account helm-service-account -n prod
👉 Ensures Helm runs with least-privilege access.
🔹 Extra Tips
Use semantic versioning (
0.1.0
,1.0.0
) for charts.Keep default values minimal → override in env files.
Document your chart (
README.md
with examples).Always store charts in a Helm repository (e.g., GitHub Pages, Azure Container Registry, JFrog).
✅ What You Achieved
Learned linting, dependency management, unit testing, GitOps, and RBAC security.
Built charts that are production-ready.
Ensured deployments are safe, testable, and automated.
Chapter 9: Helm Advanced Templating
🔹 Why Advanced Templating?
Avoid duplication → generate 10 services from a list with a loop.
Conditional logic → deploy Ingress only in Prod.
Pipelines → transform values before rendering.
Functions → manipulate strings, numbers, and YAML data.
✅ 5 Real-World Templating Examples
Example 1: Loops – Generate Multiple Config Entries
Suppose you want multiple environment variables for your app.
values.yaml
env:
- name: DB_HOST
value: mysql-service
- name: CACHE_HOST
value: redis-service
- name: LOG_LEVEL
value: DEBUG
templates/deployment.yaml
env:
{{- range .Values.env }}
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}
👉 Renders multiple environment variables dynamically.
Example 2: Conditionals (if/else)
Enable Ingress only when ingress.enabled=true
.
values.yaml
ingress:
enabled: true
host: myapp.com
templates/ingress.yaml
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ .Release.Name }}-ingress
spec:
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ .Release.Name }}-service
port:
number: {{ .Values.service.port }}
{{- end }}
👉 If enabled=false
, no Ingress gets created.
Example 3: Pipelines (Transform Values)
Use Helm’s built-in functions.
values.yaml
username: admin
templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-config
data:
USERNAME_UPPER: {{ .Values.username | upper | quote }}
👉 Renders “ADMIN”
instead of “admin”
.
Example 4: Using Default Values
Set a fallback value if none is provided.
templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-config
data:
DB_HOST: {{ default “localhost” .Values.db.host | quote }}
👉 If db.host
not set in values, defaults to “localhost”
.
Example 5: Including & Reusing Templates
Use _helpers.tpl
to avoid duplication.
_helpers.tpl
{{- define “myapp.fullname” -}}
{{ .Release.Name }}-{{ .Chart.Name }}
{{- end }}
templates/deployment.yaml
metadata:
name: {{ include “myapp.fullname” . }}
👉 Reuses template logic across multiple files.
🔹 Bonus: Combining Loops + Conditionals
values.yaml
extraServices:
- name: metrics
port: 8080
enabled: true
- name: debug
port: 9090
enabled: false
templates/services.yaml
{{- range .Values.extraServices }}
{{- if .enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ .name }}
spec:
ports:
- port: {{ .port }}
selector:
app: {{ $.Release.Name }}
---
{{- end }}
{{- end }}
👉 Generates multiple services only for those marked as enabled: true
.
✅ What You Achieved
Used loops to generate repeated config.
Added if/else conditionals for selective resources.
Applied pipelines and functions (uppercase, default).
Reused templates with helpers.
Built dynamic manifests that adapt to environment needs.
Chapter 10: Conclusion & Real-World Project Setup in Azure
🔹 Step 1: Project Structure
Let’s build a sample microservice app (API + DB) with Helm.
helm-lab/
│── api-chart/
│ │── Chart.yaml
│ │── values.yaml
│ │── templates/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ ├── ingress.yaml
│ │ └── _helpers.tpl
│── values-dev.yaml
│── values-staging.yaml
│── values-prod.yaml
🔹 Step 2: Chart.yaml
apiVersion: v2
name: api-chart
description: A simple Node.js API with MySQL backend
type: application
version: 0.1.0
appVersion: “1.0.0”
dependencies:
- name: mysql
version: 9.4.0
repository: “https://charts.bitnami.com/bitnami”
👉 This chart depends on MySQL.
🔹 Step 3: values.yaml (Base)
replicaCount: 2
image:
repository: bavi/node-api
tag: “1.0.0”
service:
type: ClusterIP
port: 8080
ingress:
enabled: true
hostname: api.local
mysql:
auth:
rootPassword: root123
database: apidb
🔹 Step 4: Environment-Specific Values
values-dev.yaml
replicaCount: 1
image:
tag: “dev”
mysql:
auth:
rootPassword: devpass
values-staging.yaml
replicaCount: 2
image:
tag: “staging”
mysql:
auth:
rootPassword: stagepass
values-prod.yaml
replicaCount: 5
image:
tag: “stable”
mysql:
auth:
rootPassword: prodpass
🔹 Step 5: Deployment Template
templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include “api-chart.fullname” . }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ include “api-chart.name” . }}
template:
metadata:
labels:
app: {{ include “api-chart.name” . }}
spec:
containers:
- name: api
image: “{{ .Values.image.repository }}:{{ .Values.image.tag }}”
ports:
- containerPort: {{ .Values.service.port }}
env:
- name: DB_HOST
value: “{{ .Release.Name }}-mysql”
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-mysql
key: mysql-root-password
🔹 Step 6: Deploy into Azure AKS
Make sure AKS is set up (from Chapter 1).
Deploy Dev environment:
helm install api-dev ./api-chart -f values-dev.yaml -n dev --create-namespace
Deploy Staging:
helm install api-staging ./api-chart -f values-staging.yaml -n staging --create-namespace
Deploy Prod:
helm install api-prod ./api-chart -f values-prod.yaml -n prod --create-namespace
Check:
helm list -A
kubectl get pods -n prod
🔹 Step 7: Upgrade Workflow
Update to new version (e.g., 1.0.1
):
helm upgrade api-prod ./api-chart -f values-prod.yaml --set image.tag=1.0.1 -n prod
Rollback if issues:
helm rollback api-prod 1 -n prod
🔹 Step 8: Integrate into CI/CD (Azure DevOps or GitHub Actions)
Example GitHub Actions snippet:
- name: Deploy to AKS with Helm
run: |
helm upgrade api-prod ./api-chart \
-f values-prod.yaml \
--install \
-n prod
👉 Ensures every commit can roll out to AKS.
✅ What You Achieved in the Series
Setup Azure AKS cluster for Helm.
Learned Helm basics → charts, releases, repos.
Explored chart structure.
Built & customized charts with Nginx, Redis, MySQL, WordPress, Node.js API.
Managed deployments, rollbacks, multi-env values.
Used advanced templating (loops, if/else, pipelines).
Followed best practices (linting, testing, RBAC, GitOps).
Deployed a real-world project to Azure AKS.
Final Note:
Helm is not just a tool, it’s the glue between Kubernetes and DevOps automation. Mastering Helm gives you production-ready, versioned, and repeatable deployments.
Helm Learning Exercises
Chapter 1: Setting Up the Lab Environment in Azure Cloud
Create a new resource group in a different Azure region.
Deploy an AKS cluster with 1 node, then scale it to 3 nodes.
Create a namespace
helm-lab
and deploy a test Pod (nginx
).Configure
kubectl
to connect to your AKS cluster.Verify Kubernetes API server is reachable (
kubectl cluster-info
).Install Helm on Azure Cloud Shell.
Install Helm on your local machine.
Deploy a Helm chart (Nginx) into a new namespace
test
.Delete the namespace and verify Helm release is removed.
Enable Azure Monitor on your AKS cluster.
Chapter 2: What Is Helm and Why Use It?
List all Helm repositories available in your setup.
Search for the
mysql
chart in Bitnami repo.Install two instances of
nginx
using different release names.Override default replica count at install time with
--set
.List Helm releases across all namespaces.
Upgrade
nginx
release with a new replica count.Rollback
nginx
release to its first version.Delete Helm release but keep history (
--keep-history
).Export rendered manifests with
helm template
.Compare Helm vs. plain YAML (install nginx both ways).
Chapter 3: Installing & Configuring Helm
Install Helm on Linux.
Install Helm on Windows (PowerShell).
Install Helm on macOS (Homebrew).
Add the Bitnami repo and update it.
Search for the
wordpress
chart.Install
wordpress
in namespaceweb
.Verify Helm installation using
helm version
.Run
helm repo list
and document repos.Configure Helm on GitHub Actions runner.
Use
helm list -A
to check all releases.
Chapter 4: Exploring the Structure of a Helm Chart
Run
helm create mychart
and explore folder structure.Edit
Chart.yaml
→ change appVersion to“2.0.0”
.Edit
values.yaml
→ change service type toNodePort
.Modify
deployment.yaml
→ change image tonginx
.Add a ConfigMap in
templates/
.Add a helper template
_helpers.tpl
for app name.Render chart using
helm template
.Install the chart with release name
myapp
.Upgrade release with new values.
Delete release and namespace.
Chapter 5: Creating Your First Helm Chart
Create a new Helm chart for Redis.
Deploy Redis with 1 replica.
Upgrade Redis to 3 replicas.
Create Helm chart for MySQL with DB password.
Create Helm chart for WordPress with MySQL dependency.
Build custom chart for Node.js API.
Deploy Node.js API with
LoadBalancer
.Rollback Node.js API deployment.
Add dependency (Redis) to Node.js chart.
Document your custom chart with
README.md
.
Chapter 6: Deploying and Managing Releases
Install two releases of
nginx
(nginx-dev
,nginx-prod
).Deploy release in different namespaces.
List all releases in
prod
namespace.Upgrade
nginx-prod
with new image version.Rollback
nginx-prod
to previous revision.Delete
nginx-dev
release.Use
helm history
to check versions.Deploy release with custom values file.
Export manifests of release.
Automate
helm upgrade
in a shell script.
Chapter 7: Customizing Helm Charts
Create
values-dev.yaml
andvalues-prod.yaml
.Deploy chart with
values-dev.yaml
.Deploy chart with
values-prod.yaml
.Add environment variables via
values.yaml
.Create secrets using
b64enc
.Enable HPA only in Prod with conditional.
Create ingress rule for Dev (dev.myapp.com).
Create ingress rule for Prod (myapp.com).
Add a feature flag (debug mode).
Deploy chart in both Dev & Prod, compare manifests.
Chapter 8: Best Practices
Run
helm lint
on your chart.Validate chart with
kubectl apply --dry-run=client
.Add Redis dependency in
Chart.yaml
.Run
helm dependency update
.Write a unittest for
replicaCount
.Run Helm unittest plugin.
Configure RBAC for Helm with a service account.
Install Helm release with service account.
Integrate chart into ArgoCD.
Write a
README.md
with installation steps.
Chapter 9: Advanced Templating
Use a loop to create multiple env vars.
Use an
if
conditional for ingress.Use pipeline to uppercase a value.
Use pipeline to set a default DB host.
Create helper template in
_helpers.tpl
.Reuse helper template in Deployment & Service.
Loop through multiple service ports.
Conditionally enable metrics service.
Nest loop inside condition.
Render chart and verify YAML output.
Chapter 10: Real-World Project in Azure
Create namespace
dev
,staging
,prod
.Deploy API chart with
values-dev.yaml
.Deploy API chart with
values-staging.yaml
.Deploy API chart with
values-prod.yaml
.Upgrade Prod API image to
1.0.1
.Rollback Prod API to version 1.
Expose API via Azure LoadBalancer ingress.
Configure Helm in GitHub Actions CI/CD.
Deploy chart automatically via pipeline.
Document project architecture with diagrams.