Helm Chart

What is a Helm chart?

A Helm chart is a package that contains all resources required to deploy an application to a Kubernetes cluster. The package includes deployment, service, secret, and ConfigMap YAML files that define the state of a specific application.

A Helm chart packages these YAML files and templates, allowing additional configuration files to be generated according to parameterized values. This makes it possible to customize configuration files for different environments or reuse them across multiple deployments. Since each Helm chart can also be versioned independently, it is easy to manage multiple versions of an application with different settings.

Helm package and chart

Helm uses a packaging format called charts. A package is the packaged form of a Helm chart, and a chart is an archive that contains Kubernetes resource YAML files as templates, along with metadata files and related content.

  • A chart is a collection of files that describe Kubernetes resources.
  • A chart is used to deploy something.
    • Examples: a memcached Pod, a web app with HTTP servers, databases, and so on.
  • A chart is created from files organized in a specific directory tree.
    • These files can be packaged as a versioned archive for deployment.

Creating a chart file and understanding its structure

Create a chart directory

Create a directory for Helm charts, then use the helm create {directory} command to generate the default directory structure.

% mkdir charts
% cd charts
% helm create app
Creating app

Chart file structure

The generated default file structure is as follows.

% tree app
app
├── Chart.yaml                    # YAML file with chart name, version, description, and other information. (required)
├── charts                        # Directory containing charts this chart depends on. (optional)
├── templates                     # Directory of template files that generate valid Kubernetes manifests when combined with values. (required)
│   ├── NOTES.txt                 # Text file containing brief usage instructions. (optional)
│   ├── _helpers.tpl              # Shared variable definitions for template manifest files. (required)
│   ├── deployment.yaml           # Resource template files to run in the cluster
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml                   # File defining default configuration variables used by chart templates. (optional)

4 directories, 10 files

What is a manifest file? In computing, it is a file containing metadata for a group of files that are part of a set or a coherent unit.

YAML files

chart.yaml

apiVersion: API version of the Helm Chart itself (required)
name: Chart name (required)
version: Chart version, which must follow SemVer (Semantic Versioning). (required)
         # Example: X.X.X format. See SemVer rules: https://semver.org/lang/ko/
kubeVersion: SemVer range for the minimum compatible Kubernetes version that guarantees chart installation and execution. (optional)
             # Example: ">=1.15.3"
description: Brief description of the chart project. (optional)
type: Chart type. (optional)
keywords:
  - Keyword list for this chart project. (optional)
    # Keywords are also searched by helm search.
home: URL of the chart project homepage. (optional)
sources:
  - List of source code URLs for this chart project. (optional)
    # This is not the chart repository address.
dependencies: # List of chart requirements. (optional)
  - name: Chart name (nginx)
    version: Chart version ("1.2.3")
    repository: Repository URL ("https://example.com/charts") or ("@repo-name")
    condition: (optional) YAML path that creates a boolean value determining whether charts are enabled or disabled. Example: subchart1.enabled
    tags: # (optional)
      - Tags that can group charts so they can be enabled or disabled together
    enabled: (optional) Boolean that determines whether the chart can be loaded
    import-values: # (optional)
      - ImportValues holds mappings for parent keys to import. Each item can be a string or a child/parent child-list pair.
    alias: (optional) Used as an alias for the chart. Useful when the same chart must be added multiple times.
maintainers: # (optional)
  - name: Maintainer name (required for each maintainer)
    email: Maintainer email (optional for each maintainer)
    url: URL for the maintainer (optional for each maintainer)
icon: URL of an SVG or PNG image used as an icon and shown when displaying the chart in catalogs. (optional)
appVersion: Version of the app served by the chart. (optional)
            # This is the app version served by the chart and does not need to follow SemVer.
deprecated: Whether the chart is deprecated, specified as a boolean true/false value. (optional)
annotations:
  example: List of annotations mapped by key. (optional).

values.yaml

In templates, values are used in a form such as {{ .Values.image.tag }}. Pay attention to indentation when writing this file.

Define resources to deploy in the templates folder

By default, deployment, service, serviceaccount, and ingress templates exist.

Define persistent volumes, config maps, and other resources as needed.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.name  }}
  labels:
    app: {{ .Values.name  }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      name: {{ .Values.name }}
  template:
    metadata:
      {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      labels:
        name: {{ .Values.name  }}
    spec:
      containers:
    - name: {{ .Chart.Name }}
      image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
      imagePullPolicy: {{ .Values.image.pullPolicy }}
      ports:
        - name: http
          containerPort: {{ .Values.container.port  }}
          protocol: TCP
      envFrom:
        - configMapRef:
            name: {{ .Values.config.name  }}
      volumeMounts:
        - mountPath: {{ .Values.container.mountpath  }}
          name: {{ .Values.container.volumename }}

  volumes:
    - name: {{ .Values.container.volumename }}
      persistentVolumeClaim:
        claimName: {{ .Values.PVC.name }}

Helm template syntax

Template files follow the standard conventions for writing Go templates. See the (text/template Go package documentation).

Variables are used with {{ }}.

  • .Values
    • Variables defined in the values.yaml file.
  • .Charts
    • Variables defined in the Charts.yaml file.
    • The chart version can be accessed as Chart.Version, and maintainers as Chart.Maintainers.
  • .Release
    • Information assigned during deployment.
      • For example, when installing with --namespace test, .Release.Namespace is assigned test.
    • Release.Name: Release name, not the chart name.
    • Release.Namespace: Namespace where the chart was released.
    • Release.Service: Service that performs the release.
    • Release.IsUpgrade: Set to true if currently upgrading or rolling back.
    • Release.IsInstall: Set to true if currently installing.
  • include...
    • Variables defined in the _helpers.tpl file.
  • with ~ end
    • Syntax that defines the scope of a variable. The corresponding block defines that . belongs to the configured variable.
    • Example: in the code below, .drink means .Values.favorite.drink.
      {{- with .Values.favorite }}
        drink: {{ .drink | default "tea" | quote }}
        food: {{ .food | upper | quote }}
      {{- end }}
      
  • toYaml
    • Converts the variable to YAML format.
  • quote
    • Converts the value to a string type.

Inspecting a chart

You can check whether the defined chart is syntactically valid.

helm lint {Chart.yaml location}

This only checks for syntax errors and does not mean that installation will succeed without problems.

You can preview the resource deployment result generated from the templates and referenced variables.

helm template {Chart.yaml location}

This process lets you check whether the deployment output matches the intended form.

You can test-install the chart to check for errors.

helm install {release name} {Chart.yaml location}  --debug --dry-run
  • --dry-run: Test-installs the chart without actually installing it into the cluster.
  • --debug: Shows the manifest file contents for deployment.

Create a chart and register it in a repository

A Helm repository must have an index.yaml file containing information about each chart in the chart repository.

In the folder where index.yaml exists, run the following command to package and create the chart.

helm package {Chart.yaml location}

A compressed file named {name}-{version}.tgz, as defined in Chart.yaml, is created.

If you want to use the generated archive locally without registering it in a repository, you can use helm install {name}.

After creating the chart, update the index file that contains chart information.

helm repo index {index.yaml path}

If it is a GitHub repository, run git push, then:

helm repo update

The chart list is fetched again from the repository and updated.

Search to confirm that it has been updated.

helm search repo {chart name}

The search term is treated like a keyword, and charts containing that term and their repositories are printed.

Install using the created chart

Install the created chart with the following command.

helm install {deployment name} {repository name/chart name} -n {namespace}

Reference