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