Charts

Helm uses a packaging format called charts. A chart is a collection of filesthat describe a related set of Kubernetes resources. A single chart might beused to deploy something simple, like a memcached pod, or something complex,like a full web app stack with HTTP servers, databases, caches, and so on.

Charts are created as files laid out in a particular directory tree, then theycan be packaged into versioned archives to be deployed.

This document explains the chart format, and provides basic guidance forbuilding charts with Helm.

The Chart File Structure

A chart is organized as a collection of files inside of a directory. Thedirectory name is the name of the chart (without versioning information). Thus,a chart describing WordPress would be stored in the wordpress/ directory.

Inside of this directory, Helm will expect a structure that matches this:

  1. wordpress/
  2. Chart.yaml # A YAML file containing information about the chart
  3. LICENSE # OPTIONAL: A plain text file containing the license for the chart
  4. README.md # OPTIONAL: A human-readable README file
  5. values.yaml # The default configuration values for this chart
  6. values.schema.json # OPTIONAL: A JSON Schema for imposing a structure on the values.yaml file
  7. charts/ # A directory containing any charts upon which this chart depends.
  8. crds/ # Custom Resource Definitions
  9. templates/ # A directory of templates that, when combined with values,
  10. # will generate valid Kubernetes manifest files.
  11. templates/NOTES.txt # OPTIONAL: A plain text file containing short usage notes

Helm reserves use of the charts/, crds/, and templates/ directories, andof the listed file names. Other files will be left as they are.

The Chart.yaml File

The Chart.yaml file is required for a chart. It contains the following fields:

  1. apiVersion: The chart API version (required)
  2. name: The name of the chart (required)
  3. version: A SemVer 2 version (required)
  4. kubeVersion: A SemVer range of compatible Kubernetes versions (optional)
  5. description: A single-sentence description of this project (optional)
  6. type: It is the type of chart (optional)
  7. keywords:
  8. - A list of keywords about this project (optional)
  9. home: The URL of this project's home page (optional)
  10. sources:
  11. - A list of URLs to source code for this project (optional)
  12. dependencies: # A list of the chart requirements (optional)
  13. - name: The name of the chart (nginx)
  14. version: The version of the chart ("1.2.3")
  15. repository: The repository URL ("https://example.com/charts")
  16. maintainers: # (optional)
  17. - name: The maintainer's name (required for each maintainer)
  18. email: The maintainer's email (optional for each maintainer)
  19. url: A URL for the maintainer (optional for each maintainer)
  20. icon: A URL to an SVG or PNG image to be used as an icon (optional).
  21. appVersion: The version of the app that this contains (optional). This needn't be SemVer.
  22. deprecated: Whether this chart is deprecated (optional, boolean)

Other fields will be silently ignored.

Charts and Versioning

Every chart must have a version number. A version must follow the SemVer2 standard. Unlike Helm Classic, Kubernetes Helm usesversion numbers as release markers. Packages in repositories are identified byname plus version.

For example, an nginx chart whose version field is set to version: 1.2.3will be named:

  1. nginx-1.2.3.tgz

More complex SemVer 2 names are also supported, such as version:1.2.3-alpha.1+ef365. But non-SemVer names are explicitly disallowed by thesystem.

NOTE: Whereas Helm Classic and Deployment Manager were both very GitHuboriented when it came to charts, Kubernetes Helm does not rely upon or requireGitHub or even Git. Consequently, it does not use Git SHAs for versioning atall.

The version field inside of the Chart.yaml is used by many of the Helmtools, including the CLI. When generating a package, the helm package commandwill use the version that it finds in the Chart.yaml as a token in the packagename. The system assumes that the version number in the chart package namematches the version number in the Chart.yaml. Failure to meet this assumptionwill cause an error.

The apiVersion Field

The apiVersion field should be v2 for Helm charts that require at leastHelm 3. Charts supporting previous Helm versions have an apiVersion setto v1 and are still installable by Helm 3.

Changes from v1 to v2: A dependencies field defining chart dependencies, which wherelocated in a separate requirements.yaml file for v1 charts(see Chart Dependencies). The type field, discriminating application and library charts(see Chart Types).

The appVersion Field

Note that the appVersion field is not related to the version field. It is away of specifying the version of the application. For example, the drupalchart may have an appVersion: 8.2.1, indicating that the version of Drupalincluded in the chart (by default) is 8.2.1. This field is informational, andhas no impact on chart version calculations.

Deprecating Charts

When managing charts in a Chart Repository, it is sometimes necessary todeprecate a chart. The optional deprecated field in Chart.yaml can be usedto mark a chart as deprecated. If the latest version of a chart in therepository is marked as deprecated, then the chart as a whole is considered tobe deprecated. The chart name can later be reused by publishing a newer versionthat is not marked as deprecated. The workflow for deprecating charts, asfollowed by the kubernetes/charts project is:- Update chart’s Chart.yaml to mark the chart as deprecated, bumping theversion- Release the new chart version in the Chart Repository- Remove the chart from the source repository (e.g. git)

Chart Types

The type field defines the type of chart. There are two types: applicationand library. Application is the default type and it is the standard chartwhich can be operated on fully. The library or helperchart providesutilities or functions for the chart builder. A library chart differs from anapplication chart because it has no resource object and is therefore notinstallable.

Note: An application chart can be used as a library chart. This is enabledby setting the type to library. The chart will then be rendered as a librarychart where all utilities and functions can be leveraged. All resource objectsof the chart will not be rendered.

Chart LICENSE, README and NOTES

Charts can also contain files that describe the installation, configuration,usage and license of a chart.

A LICENSE is a plain text file containing thelicense for the chart. Thechart can contain a license as it may have programming logic in the templatesand would therefore not be configuration only. There can also be separatelicense(s) for the application installed by the chart, if required.

A README for a chart should be formatted in Markdown (README.md), and shouldgenerally contain:

  • A description of the application or service the chart provides
  • Any prerequisites or requirements to run the chart
  • Descriptions of options in values.yaml and default values
  • Any other information that may be relevant to the installation orconfiguration of the chartThe chart can also contain a short plain text templates/NOTES.txt file thatwill be printed out after installation, and when viewing the status of arelease. This file is evaluated as a template, and canbe used to display usage notes, next steps, or any other information relevant toa release of the chart. For example, instructions could be provided forconnecting to a database, or accessing a web UI. Since this file is printed toSTDOUT when running helm install or helm status, it is recommended to keepthe content brief and point to the README for greater detail.

Chart Dependencies

In Helm, one chart may depend on any number of other charts. These dependenciescan be dynamically linked using the dependencies field in Chart.yaml orbrought in to the charts/ directory and managed manually.

Managing Dependencies with the dependencies field

The charts required by the current chart are defined as a list in thedependencies field.

  1. dependencies:
  2. - name: apache
  3. version: 1.2.3
  4. repository: https://example.com/charts
  5. - name: mysql
  6. version: 3.2.1
  7. repository: https://another.example.com/charts
  • The name field is the name of the chart you want.
  • The version field is the version of the chart you want.
  • The repository field is the full URL to the chart repository. Note that youmust also use helm repo add to add that repo locally.Once you have defined dependencies, you can run helm dependency update and itwill use your dependency file to download all the specified charts into yourcharts/ directory for you.
  1. $ helm dep up foochart
  2. Hang tight while we grab the latest from your chart repositories...
  3. ...Successfully got an update from the "local" chart repository
  4. ...Successfully got an update from the "stable" chart repository
  5. ...Successfully got an update from the "example" chart repository
  6. ...Successfully got an update from the "another" chart repository
  7. Update Complete. Happy Helming!
  8. Saving 2 charts
  9. Downloading apache from repo https://example.com/charts
  10. Downloading mysql from repo https://another.example.com/charts

When helm dependency update retrieves charts, it will store them as chartarchives in the charts/ directory. So for the example above, one would expectto see the following files in the charts directory:

  1. charts/
  2. apache-1.2.3.tgz
  3. mysql-3.2.1.tgz

Alias field in dependencies

In addition to the other fields above, each requirements entry may contain theoptional field alias.

Adding an alias for a dependency chart would put a chart in dependencies usingalias as name of new dependency.

One can use alias in cases where they need to access a chart with othername(s).

  1. # parentchart/Chart.yaml
  2. dependencies:
  3. - name: subchart
  4. repository: http://localhost:10191
  5. version: 0.1.0
  6. alias: new-subchart-1
  7. - name: subchart
  8. repository: http://localhost:10191
  9. version: 0.1.0
  10. alias: new-subchart-2
  11. - name: subchart
  12. repository: http://localhost:10191
  13. version: 0.1.0

In the above example we will get 3 dependencies in all for parentchart

  1. subchart
  2. new-subchart-1
  3. new-subchart-2

The manual way of achieving this is by copy/pasting the same chart in thecharts/ directory multiple times with different names.

Tags and Condition fields in dependencies

In addition to the other fields above, each requirements entry may contain theoptional fields tags and condition.

All charts are loaded by default. If tags or condition fields are present,they will be evaluated and used to control loading for the chart(s) they areapplied to.

Condition - The condition field holds one or more YAML paths (delimited bycommas). If this path exists in the top parent’s values and resolves to aboolean value, the chart will be enabled or disabled based on that booleanvalue. Only the first valid path found in the list is evaluated and if no pathsexist then the condition has no effect.

Tags - The tags field is a YAML list of labels to associate with this chart. Inthe top parent’s values, all charts with tags can be enabled or disabled byspecifying the tag and a boolean value.

  1. # parentchart/Chart.yaml
  2. dependencies:
  3. - name: subchart1
  4. repository: http://localhost:10191
  5. version: 0.1.0
  6. condition: subchart1.enabled, global.subchart1.enabled
  7. tags:
  8. - front-end
  9. - subchart1
  10. - name: subchart2
  11. repository: http://localhost:10191
  12. version: 0.1.0
  13. condition: subchart2.enabled,global.subchart2.enabled
  14. tags:
  15. - back-end
  16. - subchart2
  1. # parentchart/values.yaml
  2. subchart1:
  3. enabled: true
  4. tags:
  5. front-end: false
  6. back-end: true

In the above example all charts with the tag front-end would be disabled butsince the subchart1.enabled path evaluates to ‘true’ in the parent’s values,the condition will override the front-end tag and subchart1 will be enabled.

Since subchart2 is tagged with back-end and that tag evaluates to true,subchart2 will be enabled. Also notes that although subchart2 has acondition specified, there is no corresponding path and value in the parent’svalues so that condition has no effect.

Using the CLI with Tags and Conditions

The —set parameter can be used as usual to alter tag and condition values.

  1. helm install --set tags.front-end=true --set subchart2.enabled=false
Tags and Condition Resolution
  • Conditions (when set in values) always override tags. The firstcondition path that exists wins and subsequent ones for that chart areignored.
  • Tags are evaluated as ‘if any of the chart’s tags are true then enable thechart’.
  • Tags and conditions values must be set in the top parent’s values.
  • The tags: key in values must be a top level key. Globals and nestedtags: tables are not currently supported.

Importing Child Values via dependencies

In some cases it is desirable to allow a child chart’s values to propagate tothe parent chart and be shared as common defaults. An additional benefit ofusing the exports format is that it will enable future tooling to introspectuser-settable values.

The keys containing the values to be imported can be specified in the parentchart’s dependencies in the field input-values using a YAML list. Each itemin the list is a key which is imported from the child chart’s exports field.

To import values not contained in the exports key, use thechild-parent format. Examples of both formatsare described below.

Using the exports format

If a child chart’s values.yaml file contains an exports field at the root,its contents may be imported directly into the parent’s values by specifying thekeys to import as in the example below:

  1. # parent's Chart.yaml file
  2. dependencies:
  3. - name: subchart
  4. repository: http://localhost:10191
  5. version: 0.1.0
  6. import-values:
  7. - data
  1. # child's values.yaml file
  2. ...
  3. exports:
  4. data:
  5. myint: 99

Since we are specifying the key data in our import list, Helm looks in theexports field of the child chart for data key and imports its contents.

The final parent values would contain our exported field:

  1. # parent's values file
  2. ...
  3. myint: 99

Please note the parent key data is not contained in the parent’s final values.If you need to specify the parent key, use the ‘child-parent’ format.

Using the child-parent format

To access values that are not contained in the exports key of the childchart’s values, you will need to specify the source key of the values to beimported (child) and the destination path in the parent chart’s values(parent).

The import-values in the example below instructs Helm to take any values foundat child: path and copy them to the parent’s values at the path specified inparent:

  1. # parent's Chart.yaml file
  2. dependencies:
  3. - name: subchart1
  4. repository: http://localhost:10191
  5. version: 0.1.0
  6. ...
  7. import-values:
  8. - child: default.data
  9. parent: myimports

In the above example, values found at default.data in the subchart1’s valueswill be imported to the myimports key in the parent chart’s values as detailedbelow:

  1. # parent's values.yaml file
  2. myimports:
  3. myint: 0
  4. mybool: false
  5. mystring: "helm rocks!"
  1. # subchart1's values.yaml file
  2. default:
  3. data:
  4. myint: 999
  5. mybool: true

The parent chart’s resulting values would be:

  1. # parent's final values
  2. myimports:
  3. myint: 999
  4. mybool: true
  5. mystring: "helm rocks!"

The parent’s final values now contains the myint and mybool fields importedfrom subchart1.

Managing Dependencies manually via the charts/ directory

If more control over dependencies is desired, these dependencies can beexpressed explicitly by copying the dependency charts into the charts/directory.

A dependency can be either a chart archive (foo-1.2.3.tgz) or an unpackedchart directory. But its name cannot start with _ or .. Such files areignored by the chart loader.

For example, if the WordPress chart depends on the Apache chart, the Apachechart (of the correct version) is supplied in the WordPress chart’s charts/directory:

  1. wordpress:
  2. Chart.yaml
  3. # ...
  4. charts/
  5. apache/
  6. Chart.yaml
  7. # ...
  8. mysql/
  9. Chart.yaml
  10. # ...

The example above shows how the WordPress chart expresses its dependency onApache and MySQL by including those charts inside of its charts/ directory.

TIP:To drop a dependency into your charts/ directory, use the helmpull command

Operational aspects of using dependencies

The above sections explain how to specify chart dependencies, but how does thisaffect chart installation using helm install and helm upgrade?

Suppose that a chart named “A” creates the following Kubernetes objects

  • namespace “A-Namespace”
  • statefulset “A-StatefulSet”
  • service “A-Service”Furthermore, A is dependent on chart B that creates objects

  • namespace “B-Namespace”

  • replicaset “B-ReplicaSet”
  • service “B-Service”After installation/upgrade of chart A a single Helm release is created/modified.The release will create/update all of the above Kubernetes objects in thefollowing order:

  • A-Namespace

  • B-Namespace
  • A-StatefulSet
  • B-ReplicaSet
  • A-Service
  • B-ServiceThis is because when Helm installs/upgrades charts, the Kubernetes objects fromthe charts and all its dependencies are

  • aggregrated into a single set; then

  • sorted by type followed by name; and then
  • created/updated in that order.Hence a single release is created with all the objects for the chart and itsdependencies.

The install order of Kubernetes types is given by the enumeration InstallOrderin kind_sorter.go (see the Helm sourcefile).

Templates and Values

Helm Chart templates are written in the Go templatelanguage, with the addition of 50 or soadd-on template functions from the Spriglibrary and a few other specializedfunctions.

All template files are stored in a chart’s templates/ folder. When Helmrenders the charts, it will pass every file in that directory through thetemplate engine.

Values for the templates are supplied two ways:

  • Chart developers may supply a file called values.yaml inside of a chart.This file can contain default values.
  • Chart users may supply a YAML file that contains values. This can beprovided on the command line with helm install.When a user supplies custom values, these values will override the values in thechart’s values.yaml file.

Template Files

Template files follow the standard conventions for writing Go templates (seethe text/template Go packagedocumentation for details). An exampletemplate file might look something like this:

  1. apiVersion: v1
  2. kind: ReplicationController
  3. metadata:
  4. name: deis-database
  5. namespace: deis
  6. labels:
  7. app.kubernetes.io/managed-by: deis
  8. spec:
  9. replicas: 1
  10. selector:
  11. app.kubernetes.io/name: deis-database
  12. template:
  13. metadata:
  14. labels:
  15. app.kubernetes.io/name: deis-database
  16. spec:
  17. serviceAccount: deis-database
  18. containers:
  19. - name: deis-database
  20. image: {{ .Values.imageRegistry }}/postgres:{{ .Values.dockerTag }}
  21. imagePullPolicy: {{ .Values.pullPolicy }}
  22. ports:
  23. - containerPort: 5432
  24. env:
  25. - name: DATABASE_STORAGE
  26. value: {{ default "minio" .Values.storage }}

The above example, based loosely onhttps://github.com/deis/charts, is a templatefor a Kubernetes replication controller. It can use the following four templatevalues (usually defined in a values.yaml file):

  • imageRegistry: The source registry for the Docker image.
  • dockerTag: The tag for the docker image.
  • pullPolicy: The Kubernetes pull policy.
  • storage: The storage backend, whose default is set to "minio"All of these values are defined by the template author. Helm does not require ordictate parameters.

To see many working charts, check out the Kubernetes Chartsproject

Predefined Values

Values that are supplied via a values.yaml file (or via the —set flag) areaccessible from the .Values object in a template. But there are otherpre-defined pieces of data you can access in your templates.

The following values are pre-defined, are available to every template, andcannot be overridden. As with all values, the names are case sensitive.

  • Release.Name: The name of the release (not the chart)
  • Release.Namespace: The namespace the chart was released to.
  • Release.Service: The service that conducted the release.
  • Release.IsUpgrade: This is set to true if the current operation is anupgrade or rollback.
  • Release.IsInstall: This is set to true if the current operation is aninstall.
  • Chart: The contents of the Chart.yaml. Thus, the chart version isobtainable as Chart.Version and the maintainers are in Chart.Maintainers.
  • Files: A map-like object containing all non-special files in the chart. Thiswill not give you access to templates, but will give you access to additionalfiles that are present (unless they are excluded using .helmignore). Filescan be accessed using {{ index .Files "file.name" }} or using the {{.Files.Get name }} or {{ .Files.GetString name }} functions. You can alsoaccess the contents of the file as []byte using {{ .Files.GetBytes }}
  • Capabilities: A map-like object that contains information about the versionsof Kubernetes ({{ .Capabilities.KubeVersion }} and the supported KubernetesAPI versions ({{ .Capabilities.APIVersions.Has "batch/v1" }})NOTE: Any unknown Chart.yaml fields will be dropped. They will not beaccessible inside of the Chart object. Thus, Chart.yaml cannot be used to passarbitrarily structured data into the template. The values file can be used forthat, though.

Values files

Considering the template in the previous section, a values.yaml file thatsupplies the necessary values would look like this:

  1. imageRegistry: "quay.io/deis"
  2. dockerTag: "latest"
  3. pullPolicy: "Always"
  4. storage: "s3"

A values file is formatted in YAML. A chart may include a default values.yamlfile. The Helm install command allows a user to override values by supplyingadditional YAML values:

  1. $ helm install --values=myvals.yaml wordpress

When values are passed in this way, they will be merged into the default valuesfile. For example, consider a myvals.yaml file that looks like this:

  1. storage: "gcs"

When this is merged with the values.yaml in the chart, the resulting generatedcontent will be:

  1. imageRegistry: "quay.io/deis"
  2. dockerTag: "latest"
  3. pullPolicy: "Always"
  4. storage: "gcs"

Note that only the last field was overridden.

NOTE: The default values file included inside of a chart must be namedvalues.yaml. But files specified on the command line can be named anything.

NOTE: If the —set flag is used on helm install or helm upgrade, thosevalues are simply converted to YAML on the client side.

NOTE: If any required entries in the values file exist, they can be declaredas required in the chart template by using the ‘required’function

Any of these values are then accessible inside of templates using the .Valuesobject:

  1. apiVersion: v1
  2. kind: ReplicationController
  3. metadata:
  4. name: deis-database
  5. namespace: deis
  6. labels:
  7. app.kubernetes.io/managed-by: deis
  8. spec:
  9. replicas: 1
  10. selector:
  11. app.kubernetes.io/name: deis-database
  12. template:
  13. metadata:
  14. labels:
  15. app.kubernetes.io/name: deis-database
  16. spec:
  17. serviceAccount: deis-database
  18. containers:
  19. - name: deis-database
  20. image: {{ .Values.imageRegistry }}/postgres:{{ .Values.dockerTag }}
  21. imagePullPolicy: {{ .Values.pullPolicy }}
  22. ports:
  23. - containerPort: 5432
  24. env:
  25. - name: DATABASE_STORAGE
  26. value: {{ default "minio" .Values.storage }}

Scope, Dependencies, and Values

Values files can declare values for the top-level chart, as well as for any ofthe charts that are included in that chart’s charts/ directory. Or, to phraseit differently, a values file can supply values to the chart as well as to anyof its dependencies. For example, the demonstration WordPress chart above hasboth mysql and apache as dependencies. The values file could supply valuesto all of these components:

  1. title: "My WordPress Site" # Sent to the WordPress template
  2. mysql:
  3. max_connections: 100 # Sent to MySQL
  4. password: "secret"
  5. apache:
  6. port: 8080 # Passed to Apache

Charts at a higher level have access to all of the variables defined beneath. Sothe WordPress chart can access the MySQL password as .Values.mysql.password.But lower level charts cannot access things in parent charts, so MySQL will notbe able to access the title property. Nor, for that matter, can it accessapache.port.

Values are namespaced, but namespaces are pruned. So for the WordPress chart, itcan access the MySQL password field as .Values.mysql.password. But for theMySQL chart, the scope of the values has been reduced and the namespace prefixremoved, so it will see the password field simply as .Values.password.

Global Values

As of 2.0.0-Alpha.2, Helm supports special “global” value. Consider thismodified version of the previous example:

  1. title: "My WordPress Site" # Sent to the WordPress template
  2. global:
  3. app: MyWordPress
  4. mysql:
  5. max_connections: 100 # Sent to MySQL
  6. password: "secret"
  7. apache:
  8. port: 8080 # Passed to Apache

The above adds a global section with the value app: MyWordPress. This valueis available to all charts as .Values.global.app.

For example, the mysql templates may access app as {{ .Values.global.app}}, and so can the apache chart. Effectively, the values file above isregenerated like this:

  1. title: "My WordPress Site" # Sent to the WordPress template
  2. global:
  3. app: MyWordPress
  4. mysql:
  5. global:
  6. app: MyWordPress
  7. max_connections: 100 # Sent to MySQL
  8. password: "secret"
  9. apache:
  10. global:
  11. app: MyWordPress
  12. port: 8080 # Passed to Apache

This provides a way of sharing one top-level variable with all subcharts, whichis useful for things like setting metadata properties like labels.

If a subchart declares a global variable, that global will be passed downward(to the subchart’s subcharts), but not upward to the parent chart. There is noway for a subchart to influence the values of the parent chart.

Also, global variables of parent charts take precedence over the globalvariables from subcharts.

Schema Files

Sometimes, a chart maintainer might want to define a structure on their values.This can be done by defining a schema in the values.schema.json file. A schemais represented as a JSON Schema. It might looksomething like this:

  1. {
  2. "$schema": "https://json-schema.org/draft-07/schema#",
  3. "properties": {
  4. "image": {
  5. "description": "Container Image",
  6. "properties": {
  7. "repo": {
  8. "type": "string"
  9. },
  10. "tag": {
  11. "type": "string"
  12. }
  13. },
  14. "type": "object"
  15. },
  16. "name": {
  17. "description": "Service name",
  18. "type": "string"
  19. },
  20. "port": {
  21. "description": "Port",
  22. "minimum": 0,
  23. "type": "integer"
  24. },
  25. "protocol": {
  26. "type": "string"
  27. }
  28. },
  29. "required": [
  30. "protocol",
  31. "port"
  32. ],
  33. "title": "Values",
  34. "type": "object"
  35. }

This schema will be applied to the values to validate it. Validation occurs whenany of the following commands are invoked:

  • helm install
  • helm upgrade
  • helm lint
  • helm templateAn example of a values.yaml file that meets the requirements of this schemamight look something like this:
  1. name: frontend
  2. protocol: https
  3. port: 443

Note that the schema is applied to the final .Values object, and not just tothe values.yaml file. This means that the following yaml file is valid,given that the chart is installed with the appropriate —set option shownbelow.

  1. name: frontend
  2. protocol: https
  1. helm install --set port=443

Furthermore, the final .Values object is checked against all subchartschemas. This means that restrictions on a subchart can’t be circumvented by aparent chart. This also works backwards - if a subchart has a requirement thatis not met in the subchart’s values.yaml file, the parent chart must satisfythose restrictions in order to be valid.

References

When it comes to writing templates, values, and schema files, there are severalstandard references that will help you out.

Custom Resource Definitions (CRDs)

Kubernetes provides a mechanism for declaring new types of Kubernetes objects.Using CustomResourceDefinitions (CRDs), Kubernetes developers can declare customresource types.

In Helm 3, CRDs are treated as a special kind of object. They are installedbefore the rest of the chart, and are subject to some limitations.

CRD YAML files should be placed in the crds/ directory inside of a chart.Multiple CRDs (separated by YAML start and end markers) may be placed in thesame file. Helm will attempt to load all of the files in the CRD directoryinto Kubernetes.

CRD files cannot be templated. They must be plain YAML documents.

When Helm installs a new chart, it will upload the CRDs, pause until the CRDsare made available by the API server, and then start the template engine, renderthe rest of the chart, and upload it to Kubernetes. Because of this ordering,CRD information is available in the .Capabilities object in Helm templates,and Helm templates may create new instances of objects that were declared inCRDs.

For example, if your chart had a CRD for CronTab in the crds/ directory, youmay create instances of the CronTab kind in the templates/ directory:

  1. crontabs/
  2. Chart.yaml
  3. crds/
  4. crontab.yaml
  5. templates/
  6. mycrontab.yaml

The crontab.yaml file must contain the CRD with no template directives:

  1. kind: CustomResourceDefinition
  2. metadata:
  3. name: crontabs.stable.example.com
  4. spec:
  5. group: stable.example.com
  6. versions:
  7. - name: v1
  8. served: true
  9. storage: true
  10. scope: Namespaced
  11. names:
  12. plural: crontabs
  13. singular: crontab
  14. kind: CronTab

Then the template mycrontab.yaml may create a new CronTab (using templatesas usual):

  1. apiVersion: stable.example.com
  2. kind: CronTab
  3. metadata:
  4. name: {{ .Values.name }}
  5. spec:
  6. # ...

Helm will make sure that the CronTab kind has been installed and is availablefrom the Kubernetes API server before it proceeds installing the things intemplates/.

Limitations on CRDs

Unlike most objects in Kubernetes, CRDs are installed globally. For that reason,Helm takes a very cautious approach in managing CRDs. CRDs are subject to thefollowing limitations:

  • CRDs are never reinstalled. If Helm determines that the CRDs in the crds/directory are already present (regardless of version), Helm will not attemptto install or upgrade.
  • CRDs are never installed on upgrade or rollback. Helm will only create CRDs oninstallation operations.
  • CRDs are never deleted. Deleting a CRD automatically deletes all of the CRD’scontents across all namespaces in the cluster. Consequently, Helm will notdelete CRDs.Operators who want to upgrade or delete CRDs are encouraged to do this manuallyand with great care.

Using Helm to Manage Charts

The helm tool has several commands for working with charts.

It can create a new chart for you:

  1. $ helm create mychart
  2. Created mychart/

Once you have edited a chart, helm can package it into a chart archive foryou:

  1. $ helm package mychart
  2. Archived mychart-0.1.-.tgz

You can also use helm to help you find issues with your chart’s formatting orinformation:

  1. $ helm lint mychart
  2. No issues found

Chart Repositories

A chart repository is an HTTP server that houses one or more packaged charts.While helm can be used to manage local chart directories, when it comes tosharing charts, the preferred mechanism is a chart repository.

Any HTTP server that can serve YAML files and tar files and can answer GETrequests can be used as a repository server.

Helm comes with built-in package server for developer testing (helm serve).The Helm team has tested other servers, including Google Cloud Storage withwebsite mode enabled, and S3 with website mode enabled.

A repository is characterized primarily by the presence of a special file calledindex.yaml that has a list of all of the packages supplied by the repository,together with metadata that allows retrieving and verifying those packages.

On the client side, repositories are managed with the helm repo commands.However, Helm does not provide tools for uploading charts to remote repositoryservers. This is because doing so would add substantial requirements to animplementing server, and thus raise the barrier for setting up a repository.

Chart Starter Packs

The helm create command takes an optional —starter option that lets youspecify a “starter chart”.

Starters are just regular charts, but are located in$XDG_DATA_HOME/helm/starters. As a chart developer, you may author charts thatare specifically designed to be used as starters. Such charts should be designedwith the following considerations in mind:

  • The Chart.yaml will be overwritten by the generator.
  • Users will expect to modify such a chart’s contents, so documentation shouldindicate how users can do so.
  • All occurrences of <CHARTNAME> will be replaced with the specified chartname so that starter charts can be used as templates.Currently the only way to add a chart to $XDG_DATA_HOME/helm/starters is tomanually copy it there. In your chart’s documentation, you may want to explainthat process.