Helm and Package Management
A real Kubernetes application isn't one manifest — it's a Deployment, a Service, a ConfigMap, an Ingress, maybe a PersistentVolumeClaim, RBAC rules, and a HorizontalPodAutoscaler. That's 7+ YAML files that need to stay in sync, parameterized per environment, and versioned together. Helm solves this by packaging related manifests into a single deployable unit called a chart, with templating for environment-specific values and built-in release management for upgrades and rollbacks.
Helm Package Management: Templates + Values → Manifests → Releases
What Helm Actually Does
Helm is a package manager for Kubernetes — think apt or brew, but for K8s resources. It does three things:
- Packages multiple manifests into a single chart
- Templates those manifests with configurable values
- Manages releases — tracking what's installed, supporting upgrades and rollbacks
Without Helm, deploying an application means running kubectl apply on a pile of YAML files and hoping you got the right versions, in the right order, with the right environment-specific values. Helm gives you helm install my-app ./my-chart -f production.yaml — one command, parameterized, versioned.
Chart Structure
A Helm chart is a directory with a specific layout:
my-chart/
├── Chart.yaml # Chart metadata (name, version, dependencies)
├── values.yaml # Default configuration values
├── templates/ # Kubernetes manifest templates
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── hpa.yaml
│ └── _helpers.tpl # Reusable template snippets
├── charts/ # Dependency charts
└── README.md
Chart.yaml defines the chart's identity and dependencies:
apiVersion: v2
name: my-web-app
version: 1.2.0 # Chart version
appVersion: "3.1.0" # Application version
dependencies:
- name: postgresql
version: "12.1.0"
repository: "https://charts.bitnami.com/bitnami"
values.yaml provides defaults that users override per environment:
replicaCount: 3
image:
repository: myapp
tag: "3.1.0"
resources:
requests:
cpu: 250m
memory: 256Mi
ingress:
enabled: true
host: app.example.com
Template Rendering
Templates use Go's text/template syntax with Helm's extensions. The {{ .Values.xxx }} accessor pulls from values.yaml or user overrides:
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-chart.fullname" . }}
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
resources:
{{- toYaml .Values.resources | nindent 12 }}
You can preview what Helm will generate without deploying: helm template my-release ./my-chart -f staging.yaml. This is invaluable for debugging — always check the rendered output before deploying.
Core Commands
# Install a chart as a new release
helm install my-release ./my-chart -f production.yaml
# Upgrade an existing release (new revision)
helm upgrade my-release ./my-chart -f production.yaml
# Rollback to a previous revision
helm rollback my-release 2
# List releases
helm list
# View release history
helm history my-release
# Uninstall a release
helm uninstall my-release
# Search Artifact Hub for community charts
helm search hub prometheus
# Add a chart repository
helm repo add bitnami https://charts.bitnami.com/bitnami
Repositories and Artifact Hub
Helm charts are distributed via OCI registries or chart repositories. Artifact Hub (artifacthub.io) is the central search engine — it indexes charts from hundreds of repositories. Major chart publishers include Bitnami, the Prometheus community, and cloud provider official repos.
For internal charts, most teams push to their existing container registry (ECR, GCR, ACR all support OCI-based Helm charts) or use a dedicated chart repository like ChartMuseum.
Creating Custom Charts
# Scaffold a new chart
helm create my-service
# Lint for issues
helm lint ./my-service
# Package for distribution
helm package ./my-service
# Push to OCI registry
helm push my-service-1.0.0.tgz oci://registry.example.com/charts
The scaffolded chart is a good starting point, but it includes templates for features you might not need (ServiceAccount, Ingress, HPA). Strip it down to what you actually use — a leaner chart is easier to maintain.
Helm vs Kustomize
Kustomize is the main alternative to Helm. It's built into kubectl (kubectl apply -k) and uses an overlay-based approach instead of templating. You write plain YAML manifests and layer patches on top per environment.
| Aspect | Helm | Kustomize |
|---|---|---|
| Approach | Template + values | Base + overlays (patches) |
| Parameterization | Go templates, values files | Strategic merge patches, JSON patches |
| Packaging | Charts distributed via registries | Plain directories in git |
| Release management | Built-in (revisions, rollback) | None — relies on GitOps tooling |
| Learning curve | Moderate (templating syntax) | Lower (just YAML patches) |
| Ecosystem | Thousands of community charts | No package ecosystem |
| Best for | Third-party software, complex apps | Internal apps, GitOps workflows |
The practical guidance: use Helm for community software (installing Prometheus, NGINX Ingress, cert-manager) and Kustomize for your own applications where you control the manifests and want the simplicity of pure YAML with overlays. Many teams use both.
Key Takeaways
- Helm packages multiple Kubernetes manifests into a single versioned, parameterized chart
values.yamlprovides defaults that you override per environment — keeps your templates DRY- Always run
helm templateto inspect rendered output before deploying - Use Artifact Hub to find community charts instead of writing manifests from scratch
- Helm's release management gives you upgrade/rollback history; Kustomize needs external tooling for this
- Use Helm for third-party charts, Kustomize for your own apps — or use both
Enjoyed this breakdown?
Get notified when new lessons go live.