Kubernetes YAML manifests are powerful, but managing dozens of files for each environment is a nightmare. Helm is the “package manager for Kubernetes” — it packages manifests into reusable charts with parameterization. Helm 2.x is the de facto standard for Kubernetes deployment in 2018.
Why Helm¶
Imagine a typical application: Deployment, Service, ConfigMap, Secret, Ingress, HorizontalPodAutoscaler. That’s 6 YAML files. For 3 environments (dev, staging, prod) with minor differences, that’s 18 files. With Helm, you have one chart and 3 values files.
- Parameterization — one template, different values per environment
- Versioning — each release has a version, you can rollback
- Dependencies — a chart can depend on other charts (PostgreSQL, Redis)
- Ecosystem — stable/ and incubator/ repositories with ready-made charts for Prometheus, Grafana, nginx-ingress, cert-manager
Anatomy of a Helm Chart¶
myapp/
├── Chart.yaml # Chart metadata (name, version, description)
├── values.yaml # Default values
├── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── _helpers.tpl # Reusable template snippets
│ └── NOTES.txt # Post-install instructions
├── charts/ # Sub-charts (dependencies)
└── requirements.yaml # Dependency declarations
Templates and Values¶
Helm uses the Go template engine. Values from values.yaml are interpolated into templates:
# values.yaml
replicaCount: 3
image:
repository: registry.company.com/myapp
tag: "1.4.2"
pullPolicy: IfNotPresent
resources:
limits:
cpu: 500m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
ingress:
enabled: true
host: api.company.com
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
labels:
{{- include "myapp.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "myapp.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "myapp.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
Working with Helm¶
# Install chart
$ helm install myapp ./myapp -f values-prod.yaml
# Upgrade with new values
$ helm upgrade myapp ./myapp --set image.tag=1.4.3
# Rollback to previous version
$ helm rollback myapp 1
# Release history
$ helm history myapp
REVISION UPDATED STATUS DESCRIPTION
1 Mon Oct 15 10:00:00 2018 SUPERSEDED Install complete
2 Tue Oct 16 14:30:00 2018 SUPERSEDED Upgrade complete
3 Wed Oct 17 09:00:00 2018 DEPLOYED Rollback to 1
# Debug — render templates without installation
$ helm template myapp ./myapp -f values-staging.yaml
Dependencies — Composing Charts¶
Your application needs PostgreSQL and Redis? You don’t need to define them manually:
# requirements.yaml
dependencies:
- name: postgresql
version: "3.18.3"
repository: "https://charts.helm.sh/stable"
condition: postgresql.enabled
- name: redis
version: "5.1.3"
repository: "https://charts.helm.sh/stable"
condition: redis.enabled
The helm dependency update command downloads sub-charts to the charts/ directory. You configure values for dependencies in the main values.yaml:
# values.yaml
postgresql:
enabled: true
postgresqlPassword: "secret"
persistence:
size: 10Gi
redis:
enabled: true
cluster:
enabled: false
Helm in CI/CD Pipeline¶
Helm integrates excellently into CI/CD pipelines:
- Lint:
helm lint ./myapp— syntax validation and best practices - Dry-run:
helm upgrade --install --dry-run— simulation without actual deployment - Diff: helm-diff plugin shows what will change compared to current state
- Automated rollback:
helm upgrade --atomic --timeout 5m— automatic rollback if deployment fails
Tiller — Helm 2 Security Issue¶
Helm 2 uses a server-side component called Tiller, which runs in the cluster with cluster-admin privileges. This is a security risk — anyone with access to the Tiller API can deploy anything anywhere.
Mitigation:
- Tiller per namespace with limited RBAC privileges
--tiller-namespaceflag for isolation- TLS between Helm client and Tiller
The good news is that Helm 3 (currently in alpha) completely removes Tiller. Release information is stored as Kubernetes Secrets. We expect a stable release in 2019.
Best Practices¶
- Semantic versioning — Chart.yaml version follows semver (MAJOR.MINOR.PATCH)
- Immutable tags — don’t use
:latestin production, always use specific tags - Resource limits — always define CPU/memory requests and limits
- NOTES.txt — displays useful information after installation (URL, credentials)
- Helm test —
helm test myappruns test pods (smoke tests) - Chart repository — ChartMuseum or GitHub Pages for hosting custom charts
Helm is an Essential Tool for Kubernetes¶
Without Helm, managing Kubernetes manifests for real applications is unbearable. Helm Charts bring parameterization, versioning, dependencies, and an ecosystem of ready-made solutions. Start with helm create, add custom templates, and integrate into CI/CD. And watch Helm 3 — removing Tiller will be a game changer.
Need help with implementation?
Our experts can help with design, implementation, and operations. From architecture to production.
Contact us