Now that we can install charts, let’s open one up. In this chapter we scaffold a brand new chart and walk through every file, so the rest of the series has a solid foundation.
Scaffold a chart
Helm can generate a working starter chart for you:
helm create demo
This creates a demo/ folder:
demo/
├── Chart.yaml
├── values.yaml
├── charts/
├── templates/
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── NOTES.txt
│ └── tests/
└── .helmignore
Let’s go through the important pieces.
Chart.yaml — the chart’s identity card
Chart.yaml holds metadata about the chart itself:
apiVersion: v2
name: demo
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: "1.16.0"
- apiVersion: v2 — the modern chart format (used by Helm 3 and 4).
- name / description — what the chart is.
- type —
application(something you deploy) orlibrary(shared template helpers, not installable on its own). - version — the version of the chart, bumped when you change the chart. Uses SemVer.
- appVersion — the version of the app inside the chart (e.g. the image tag). This is just metadata; it doesn’t have to be SemVer.
Keep the two versions straight: version is about the packaging, appVersion is about
the software being packaged.
values.yaml — the default configuration
values.yaml is the single source of default settings. Everything a user might want to
change lives here:
replicaCount: 1
image:
repository: nginx
tag: ""
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
Templates read these values (we’ll see how next chapter). Users override them with
-f my-values.yaml or --set, but they never have to edit the templates.
templates/ — the manifests, parameterized
This is where the real work happens. Each file in templates/ is a Kubernetes manifest
with placeholders. A trimmed deployment.yaml looks like this:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-demo
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- name: demo
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
Anything inside {{ }} is a template action that Helm evaluates
at install time. .Values reaches into values.yaml; .Release is information about
this particular install. We’ll dig into all of these in the next chapter.
templates/_helpers.tpl — reusable snippets
Files starting with an underscore aren’t rendered into Kubernetes objects. Instead they hold named templates — reusable snippets you can include elsewhere, most commonly a standard set of labels and a naming helper. More on these in chapter 4.
templates/NOTES.txt — the post-install message
NOTES.txt is a template too, but its rendered output is printed to the terminal after
helm install. It’s the perfect place to tell users how to reach the app they just
deployed.
charts/ — subcharts (dependencies)
The charts/ folder holds dependency charts. If your app needs Redis or Postgres,
you can declare those as dependencies and Helm places them here. We’ll cover
dependencies in chapter 7.
.helmignore
Like .gitignore, this lists files to exclude when packaging the chart (.git,
editor files, and so on).
Render it to see the result
You don’t need a cluster to see what a chart produces. helm template renders
everything locally:
helm template my-demo ./demo
Try changing a value and re-rendering:
helm template my-demo ./demo --set replicaCount=3
You’ll see the replicas field in the output change to 3. That immediate feedback
loop — edit values, re-render, inspect — is how you’ll develop every chart.
Lint early, lint often
Helm ships a linter that catches structural mistakes:
helm lint ./demo
The scaffolded demo chart for this chapter is in
02-anatomy-of-a-chart.
Now that we know the layout of a chart, it’s time to learn the language that powers the templates. In the next chapter we’ll cover Helm templating from the ground up.