If you deploy even a slightly complex application (say a microservice + MySQL + Redis + Nginx), you’ll end up with so many YAML files you start doubting the meaning of life. And the configuration differs from environment to environment (development, testing, production) — surely you’re not going to maintain three sets of YAML? Helm exists precisely to solve this pain — it’s called “the apt/yum of K8s”.
1. What Problem Does Helm Solve?
Let’s start with an everyday scenario, one without Helm.
You want to deploy an application, and you need to write:
- A Deployment YAML (the application itself)
- A Service YAML (to expose ports)
- A ConfigMap YAML (configuration)
- A PVC YAML (storage)
- Possibly Ingress, Secret, HPA as well……
One set for development, one for testing, one for production. Across three environments that’s a dozen-plus YAML files alone. And the difference between environments may come down to just a few values (image tag, replica count, database address) — yet because YAML is static, you have no choice but to maintain several near-identical sets of files.
Helm does one thing: it turns YAML into templates. You write a single template (a Chart), inject different parameters through different values.yaml files, and generate the final YAML that fits each environment.
To understand it, draw an analogy with Linux:
| Linux | Kubernetes |
|---|---|
| Software package (deb/rpm) | Helm Chart |
| apt/yum | Helm CLI |
| Software source (/etc/apt/sources.list) | Helm Repository |
| Configuration file (/etc/nginx/nginx.conf) | values.yaml |
2. Helm 2 vs Helm 3 — A Massive Architectural Change
If you search the web for material on Helm, be careful to distinguish the versions — the architecture changed a great deal between Helm 2 and Helm 3.
The Helm 2 Architecture (Now Obsolete)
In Helm 2 there was a component called Tiller, which lived permanently inside the K8s cluster:
helm CLI → Tiller(在 K8s 集群内)→ API Server
Tiller was responsible for receiving helm commands and managing the installation, upgrade and rollback of Releases. But it had one fatal problem: Tiller held cluster-administrator-level privileges. That meant anyone able to call Tiller was able to do anything at all to the cluster. The security problem was extremely serious.
The Helm 3 Architecture (Now Recommended)
Helm 3 removed Tiller entirely:
helm CLI → API Server
The helm command line communicates with the API Server directly, and its privileges depend entirely on the kubeconfig configured locally by whoever runs it. However much kubectl privilege you have, that’s exactly how much helm has. Secure and simple.
In addition, Helm 3 deprecated Helm 2’s requirements.yaml, switching to declaring dependencies directly inside the Chart. For more detail you can consult the official migration guide.
3. Charts — Helm’s Application Packages
Helm’s package is called a Chart; it is a group of files with a fixed directory structure.
Chart Directory Structure
myapp/
├── Chart.yaml # Chart metadata
├── values.yaml # default configuration values
├── charts/ # dependent sub-Charts
├── templates/ # template files (the very core)
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── configmap.yaml
│ ├── _helpers.tpl # template helper functions
│ └── NOTES.txt # message shown after installation
└── .helmignore
Chart.yaml — the Chart’s “identity card”:
apiVersion: v2 # Helm 3 uses v2
name: myapp # Chart name
version: 1.0.0 # Chart version
appVersion: "2.1.0" # application version
description: My Application Chart
type: application
values.yaml — the default configuration values, supplying the defaults for the template variables:
replicaCount: 3
image:
repository: harbor.yourcompany.com/backend/myapp
tag: "2.1.0"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
targetPort: 8080
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
env:
DB_HOST: mysql-service
DB_PORT: "3306"
templates/ — the template files, which use Go template syntax (``) to reference values from values.yaml.
How Does a Chart Work?
The Helm workflow reduces to:
Chart (template)+ values.yaml (data) → render → standard K8s YAML → submit to API Server
You don’t write the YAML for Pod/Service/Deployment directly; you write their templates. When you run helm install, Helm combines the templates with the values, renders the final YAML, and submits it to K8s.
4. Building a Chart from Scratch
Suppose we have a Java application, myapp, that needs a Deployment + Service + ConfigMap.
Step 1: Create the Chart Skeleton
helm create myapp
This generates a set of default files; we delete the ones we don’t need (the defaults are Nginx templates) and keep the core structure.
Step 2: Write the Deployment Template
templates/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name:
labels:
app:
spec:
replicas:
selector:
matchLabels:
app:
template:
metadata:
labels:
app:
spec:
containers:
- name:
image: ":"
imagePullPolicy:
ports:
- containerPort:
env:
- name:
value:
resources:
Step 3: Write the Service Template
templates/service.yaml:
apiVersion: v1
kind: Service
metadata:
name:
spec:
type:
selector:
app:
ports:
- port:
targetPort:
Step 4: Write the ConfigMap Template
templates/configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: -config
data:
application.properties: |
server.port=
spring.datasource.url=jdbc:mysql://:/mydb
Step 5: Validate and Install
# validate the rendered result (without actually installing)
helm install --dry-run --debug myapp ./myapp
# actually install
helm install myapp ./myapp
# see what got installed
helm list
kubectl get all -l app=myapp
Multi-Environment Deployment
The same Chart adapts to different environments through different values files:
# development environment
helm install myapp-dev ./myapp -f values-dev.yaml
# production environment
helm install myapp-prod ./myapp -f values-prod.yaml
values-dev.yaml and values-prod.yaml only need to override the parts that differ from the defaults:
# values-prod.yaml
replicaCount: 10
image:
tag: "2.1.0"
resources:
requests:
memory: "1Gi"
cpu: "1000m"
limits:
memory: "2Gi"
cpu: "2000m"
5. Common Helm Operations
# list installed Releases
helm list
# view Release details
helm status myapp
helm get values myapp # view the values used at install time
helm get manifest myapp # view the full rendered YAML
# upgrade
helm upgrade myapp ./myapp -f values-prod.yaml
# rollback
helm rollback myapp 1 # roll back to revision 1
# view history
helm history myapp
# delete
helm uninstall myapp
# add a remote repository (Bitnami is currently the most widely used public Helm repository)
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# search for Charts in a repository
helm search repo nginx
# you can also search for and discover more Charts on Artifact Hub (artifacthub.io)
Template Syntax Quick Reference
Go template syntax is a little counter-intuitive; here are the most commonly used pieces:
| Syntax | Purpose | Example |
|---|---|---|
| Reference a value from values | |
||
| Reference the Release name | |
||
| Call a template defined in `_helpers.tpl` | |
||
| `` | Pipe + add quotes | version: |
| `` | Convert to YAML + indent | Used for complex objects |
| `` | Default value | Use 8080 if the port isn’t configured |
... |
Conditional rendering | Decide by a switch whether to generate a section |
6. Combining Helm with CI/CD
In a Jenkins Pipeline, Helm makes deployment extremely concise:
stage('Deploy to K8s') {
steps {
sh '''
helm upgrade --install myapp ./helm/myapp \
--namespace production \
--set image.tag=${BUILD_NUMBER} \
--wait \
--timeout 5m
'''
}
}
--wait waits until every Pod is ready before returning. --timeout stops it hanging forever.
Summary
Helm’s core value is turning K8s’s YAML from “static files” into “templatable packages”. It makes deployment as simple as apt install, and frees multi-environment management from maintaining a pile of duplicated YAML.
Write the Chart, configure the values, type one Helm command — deployment done. Next time, in the final article of this series, we’ll talk about the two most critical concepts in production deployment: health checks and rolling updates, so that deployment achieves genuinely zero downtime.
A small step forward every day is a new height!