Deploy Applications to Kubernetes with Helm Charts
Package, version, and deploy Kubernetes applications using Helm charts with value overrides, template functions, and release management for reproducible infrastructure
Package and deploy applications to Kubernetes using Helm, the package manager for K8s. The following demonstrates how to chart structure, templating with values, release upgrades and rollbacks, and dependency management for production-grade deployments.
When to Use This
- You deploy the same application to multiple environments with different configurations. See Environment Variables for per-environment config.
- Kubernetes manifests become repetitive and hard to maintain across teams. See Docker Compose Local Dev for local multi-service templates.
- You need versioned releases with easy rollback capabilities. See Blue-Green Deployment for instant rollback.
Solution
1. Chart Structure
myapp/
Chart.yaml # Chart metadata
values.yaml # Default configuration values
values.prod.yaml # Production overrides
templates/
_helpers.tpl # Named template helpers
deployment.yaml
service.yaml
ingress.yaml
configmap.yaml
charts/ # Subchart dependencies
2. Chart Metadata
# Chart.yaml
apiVersion: v2
name: myapp
description: A Helm chart for MyApp
type: application
version: 1.2.0
appVersion: "2.5.1"
dependencies:
- name: postgresql
version: 12.x.x
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
3. Template with Values
# 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 | default .Chart.AppVersion }}"
ports:
- containerPort: {{ .Values.service.port }}
env:
- name: DATABASE_URL
value: {{ .Values.database.url | quote }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
4. Default and Override Values
# values.yaml
replicaCount: 2
image:
repository: myregistry/myapp
tag: ""
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 3000
ingress:
enabled: false
database:
url: "postgres://localhost:5432/myapp"
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
# values.prod.yaml
replicaCount: 5
ingress:
enabled: true
hosts:
- host: myapp.example.com
paths:
- path: /
pathType: Prefix
resources:
limits:
cpu: 2000m
memory: 2Gi
5. Install and Upgrade
# Install with default values
helm install myapp ./myapp
# Install with production overrides
helm install myapp ./myapp -f values.prod.yaml
# Upgrade existing release
helm upgrade myapp ./myapp -f values.prod.yaml
# Rollback to previous revision
helm rollback myapp 2
# List release history
helm history myapp
6. Named Template Helpers
# templates/_helpers.tpl
{{/* Expand the name of the chart */}}
{{- define "myapp.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/* Create a default fully qualified app name */}}
{{- define "myapp.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
How It Works
- Charts package Kubernetes manifests into versioned, configurable units
- Templates use Go templating to inject values into YAML resources
- Values files provide environment-specific configuration overrides
- Releases track deployed chart versions for easy rollback
Production Considerations
- Store charts in a registry (Harbor, OCI registry) rather than local files
- Use
helm lintandhelm templateto validate before deploying - Pin dependency versions explicitly to prevent unexpected upgrades
Common Mistakes
- Hardcoding environment values in templates instead of values files
- Forgetting to update
Chart.versionwhen making changes - Not testing
helm upgradebefore applying to production
Performance Tips
- Use
helm templatefor validation. Faster than full deploy:
helm template my-app ./my-app -f values.yaml > manifest.yaml
kubectl apply --dry-run=client -f manifest.yaml
- Cache chart dependencies. Avoid re-downloading subcharts:
# Dependencies are cached in charts/ directory
helm dependency build # Downloads once
helm dependency update # Only updates changed deps
- Use
--reuse-valuesfor minor updates. Avoid re-specifying all values:
# Only override specific values, keep the rest
helm upgrade my-app ./my-app --reuse-values --set image.tag=v2.0.1
- Parallelize tests with
helm test. Run multiple test pods:
# templates/tests/
# test-1.yaml, test-2.yaml, test-3.yaml
# All run in parallel when you execute: helm test my-app Frequently Asked Questions
How is this different from Kustomize?
Helm uses templating and packaging for reusable charts. Kustomize uses overlays and patches without templating. Helm is better for distributing complex applications; Kustomize is simpler for internal overlays.
Can I use Helm with CI/CD?
Yes. Use helm upgrade --install for idempotent deployments in pipelines. Combine with helm diff to preview changes before applying.
Related Resources
Local Microservices Development with Docker Compose
Orchestrate multi-service local environments with Docker Compose including databases, caches, message brokers, and reverse proxies with hot reload and shared networks
PatternAmbassador Pattern for Resilient Remote Service Access
Add a local ambassador that handles retries, circuit breaking, and monitoring when calling remote services, keeping the client simple and the service logic pure
GuideKubernetes Basics for Application Developers
Learn the core Kubernetes concepts every developer needs: Pods, Services, Deployments, ConfigMaps, and basic kubectl commands.
RecipeGrafana Dashboards for Observability with Prometheus
Build Grafana dashboards that visualize Prometheus metrics. Use panels, template variables, provisioning, and alerts for team-wide observability.
RecipeMetrics Collection and Alerting with Prometheus
Instrument applications and infrastructure with Prometheus metrics, configure alerting rules, and set up recording rules for efficient monitoring.
RecipeCloud Cost Optimization Recipe
Reduce cloud infrastructure costs with right-sizing, reserved instances, spot instances, and automated resource scheduling across AWS, GCP, and Azure.