Cart

    Sorry, we could not find any results for your search querry.

    Creating Helm Charts

    Helm is a package manager for Kubernetes. Helm uses a package format called Charts. A Chart is a collection of files that describes a coherent set of Kubernetes resources. Just as apt simplifies installing and managing software on Debian/Ubuntu, Helm does the same for Kubernetes resources. In this guide, we’ll show you how to create and use your own Helm Chart.

     

     

    Creating a Helm Chart manually

     

    Step 1

    A Helm Chart uses a specific folder structure and set of files. You can create these manually, or automatically with “helm create”. The latter is the quickest and simplest, and works as follows:

    helm create demo-Chart

    This command automatically creates a directory with the following files:

    demo-Chart
    ├── Chart.yaml
    ├── values.yaml
    ├── Charts/
    └── templates/
        ├── _helpers.tpl
        ├── NOTES.txt
        ├── deployment.yaml
        ├── service.yaml
        ├── ingress.yaml
        ├── hpa.yaml
        ├── serviceaccount.yaml
        └── tests/
            └── test-connection.yaml

     

    Step 2

    From here, edit the files as needed. Start by opening “Chart.yaml”, for example:

    nano demo-Chart/Chart.yaml

    Adjust the contents as desired and save your changes (ctrl + x > y > enter), for example:

    apiVersion: v2
    name: demo-Chart
    description: A Helm Chart for Nginx
    type: application
    version: 0.1.0
    appVersion: "1.29.1"
    kubeVersion: ">=1.24.0-0"
    maintainers:
      - name: Your Name
        email: you@example.com

    This file contains metadata for your Chart, such as its name, version, and description. The required fields in the Chart.yaml file are apiVersion, name, and version, which define the Chart API version, the Chart name, and the Chart version respectively. The remaining fields are optional and can be used to provide additional information about the Chart. 
    You can find the correct appVersion by checking, for example, the current software version in an existing Chart on Artifact Hub.

    The most commonly used fields in Chart.yaml are:

    apiVersion: v2                        # The Chart API version, always "v2" (required)
    name: demo-Chart                      # The name of the Chart (required)
    description: "Short description"      # A description of your project
    type: application                     # Application or Library; see the default comments in Chart.yaml
    version: 0.1.0                        # The Chart version (SemVer, required)
    appVersion: "8.0"                     # App version (free-form)
    kubeVersion: ">=1.24.0-0"             # Compatible Kubernetes version
    keywords: "Software A, B"             # A list of project keywords (optional)
    home: https://...                     # Project homepage
    sources:                              # URLs pointing to source code
      - https://...
    maintainers:                          # Optional maintainer details for the Helm Chart
      - name: ...
        email: ...
        url: ...
    engine: gotpl                         # Template engine name (default is gotpl)
    icon: https://.../icon.png            # URL to an SVG or PNG icon
    deprecated: 0                         # Whether this Chart is deprecated (boolean)

     

    Step 3 

    The next file, values.yaml, is one of the most important: this is where you define the values of many variables. In any file where a variable appears, its value is automatically filled in by referencing it from values.yaml, for example: {{ .Values.replicaCount }}. Here, .Values indicates the variable resides in values.yaml, and replicaCount is the variable being used.

    The benefit of using values.yaml is that you don’t have to edit other .yaml files when you change variable values—you do it from this single file: values.yaml. First open values.yaml:

    nano demo-Chart/values.yaml

    Adjust the file as you like—for a minimal Nginx deployment, for instance—then save your changes (without the comments) (ctrl + x > y > enter). Here we assume an Nginx setup with a corresponding service.

    deploymentName: nginx
    # A short, recognisable name also used in labels/selectors and resource names.
    
    replicaCount: 1
    # Number of pods. For stateful DBs usually 1 (unless you arrange replication/clustering).
    
    image:
      repository: nginx
      # The container image name. Three options:
      # - Name as on Docker Hub (e.g. the mysql in https://hub.docker.com/_/mysql): "mysql"
      # - A full docker.io address: "docker.io/library/mysql"
      # - A private registry, for example: "registry.example.com/team/mysql"
      tag: "1.29.1"
      # Image version. For production, a fixed tag is recommended, e.g. 1.29.1.
      # Alternatively, you can use "latest".
      pullPolicy: IfNotPresent
      # - Always: pulls the image every time the pod restarts.
      # - IfNotPresent: only pulls if the image isn’t present locally (default).
      # - Never: never pull (image MUST exist locally; rarely needed).
    
    service:
      name: nginx
      # Kubernetes Service name (cluster-internal DNS).
      type: ClusterIP
      # Choose one of the following Service types:
      # - ClusterIP: internal-only (within the cluster). Safest option for databases.
      # - NodePort: external via each node:port; simple but limited.
      # - LoadBalancer: external IP via cloud LB; use only if the service must be publicly reachable.
      port: 80                           # Port the service listens on.
      protocol: TCP                      # TCP, UDP

     

    Step 4

    The ‘templates’ folder contains template files for the Kubernetes resources managed by your Chart. Open deployment.yaml, for example:

    nano demo-Chart/templates/deployment.yaml

    The default file includes many options; see also the earlier guide creating Kubernetes objects.
    For a simple Nginx deployment, a layout like the one below is sufficient. You’ll see various values referenced with a structure such as {{ .Values.deploymentName }}. These are filled in automatically based on the deploymentName in values.yaml (see step 3).

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: {{ .Values.deploymentName }}
      labels:
        app.kubernetes.io/name: {{ .Values.deploymentName }}
    spec:
      replicas: {{ .Values.replicaCount }}
      selector:
        matchLabels:
          app.kubernetes.io/name: {{ .Values.deploymentName }}
      template:
        metadata:
          labels:
            app.kubernetes.io/name: {{ .Values.deploymentName }}
        spec:
          containers:
            - name: nginx
              image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
              imagePullPolicy: {{ .Values.image.pullPolicy }}
              ports:
                - name: http
                  containerPort: {{ .Values.service.port }}

     

    Step 5

    In step 3 we also included values for an Nginx service. There’s already an example for services in demo-Chart/templates/services.yaml:

    nano demo-Chart/templates/services.yaml

    Thanks to the configuration in values.yaml, you can reference those values in services.yaml too—for a simple Nginx setup, for example:

    apiVersion: v1
    kind: Service
    metadata:
      name: {{ .Values.service.name }}
      labels:
        app.kubernetes.io/name: {{ .Values.deploymentName }}
    spec:
      type: {{ .Values.service.type }}
      selector:
        app.kubernetes.io/name: {{ .Values.deploymentName }}
      ports:
        - port: {{ .Values.service.port }}
          targetPort: {{ .Values.service.port }}
          protocol: {{ .Values.service.protocol }}

     

    Step 6 – optional

    So far we’ve assumed a minimal setup. If you’d also like to add an ingress, you can do so by adding the required variables to values.yaml:

    nano demo-Chart/values.yaml

    Edit the file as desired (without the comments) and save your changes (ctrl + x > y > enter). 

    ingress:
      enabled: true             # enable the ingress resource
      ingressClassName: nginx   # omit this if you only use annotations, e.g. below.
      annotations:              # optional; remove this if you use ingressClassName
        nginx.ingress.kubernetes.io/ssl-redirect: "false"
        nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    
      hosts:
        - host: example.local   # the hostname of your Nginx setup
          paths:
            - path: /
              pathType: Prefix
              # optionally override serviceName and servicePort (from the service above)
              # serviceName: nginx-demo
              # servicePort: 80
    
      # Optional with TLS; this requires a Secret.
      tls:
        - hosts:
            - example.local
          SecretName: example-local-tls

    There are several options for using Secrets; see for example this Nginx Chart, or our Traefik guide for an example of creating and using a Secret in a Kubernetes object.

    The default demo-Chart/templates/ingress.yaml file is cleverly put together with if statements so it won’t be used unless you enable ingress in values.yaml and provide the relevant variables; otherwise everything is filled in automatically. For completeness, here’s the default content of ingress.yaml.

    {{- if .Values.ingress.enabled -}}
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: {{ include "demo-Chart.fullname" . }}
      labels:
        {{- include "demo-Chart.labels" . | nindent 4 }}
      {{- with .Values.ingress.annotations }}
      annotations:
        {{- toYaml . | nindent 4 }}
      {{- end }}
    spec:
      {{- with .Values.ingress.className }}
      ingressClassName: {{ . }}
      {{- end }}
      {{- if .Values.ingress.tls }}
      tls:
        {{- range .Values.ingress.tls }}
        - hosts:
            {{- range .hosts }}
            - {{ . | quote }}
            {{- end }}
          SecretName: {{ .SecretName }}
        {{- end }}
      {{- end }}
      rules:
        {{- range .Values.ingress.hosts }}
        - host: {{ .host | quote }}
          http:
            paths:
              {{- range .paths }}
              - path: {{ .path }}
                {{- with .pathType }}
                pathType: {{ . }}
                {{- end }}
                backend:
                  service:
                    name: {{ include "demo-Chart.fullname" $ }}
                    port:
                      number: {{ $.Values.service.port }}
              {{- end }}
        {{- end }}
    {{- end }}

     

    Step 7

    There are a few more files in the templates folder, such as hpa.yaml (not yet supported on our platform) and serviceaccount.yaml. These are set up so they won’t be used unless you specify otherwise in values.yaml. You’re free to delete NOTES.txt, hpa.yaml, and serviceaccount.yaml. Do keep _helpers.tpl: it contains small snippets you can call from other files, such as {{ include "demo-Chart.name" . }}. 

    No further changes are needed, and you can proceed to install your Helm Chart.


     

    Installing and managing the Helm Chart

     

     

    Installing the Helm Chart

    There are several ways to install a Helm Chart (i.e. your Helm release). We’ll start with the simplest and assume you’re on the command line (any OS) in the directory where the Helm Chart was created (/demo-Chart/ in this example). You can find more information about the helm install command here.

    helm install nginx -f values.yaml

    Optionally add -n namespace to the command and change ‘namespace’ to the desired name. This determines which namespace the Helm Chart is installed into. This is optional and requires an existing namespace (kubectl create ns namespacename).

    In our example we didn’t assume a setup with sensitive passwords. If you do need those, there are a few ways to provide them (the examples below assume a MySQL setup):

    Using a Secret (for production environments):

    helm install mysql-demo \
      --set mysql.existingSecret=mysql-prod-Secret \
      --set mysql.database=mydb

    Creating Secrets is beyond the scope of this guide, but you’ll find an example of creating and using Secrets in our Traefik guide.

    Inline passwords (for test environments):

    helm install mysql-demo \
      --set mysql.rootPassword="$(openssl rand -base64 24)" \
      --set mysql.password="$(openssl rand -base64 24)" \
      --set mysql.user=appuser

     

    Checking your Helm release

     

    You can list all releases on your cluster with:

    helm list

    The output looks like this (note the scrollbar):

    NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          Chart                     APP VERSION
    mysql-1670416172        default         1               2022-12-07 13:29:33.9111825 +0100 STD   deployed        mysql-9.4.4               8.0.31

    For more specific information (similar to the output of the ‘helm install’ command), run:

    helm status releasename

    Of course, you can also check individual components of your release with familiar kubectl commands, for example:

    kubectl get deployment

    If you’re using a namespace (recommended), don’t forget to add -n namespacename to the command.


     

    Removing your Helm release

    Removing a release is as straightforward as installing it:

    helm uninstall releasename

    Replace ‘releasename’ with the name of the release as shown under ‘NAME’ in the output of the ‘helm list’ command.

    Optionally, you can add the --keep-history flag. This is a handy way to retain information about the release:

    helm uninstall releasename --keep-history

    You can then review the history of the ‘releasename’ later with:

    helm history releasename

    Helm goes a step further: using this information, you can roll back a release after uninstalling it with:

    helm rollback releasename revision

    You’ll find the revision number in the output of the helm history command.


     

    That brings us to the end of this guide on creating Helm Charts. In a future update, we’ll expand it with additional components such as secrets, persistent volumes, etc.

    Need help?

    Receive personal support from our supporters

    Contact us