Library Charts

A library chart is a type of Helm chart that defines chart primitives or definitions which can be shared by Helm templates in other charts. This allows users to share snippets of code that can be re-used across charts, avoiding repetition and keeping charts DRY.

The library chart was introduced in Helm 3 to formally recognize common or helper charts that have been used by chart maintainers since Helm 2. By including it as a chart type, it provides:

  • A means to explicitly distinguish between common and application charts
  • Logic to prevent installation of a common chart
  • No rendering of templates in a common chart which may contain release artifacts
  • Allow for dependent charts to use the importer’s context

A chart maintainer can define a common chart as a library chart and now be confident that Helm will handle the chart in a standard consistent fashion. It also means that definitions in an application chart can be shared by changing the chart type.

Create a Simple Library Chart

As mentioned previously, a library chart is a type of Helm chart. This means that you can start off by creating a scaffold chart:

  1. $ helm create mylibchart
  2. Creating mylibchart

You will first remove all the files in templates directory as we will create our own templates definitions in this example.

  1. $ rm -rf mylibchart/templates/*

The values file will not be required either.

  1. $ rm -f mylibchart/values.yaml

Before we jump into creating common code, lets do a quick review of some relevant Helm concepts. A named template (sometimes called a partial or a subtemplate) is simply a template defined inside of a file, and given a name. In the templates/ directory, any file that begins with an underscore(_) is not expected to output a Kubernetes manifest file. So by convention, helper templates and partials are placed in a _*.tpl or _*.yaml files.

In this example, we will code a common ConfigMap which creates an empty ConfigMap resource. We will define the common ConfigMap in file mylibchart/templates/_configmap.yaml as follows:

  1. {{- define "mylibchart.configmap.tpl" -}}
  2. apiVersion: v1
  3. kind: ConfigMap
  4. metadata:
  5. name: {{ .Release.Name | printf "%s-%s" .Chart.Name }}
  6. data: {}
  7. {{- end -}}
  8. {{- define "mylibchart.configmap" -}}
  9. {{- include "mylibchart.util.merge" (append . "mylibchart.configmap.tpl") -}}
  10. {{- end -}}

The ConfigMap construct is defined in named template mylibchart.configmap.tpl. It is a simple ConfigMap with an empty resource, data. Within this file there is another named template called mylibchart.configmap. This named template includes another named template mylibchart.util.merge which will take 2 named templates as arguments, the template calling mylibchart.configmap and mylibchart.configmap.tpl.

The helper function mylibchart.util.merge is a named template in mylibchart/templates/_util.yaml. It is a handy util from The Common Helm Helper Chart because it merges the 2 templates and overrides any common parts in both:

  1. {{- /*
  2. mylibchart.util.merge will merge two YAML templates and output the result.
  3. This takes an array of three values:
  4. - the top context
  5. - the template name of the overrides (destination)
  6. - the template name of the base (source)
  7. */}}
  8. {{- define "mylibchart.util.merge" -}}
  9. {{- $top := first . -}}
  10. {{- $overrides := fromYaml (include (index . 1) $top) | default (dict ) -}}
  11. {{- $tpl := fromYaml (include (index . 2) $top) | default (dict ) -}}
  12. {{- toYaml (merge $overrides $tpl) -}}
  13. {{- end -}}

This is important when a chart wants to use common code that it needs to customize with its configuration.

Finally, lets change the chart type to library. This requires editing mylibchart/Chart.yaml as follows:

  1. apiVersion: v2
  2. name: mylibchart
  3. description: A Helm chart for Kubernetes
  4. # A chart can be either an 'application' or a 'library' chart.
  5. #
  6. # Application charts are a collection of templates that can be packaged into versioned archives
  7. # to be deployed.
  8. #
  9. # Library charts provide useful utilities or functions for the chart developer. They're included as
  10. # a dependency of application charts to inject those utilities and functions into the rendering
  11. # pipeline. Library charts do not define any templates and therefore cannot be deployed.
  12. # type: application
  13. type: library
  14. # This is the chart version. This version number should be incremented each time you make changes
  15. # to the chart and its templates, including the app version.
  16. version: 0.1.0
  17. # This is the version number of the application being deployed. This version number should be
  18. # incremented each time you make changes to the application and it is recommended to use it with quotes.
  19. appVersion: "1.16.0"

The library chart is now ready to be shared and its ConfigMap definition to be re-used.

Before moving on, it is worth checking if Helm recognizes the chart as a library chart:

  1. $ helm install mylibchart mylibchart/
  2. Error: library charts are not installable

Use the Simple Library Chart

It is time to use the library chart. This means creating a scaffold chart again:

  1. $ helm create mychart
  2. Creating mychart

Lets clean out the template files again as we want to create a ConfigMap only:

  1. $ rm -rf mychart/templates/*

When we want to create a simple ConfigMap in a Helm template, it could look similar to the following:

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: {{ .Release.Name | printf "%s-%s" .Chart.Name }}
  5. data:
  6. myvalue: "Hello World"

We are however going to re-use the common code already created in mylibchart. The ConfigMap can be created in the file mychart/templates/configmap.yaml as follows:

  1. {{- include "mylibchart.configmap" (list . "mychart.configmap") -}}
  2. {{- define "mychart.configmap" -}}
  3. data:
  4. myvalue: "Hello World"
  5. {{- end -}}

You can see that it simplifies the work we have to do by inheriting the common ConfigMap definition which adds standard properties for ConfigMap. In our template we add the configuration, in this case the data key myvalue and its value. The configuration override the empty resource of the common ConfigMap. This is feasible because of the helper function mylibchart.util.merge we mentioned in the previous section.

To be able to use the common code, we need to add mylibchart as a dependency. Add the following to the end of the file mychart/Chart.yaml:

  1. # My common code in my library chart
  2. dependencies:
  3. - name: mylibchart
  4. version: 0.1.0
  5. repository: file://../mylibchart

This includes the library chart as a dynamic dependency from the filesystem which is at the same parent path as our application chart. As we are including the library chart as a dynamic dependency, we need to run helm dependency update. It will copy the library chart into your charts/ directory.

  1. $ helm dependency update mychart/
  2. Hang tight while we grab the latest from your chart repositories...
  3. ...Successfully got an update from the "stable" chart repository
  4. Update Complete. Happy Helming!⎈
  5. Saving 1 charts
  6. Deleting outdated charts

We are now ready to deploy our chart. Before installing, it is worth checking the rendered template first.

  1. $ helm install mydemo mychart/ --debug --dry-run
  2. install.go:159: [debug] Original chart version: ""
  3. install.go:176: [debug] CHART PATH: /root/test/helm-charts/mychart
  4. NAME: mydemo
  5. LAST DEPLOYED: Tue Mar 3 17:48:47 2020
  6. NAMESPACE: default
  7. STATUS: pending-install
  8. REVISION: 1
  9. TEST SUITE: None
  10. USER-SUPPLIED VALUES:
  11. {}
  12. COMPUTED VALUES:
  13. affinity: {}
  14. fullnameOverride: ""
  15. image:
  16. pullPolicy: IfNotPresent
  17. repository: nginx
  18. imagePullSecrets: []
  19. ingress:
  20. annotations: {}
  21. enabled: false
  22. hosts:
  23. - host: chart-example.local
  24. paths: []
  25. tls: []
  26. mylibchart:
  27. global: {}
  28. nameOverride: ""
  29. nodeSelector: {}
  30. podSecurityContext: {}
  31. replicaCount: 1
  32. resources: {}
  33. securityContext: {}
  34. service:
  35. port: 80
  36. type: ClusterIP
  37. serviceAccount:
  38. annotations: {}
  39. create: true
  40. name: null
  41. tolerations: []
  42. HOOKS:
  43. MANIFEST:
  44. ---
  45. # Source: mychart/templates/configmap.yaml
  46. apiVersion: v1
  47. data:
  48. myvalue: Hello World
  49. kind: ConfigMap
  50. metadata:
  51. labels:
  52. app: mychart
  53. chart: mychart-0.1.0
  54. release: mydemo
  55. name: mychart-mydemo

This looks like the ConfigMap we want with data override of myvalue: Hello World. Lets install it:

  1. $ helm install mydemo mychart/
  2. NAME: mydemo
  3. LAST DEPLOYED: Tue Mar 3 17:52:40 2020
  4. NAMESPACE: default
  5. STATUS: deployed
  6. REVISION: 1
  7. TEST SUITE: None

We can retrieve the release and see that the actual template was loaded.

  1. $ helm get manifest mydemo
  2. ---
  3. # Source: mychart/templates/configmap.yaml
  4. apiVersion: v1
  5. data:
  6. myvalue: Hello World
  7. kind: ConfigMap
  8. metadata:
  9. labels:
  10. app: mychart
  11. chart: mychart-0.1.0
  12. release: mydemo
  13. name: mychart-mydemo

Library Chart Benefits

Because of their inability to act as standalone charts, library charts can leverage the following functionality:

  • The .Files object references the file paths on the parent chart, rather than the path local to the library chart
  • The .Values object is the same as the parent chart, in contrast to application subcharts which receive the section of values configured under their header in the parent.

The Common Helm Helper Chart

  1. Note: The Common Helm Helper Chart repo on Github is no longer actively maintained, and the repo has been deprecated and archived.

This chart was the original pattern for common charts. It provides utilities that reflect best practices of Kubernetes chart development. Best of all it can be used off the bat by you when developing your charts to give you handy shared code.

Here is a quick way to use it. For more details, have a look at the README.

Create a scaffold chart again:

  1. $ helm create demo
  2. Creating demo

Lets use the common code from the helper chart. First, edit deployment demo/templates/deployment.yaml as follows:

  1. {{- template "common.deployment" (list . "demo.deployment") -}}
  2. {{- define "demo.deployment" -}}
  3. ## Define overrides for your Deployment resource here, e.g.
  4. apiVersion: apps/v1
  5. spec:
  6. replicas: {{ .Values.replicaCount }}
  7. selector:
  8. matchLabels:
  9. {{- include "demo.selectorLabels" . | nindent 6 }}
  10. template:
  11. metadata:
  12. labels:
  13. {{- include "demo.selectorLabels" . | nindent 8 }}
  14. {{- end -}}

And now the service file, demo/templates/service.yaml as follows:

  1. {{- template "common.service" (list . "demo.service") -}}
  2. {{- define "demo.service" -}}
  3. ## Define overrides for your Service resource here, e.g.
  4. # metadata:
  5. # labels:
  6. # custom: label
  7. # spec:
  8. # ports:
  9. # - port: 8080
  10. {{- end -}}

These templates show how inheriting the common code from the helper chart simplifies your coding down to your configuration or customization of the resources.

To be able to use the common code, we need to add common as a dependency. Add the following to the end of the file demo/Chart.yaml:

  1. dependencies:
  2. - name: common
  3. version: "^0.0.5"
  4. repository: "https://charts.helm.sh/incubator/"

Note: You will need to add the incubator repo to the Helm repository list (helm repo add).

As we are including the chart as a dynamic dependency, we need to run helm dependency update. It will copy the helper chart into your charts/ directory.

As helper chart is using some Helm 2 constructs, you will need to add the following to demo/values.yaml to enable the nginx image to be loaded as this was updated in Helm 3 scaffold chart:

  1. image:
  2. tag: 1.16.0

You can test that the chart templates are correct prior to deploying using the helm lint and helm template commands.

If it’s good to go, deploy away using helm install!