Skip to main content

Chapter 10.2 - Helm Charts

Learning Objectives​

By the end of this chapter, you will be able to:

  • Understand the structure of a Helm Chart
  • Create a Chart from scratch
  • Use Go templates
  • Customize with values.yaml
  • Manage dependencies
  • Publish a Chart

Introduction​

A Helm Chart is a package containing all the files needed to deploy an application in Kubernetes. It uses templates to make YAML files dynamic.


Chart Structure​

Complete Structure​

my-chart/
├── Chart.yaml # Chart metadata
├── Chart.lock # Dependency lock file
├── values.yaml # Default values
├── values.schema.json # Validation schema (optional)
├── templates/ # Kubernetes templates
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── configmap.yaml
│ ├── ingress.yaml
│ ├── _helpers.tpl # Reusable helpers
│ └── NOTES.txt # Notes displayed after installation
├── charts/ # Dependent Charts (optional)
└── README.md # Documentation

Creating a Chart​

Creating a Basic Chart​

# Create a new Chart
helm create my-chart

# Created structure
my-chart/
├── Chart.yaml
├── values.yaml
└── templates/
├── deployment.yaml
├── service.yaml
├── ingress.yaml
├── _helpers.tpl
└── NOTES.txt

Chart.yaml​

apiVersion: v2
name: my-chart
description: A Helm chart for my application
type: application
version: 0.1.0
appVersion: "1.0.0"
keywords:
- web
- application
maintainers:
- name: John Doe
email: john@example.com

Go Templates​

Basic Syntax​

Templates use the Go templates syntax:

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-deployment
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- name: {{ .Chart.Name }}
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}

Available Variables​

  • .Release.Name: Release name
  • .Release.Namespace: Namespace
  • .Chart.Name: Chart name
  • .Values.*: Values from values.yaml
  • .Capabilities.*: Cluster information

values.yaml​

Example values.yaml​

# Number of replicas
replicaCount: 3

# Image
image:
repository: nginx
tag: "1.20"
pullPolicy: IfNotPresent

# Service
service:
type: ClusterIP
port: 80

# Ingress
ingress:
enabled: true
className: nginx
hosts:
- host: example.com
paths:
- path: /
pathType: Prefix
tls: []

# Resources
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi

Complete Example: Web App Chart​

Chart.yaml​

apiVersion: v2
name: web-app
description: A simple web application
type: application
version: 0.1.0
appVersion: "1.0.0"

values.yaml​

replicaCount: 2

image:
repository: myapp
tag: "1.0.0"
pullPolicy: IfNotPresent

service:
type: ClusterIP
port: 8080

ingress:
enabled: true
className: nginx
hosts:
- host: myapp.example.com
paths:
- path: /
pathType: Prefix

resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi

templates/deployment.yaml​

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "web-app.fullname" . }}
labels:
{{- include "web-app.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "web-app.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "web-app.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 8080
name: http
resources:
{{- toYaml .Values.resources | nindent 10 }}

templates/service.yaml​

apiVersion: v1
kind: Service
metadata:
name: {{ include "web-app.fullname" . }}
labels:
{{- include "web-app.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "web-app.selectorLabels" . | nindent 4 }}

templates/_helpers.tpl​

{{/*
Common labels
*/}}
{{- define "web-app.labels" -}}
app.kubernetes.io/name: {{ include "web-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "web-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "web-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Full name
*/}}
{{- define "web-app.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name }}
{{- end }}

Installing a Local Chart​

Install​

# From a local directory
helm install my-release ./my-chart

# With custom values
helm install my-release ./my-chart -f custom-values.yaml

# With inline values
helm install my-release ./my-chart \
--set replicaCount=5 \
--set image.tag=1.1.0

Update​

# Update
helm upgrade my-release ./my-chart

# With new values
helm upgrade my-release ./my-chart -f new-values.yaml

Dependencies​

Chart.yaml with Dependencies​

apiVersion: v2
name: my-app
dependencies:
- name: postgresql
version: "12.0.0"
repository: "https://charts.bitnami.com/bitnami"
- name: redis
version: "17.0.0"
repository: "https://charts.bitnami.com/bitnami"

Installing Dependencies​

# Download dependencies
helm dependency update

# View dependencies
helm dependency list

Packaging and Distribution​

Creating a Package​

# Create a .tgz package
helm package ./my-chart

# Result: my-chart-0.1.0.tgz

Publishing to a Repository​

# Add to repository
helm repo index . --url https://charts.example.com

# Upload the package
# (depending on your storage method)

Useful Commands​

Validation​

# Linter
helm lint ./my-chart

# Template with dry-run
helm install my-release ./my-chart --dry-run --debug

# View computed values
helm template my-release ./my-chart

Testing​

# Install in test mode
helm install my-release ./my-chart --dry-run

# View generated manifest
helm get manifest my-release

Best Practices​

1. Clear Structure​

Organize templates logically.

2. Helpers​

Use _helpers.tpl for reusable code.

3. Documentation​

Document all values in values.yaml.

4. Validation​

Use values.schema.json to validate values.

5. Versioning​

Follow semantic versioning for Charts.


Summary​

In this chapter, you learned:

Structure: Chart.yaml, values.yaml, templates/, charts/
Go Templates: Syntax with double curly braces, available variables
values.yaml: Customizable default values
Helpers: _helpers.tpl for reusable code
Dependencies: Management via Chart.yaml
Packaging: helm package to create .tgz
Installation: helm install from local or repository
Best practices: Structure, helpers, documentation, versioning


Next Steps​

Chapter 10.3: Advanced Templates and Hooks
Lab 10.2: Customization with values.yaml
Lab 10.3: Creating a Custom Chart


Chapter created on: December 2024