You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
helm/docs/charts.md

23 KiB

Charts

Helm uses a packaging format called charts. A chart is a collection of files that describe a related set of Kubernetes resources. A single chart might be used 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 they can be packaged into versioned archives to be deployed.

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

The Chart File Structure

A chart is organized as a collection of files inside of a directory. The directory 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:

wordpress/
  Chart.yaml          # A YAML file containing information about the chart
  LICENSE             # OPTIONAL: A plain text file containing the license for the chart
  README.md           # OPTIONAL: A human-readable README file
  values.yaml         # The default configuration values for this chart
  charts/             # OPTIONAL: A directory containing any charts upon which this chart depends.
  templates/          # OPTIONAL: A directory of templates that, when combined with values,
                      # will generate valid Kubernetes manifest files.
  templates/NOTES.txt # OPTIONAL: A plain text file containing short usage notes

Helm will silently strip out any other files.

The Chart.yaml File

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

name: The name of the chart (required)
version: A SemVer 2 version (required)
description: A single-sentence description of this project (optional)
keywords:
  - A list of keywords about this project (optional)
home: The URL of this project's home page (optional)
sources:
  - A list of URLs to source code for this project (optional)
maintainers: # (optional)
  - name: The maintainer's name (required for each maintainer)
    email: The maintainer's email (optional for each maintainer)
engine: gotpl # The name of the template engine (optional, defaults to gotpl)
icon: A URL to an SVG or PNG image to be used as an icon (optional).

If you are familiar with the Chart.yaml file format for Helm Classic, you will notice that fields specifying dependencies have been removed. That is because the new Chart format expresses dependencies using the charts/ directory.

Other fields will be silently ignored.

Charts and Versioning

Every chart must have a version number. A version must follow the SemVer 2 standard. Unlike Helm Classic, Kubernetes Helm uses version numbers as release markers. Packages in repositories are identified by name plus version.

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

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 the system.

NOTE: Whereas Helm Classic and Deployment Manager were both very GitHub oriented when it came to charts, Kubernetes Helm does not rely upon or require GitHub or even Git. Consequently, it does not use Git SHAs for versioning at all.

The version field inside of the Chart.yaml is used by many of the Helm tools, including the CLI and the Tiller server. When generating a package, the helm package command will use the version that it finds in the Chart.yaml as a token in the package name. The system assumes that the version number in the chart package name matches the version number in the Chart.yaml. Failure to meet this assumption will cause an error.

Chart LICENSE, README and NOTES

Charts can also contain files that describe the installation, configuration, usage and license of a chart. A README for a chart should be formatted in Markdown (README.md), and should generally 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 or configuration of the chart

The chart can also contain a short plain text templates/NOTES.txt file that will be printed out after installation, and when viewing the status of a release. This file is evaluated as a template, and can be used to display usage notes, next steps, or any other information relevant to a release of the chart. For example, instructions could be provided for connecting to a database, or accessing a web UI. Since this file is printed to STDOUT when running helm install or helm status, it is recommended to keep the 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 dependencies are expressed 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 unpacked chart directory. But its name cannot start with _ or .. Such files are ignored by the chart loader.

Note: The dependencies: section of the Chart.yaml from Helm Classic has been completely removed.

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

wordpress:
  Chart.yaml
  requirements.yaml
  # ...
  charts/
    apache/
      Chart.yaml
      # ...
    mysql/
      Chart.yaml
      # ...

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

TIP: To drop a dependency into your charts/ directory, use the helm fetch command or use a requirements.yaml file

Managing Dependencies with requirements.yaml

While Helm will allow you to manually manage your dependencies, the preferred method of declaring dependencies is by using a requirements.yaml file inside of your chart.

A requirements.yaml file is a simple file for listing your dependencies.

dependencies:
  - name: apache
    version: 1.2.3
    repository: http://example.com/charts
  - name: mysql
    version: 3.2.1
    repository: http://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 you must also use helm repo add to add that repo locally.

Once you have a dependencies file, you can run helm dependency update and it will use your dependency file to download all of the specified charts into your charts/ directory for you.

$ helm dep up foochart
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "local" chart repository
...Successfully got an update from the "stable" chart repository
...Successfully got an update from the "example" chart repository
...Successfully got an update from the "another" chart repository
Update Complete. Happy Helming!
Saving 2 charts
Downloading apache from repo http://example.com/charts
Downloading mysql from repo http://another.example.com/charts

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

charts/
  apache-1.2.3.tgz
  mysql-3.2.1.tgz

Manging charts with requirements.yaml is a good way to easily keep charts updated, and also share requirements information throughout a team.

Templates and Values

By default, Helm Chart templates are written in the Go template language, with the addition of 50 or so add-on template functions. (In the future, Helm may support other template languages, like Python Jinja.)

All template files are stored in a chart's templates/ folder. When Helm renders the charts, it will pass every file in that directory through the template 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 be provided on the command line with helm install.

When a user supplies custom values, these values will override the values in the chart's values.yaml file.

Template Files

Template files follow the standard conventions for writing Go templates (see the text/template Go package documentation for details). An example template file might look something like this:

apiVersion: v1
kind: ReplicationController
metadata:
  name: deis-database
  namespace: deis
  labels:
    heritage: deis
spec:
  replicas: 1
  selector:
    app: deis-database
  template:
    metadata:
      labels:
        app: deis-database
    spec:
      serviceAccount: deis-database
      containers:
        - name: deis-database
          image: {{.Values.imageRegistry}}/postgres:{{.Values.dockerTag}}
          imagePullPolicy: {{.Values.pullPolicy}}
          ports:
            - containerPort: 5432
          env:
            - name: DATABASE_STORAGE
              value: {{default "minio" .Values.storage}}

The above example, based loosely on https://github.com/deis/charts, is a template for a Kubernetes replication controller. It can use the following four template values (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 or dictate parameters.

Predefined Values

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

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

  • Release.Name: The name of the release (not the chart)
  • Release.Time: The time the chart release was last updated. This will match the Last Released time on a Release object.
  • Release.Namespace: The namespace the chart was released to.
  • Release.Service: The service that conducted the release. Usually this is Tiller.
  • Chart: The contents of the Chart.yaml. Thus, the chart version is obtainable as Chart.Version and the maintainers are in Chart.Maintainers.
  • Files: A map-like object containing all non-special files in the chart. This will not give you access to templates, but will give you access to additional files that are present. Files can be accessed using {{index .Files "file.name"}} or using the {{.Files.Get name}} or {{.Files.GetString name}} functions. You can also access the contents of the file as []byte using {{.Files.GetBytes}}

NOTE: Any unknown Chart.yaml fields will be dropped. They will not be accessible inside of the Chart object. Thus, Chart.yaml cannot be used to pass arbitrarily structured data into the template.

Values files

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

imageRegistry: "quay.io/deis"
dockerTag: "latest"
pullPolicy: "alwaysPull"
storage: "s3"

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

$ helm install --values=myvals.yaml wordpress

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

storage: "gcs"

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

imageRegistry: "quay.io/deis"
dockerTag: "latest"
pullPolicy: "alwaysPull"
storage: "gcs"

Note that only the last field was overridden.

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

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

apiVersion: v1
kind: ReplicationController
metadata:
  name: deis-database
  namespace: deis
  labels:
    heritage: deis
spec:
  replicas: 1
  selector:
    app: deis-database
  template:
    metadata:
      labels:
        app: deis-database
    spec:
      serviceAccount: deis-database
      containers:
        - name: deis-database
          image: {{.Values.imageRegistry}}/postgres:{{.Values.dockerTag}}
          imagePullPolicy: {{.Values.pullPolicy}}
          ports:
            - containerPort: 5432
          env:
            - name: DATABASE_STORAGE
              value: {{default "minio" .Values.storage}}

Scope, Dependencies, and Values

Values files can declare values for the top-level chart, as well as for any of the charts that are included in that chart's charts/ directory. Or, to phrase it differently, a values file can supply values to the chart as well as to any of its dependencies. For example, the demonstration Wordpress chart above has both mysql and apache as dependencies. The values file could supply values to all of these components:

title: "My Wordpress Site" # Sent to the Wordpress template

mysql:
  max_connections: 100 # Sent to MySQL
  password: "secret"

apache:
  port: 8080 # Passed to Apache

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

Values are namespaced, but namespaces are pruned. So for the Wordpress chart, it can access the MySQL password field as .Values.mysql.password. But for the MySQL chart, the scope of the values has been reduced and the namespace prefix removed, 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 this modified version of the previous example:

title: "My Wordpress Site" # Sent to the Wordpress template

global:
  app: MyWordpress

mysql:
  max_connections: 100 # Sent to MySQL
  password: "secret"

apache:
  port: 8080 # Passed to Apache

The above adds a global section with the value app: MyWordpress. This value is 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 is regenerated like this:

title: "My Wordpress Site" # Sent to the Wordpress template

global:
  app: MyWordpress

mysql:
  global:
    app: MyWordpress
  max_connections: 100 # Sent to MySQL
  password: "secret"

apache:
  global:
    app: MyWordpress
  port: 8080 # Passed to Apache

This provides a way of sharing one top-level variable with all subcharts, which is 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 no way for a subchart to influence the values of the parent chart.

Global sections are restricted to only simple key/value pairs. They do not support nesting.

For example, the following is illegal and will not work:

global:
  foo:  # It is illegal to nest an object inside of global.
    bar: baz

References

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

Hooks

Helm provides a hook mechanism to allow chart developers to intervene at certain points in a release's life cycle. For example, you can use hooks to:

  • Load a ConfigMap or Secret during install before any other charts are loaded.
  • Execute a Job to backup up a database before installing a new chart, and then execute a second job after the upgrade in order to restore data.
  • Run a Job before deleting a release to gracefully take a service out of rotation before removing it.

Hooks work like regular templates, but they have special annotations that cause Helm to utilize them differently. In this section, we cover the basic usage pattern for hooks.

The Available Hooks

The following hooks are defined:

  • pre-install: Executes after templates are rendered, but before any resources are created in Kubernetes.
  • post-install: Executes after all resources are loaded into Kubernetes
  • pre-delete: Executes on a deletion request before any resources are deleted from Kubernetes.
  • post-delete: Executes on a deletion request after all of the release's resources have been deleted.
  • pre-upgrade: Executes on an upgrade request after templates are rendered, but before any resources are loaded into Kubernetes (e.g. before a kuberntes apply operation).
  • post-upgrade: Executes on an upgrade after all resources have been upgraded.

Hooks and the Release Lifecycle

Hooks allow you, the chart developer, an opportunity to perform operations at strategic points in a release lifecycle. For example, consider the lifecycle for a helm install. By default, the lifecycle looks like this:

  1. User runs helm install foo
  2. Chart is loaded into Tiller
  3. After some verification, Tiller renders the foo templates
  4. Tiller loads the resulting resources into Kubernetes
  5. Tiller returns the release name (and other data) to the client
  6. The client exits

Helm defines two hooks for the install lifecycle: pre-install and post-install. If the developer of the foo chart implements both hooks, the lifecycle is altered like this:

  1. User runs helm install foo
  2. Chart is loaded into Tiller
  3. After some verification, Tiller renders the foo templates
  4. Tiller executes the pre-install hook (loading hook resources into Kubernetes)
  5. Tiller waits until the hook is "Ready"
  6. Tiller loads the resulting resources into Kubernetes
  7. Tiller executes the post-install hook (loading hook resources)
  8. Tiller waits until the hook is "Ready"
  9. Tiller returns the release name (and other data) to the client
  10. The client exits

What does it mean to wait until a hook is ready? This depends on the resource declared in the hook. If the resources is a Job kind, Tiller will wait until the job successfully runs to completion. And if the job fails, the release will fail. This is a blocking operation, so the Helm client will pause while the Job is run.

For all other kinds, as soon as Kubernetes marks the resource as loaded (added or updated), the resource is considered "Ready". When many resources are declared in a hook, the resources are executed serially, but the order of their execution is not guaranteed.

Hook resources are unmanaged

The resources that a hook creates are not tracked or managed as part of the release. Once Tiller verifies that the hook has reached its ready state, it will leave the hook resource alone.

Practically speaking, this means that if you create resources in a hook, you cannot rely upon helm delete to remove the resources. To destroy such resources, you need to write code to perform this operation in a pre-delete or post-delete hook.

Writing a Hook

Hooks are just Kubernetes manfiest files with special annotations in the metadata section. Because they are template files, you can use all of the normal template features, including reading .Values, .Release, and .Template.

For example, this template, stored in templates/post-install-job.yaml, declares a job to be run on post-install:

apiVersion: batch/v1
kind: Job
metadata:
  name: "{{.Release.Name}}"
  labels:
    heritage: {{.Release.Service | quote }}
    release: {{.Release.Name | quote }}
    chart: "{{.Chart.Name}}-{{.Chart.Version}}"
  annotations:
    # This is what defines this resource as a hook. Without this line, the
    # job is considered part of the release.
    "helm.sh/hook": post-install
spec:
  template:
    metadata:
      name: "{{.Release.Name}}"
      labels:
        heritage: {{.Release.Service | quote }}
        release: {{.Release.Name | quote }}
        chart: "{{.Chart.Name}}-{{.Chart.Version}}"
    spec:
      restartPolicy: Never
      containers:
      - name: post-install-job
        image: "alpine:3.3"
        command: ["/bin/sleep","{{default "10" .Values.sleepyTime}}"]

What makes this template a hook is the annotation:

  annotations:
    "helm.sh/hook": post-install

One resource can implement multiple hooks:

  annotations:
    "helm.sh/hook": post-install,post-upgrade

Similarly, there is no limit to the number of different resources that may implement a given hook. For example, one could declare both a secret as a config map as a pre-install hook. It is important to keep in mind, though, that there are no ordering guarantees about hooks.

When subcharts declare hooks, those are also evaluated. There is no way for a top-level chart to disable the hooks declared by subcharts. And again, there is no guaranteed ordering.

Using Helm to Manage Charts

The helm tool has several commands for working with charts.

It can create a new chart for you:

$ helm create mychart
Created mychart/

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

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

You can also use helm to help you find issues with your chart's formatting or information:

$ helm lint mychart
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 to sharing charts, the preferred mechanism is a chart repository.

Any HTTP server that can serve YAML files and tar files and can answer GET requests 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 with website mode enabled, and S3 with website mode enabled.

A repository is characterized primarily by the presence of a special file called index.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 repository servers. This is because doing so would add substantial requirements to an implementing server, and thus raise the barrier for setting up a repository.