Merge pull request #5972 from bacongobbler/move-docs-to-helm-www

chore(docs): move docs to helm-www
pull/6083/head
Matthew Fisher 5 years ago committed by GitHub
commit da7b66fd16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

2
.gitignore vendored

@ -4,8 +4,6 @@
.idea/
.vimrc
.vscode/
/docs/helm
/docs/man
_dist/
bin/
vendor/

@ -10,4 +10,4 @@ couple of parameters.
The `values.yaml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -10,4 +10,4 @@ couple of parameters.
The `values.yaml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -10,4 +10,4 @@ couple of parameters.
The `values.yaml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -10,4 +10,4 @@ couple of parameters.
The `values.yaml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -6,4 +6,4 @@ couple of parameters.
The `values.yaml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -1,56 +0,0 @@
# The Kubernetes Helm Architecture
This document describes the Helm architecture at a high level.
## The Purpose of Helm
Helm is a tool for managing Kubernetes packages called _charts_. Helm
can do the following:
- Create new charts from scratch
- Package charts into chart archive (tgz) files
- Interact with chart repositories where charts are stored
- Install and uninstall charts into an existing Kubernetes cluster
- Manage the release cycle of charts that have been installed with Helm
For Helm, there are three important concepts:
1. The _chart_ is a bundle of information necessary to create an
instance of a Kubernetes application.
2. The _config_ contains configuration information that can be merged
into a packaged chart to create a releasable object.
3. A _release_ is a running instance of a _chart_, combined with a
specific _config_.
## Components
Helm is an executable which is implemented into two distinct parts:
**The Helm Client** is a command-line client for end users. The client
is responsible for the following:
- Local chart development
- Managing repositories
- Managing releases
- Interfacing with the Helm library
- Sending charts to be installed
- Requesting upgrading or uninstalling of existing releases
**The Helm Library** provides the logic for executing all Helm operations.
It interfaces with the Kubernetes API server and provides the following capability:
- Combining a chart and configuration to build a release
- Installing charts into Kubernetes, and providing the subsequent release object
- Upgrading and uninstalling charts by interacting with Kubernetes
The standalone Helm library encapsulates the Helm logic so that it can be leveraged by different clients.
## Implementation
The Helm client and library is written in the Go programming language.
The library uses the Kubernetes client library to communicate with Kubernetes. Currently,
that library uses REST+JSON. It stores information in Secrets located inside of Kubernetes.
It does not need its own database.
Configuration files are, when possible, written in YAML.

@ -1,21 +0,0 @@
# The Chart Best Practices Guide
This guide covers the Helm Team's considered best practices for creating charts.
It focuses on how charts should be structured.
We focus primarily on best practices for charts that may be publicly deployed.
We know that many charts are for internal-use only, and authors of such charts
may find that their internal interests override our suggestions here.
## Table of Contents
- [General Conventions](conventions.md): Learn about general chart conventions.
- [Values Files](values.md): See the best practices for structuring `values.yaml`.
- [Templates](templates.md): Learn some of the best techniques for writing templates.
- [Dependencies](requirements.md): Follow best practices for `dependencies` declared in `Chart.yaml`.
- [Labels and Annotations](labels.md): Helm has a _heritage_ of labeling and annotating.
- Kubernetes Resources:
- [Pods and Pod Specs](pods.md): See the best practices for working with pod specifications.
- [Role-Based Access Control](rbac.md): Guidance on creating and using service accounts, roles, and role bindings.
- [Third Party Resources](third_party_resources.md): Third Party Resources (TPRs) have their own associated best practices.

@ -1,39 +0,0 @@
# General Conventions
This part of the Best Practices Guide explains general conventions.
## Chart Names
Chart names should be lower case letters and numbers. Words _may_ be separated with dashes (-):
Examples:
```
drupal
nginx-lego
aws-cluster-autoscaler
```
Neither uppercase letters nor underscores should be used in chart names. Dots should not be used in chart names.
The directory that contains a chart MUST have the same name as the chart. Thus, the chart `nginx-lego` MUST be created in a directory called `nginx-lego/`. This is not merely a stylistic detail, but a requirement of the Helm Chart format.
## Version Numbers
Wherever possible, Helm uses [SemVer 2](http://semver.org) to represent version numbers. (Note that Docker image tags do not necessarily follow SemVer, and are thus considered an unfortunate exception to the rule.)
When SemVer versions are stored in Kubernetes labels, we conventionally alter the `+` character to an `_` character, as labels do not allow the `+` sign as a value.
## Formatting YAML
YAML files should be indented using _two spaces_ (and never tabs).
## Usage of the Words Helm and Chart
There are a few small conventions followed for using the words Helm and helm.
- Helm refers to the project, and is often used as an umbrella term
- `helm` refers to the client-side command
- The term 'chart' does not need to be capitalized, as it is not a proper noun.
When in doubt, use _Helm_ (with an uppercase 'H').

@ -1,37 +0,0 @@
# Custom Resource Definitions
This section of the Best Practices Guide deals with creating and using Custom Resource Definition
objects.
When working with Custom Resource Definitions (CRDs), it is important to distinguish
two different pieces:
- There is a declaration of a CRD. This is the YAML file that has the kind `CustomResourceDefinition`
- Then there are resources that _use_ the CRD. Say a CRD defines `foo.example.com/v1`. Any resource
that has `apiVersion: example.com/v1` and kind `Foo` is a resource that uses the CRD.
## Install a CRD Declaration Before Using the Resource
Helm is optimized to load as many resources into Kubernetes as fast as possible.
By design, Kubernetes can take an entire set of manifests and bring them all
online (this is called the reconciliation loop).
But there's a difference with CRDs.
For a CRD, the declaration must be registered before any resources of that CRDs
kind(s) can be used. And the registration process sometimes takes a few seconds.
### Method 1: Separate Charts
One way to do this is to put the CRD definition in one chart, and then put any
resources that use that CRD in _another_ chart.
In this method, each chart must be installed separately.
### Method 2: Pre-install Hooks
To package the two together, add a `pre-install` hook to the CRD definition so
that it is fully installed before the rest of the chart is executed.
Note that if you create the CRD with a `pre-install` hook, that CRD definition
will not be uninstalled when `helm uninstall` is run.

@ -1,36 +0,0 @@
# Labels and Annotations
This part of the Best Practices Guide discusses the best practices for using
labels and annotations in your chart.
## Is it a Label or an Annotation?
An item of metadata should be a label under the following conditions:
- It is used by Kubernetes to identify this resource
- It is useful to expose to operators for the purpose of querying the system.
For example, we suggest using `helm.sh/chart: NAME-VERSION` as a label so that operators
can conveniently find all of the instances of a particular chart to use.
If an item of metadata is not used for querying, it should be set as an annotation
instead.
Helm hooks are always annotations.
## Standard Labels
The following table defines common labels that Helm charts use. Helm itself never requires that a particular label be present. Labels that are marked REC
are recommended, and _should_ be placed onto a chart for global consistency. Those marked OPT are optional. These are idiomatic or commonly in use, but are not relied upon frequently for operational purposes.
Name|Status|Description
-----|------|----------
`app.kubernetes.io/name` | REC | This should be the app name, reflecting the entire app. Usually `{{ template "name" . }}` is used for this. This is used by many Kubernetes manifests, and is not Helm-specific.
`helm.sh/chart` | REC | This should be the chart name and version: `{{ .Chart.Name }}-{{ .Chart.Version \| replace "+" "_" }}`.
`app.kubernetes.io/managed-by` | REC | This should always be set to `{{ .Release.Service }}`. It is for finding all things managed by Tiller.
`app.kubernetes.io/instance` | REC | This should be the `{{ .Release.Name }}`. It aid in differentiating between different instances of the same application.
`app.kubernetes.io/version` | OPT | The version of the app and can be set to `{{ .Chart.AppVersion }}`.
`app.kubernetes.io/component` | OPT | This is a common label for marking the different roles that pieces may play in an application. For example, `app.kubernetes.io/component: frontend`.
`app.kubernetes.io/part-of` | OPT | When multiple charts or pieces of software are used together to make one application. For example, application software and a database to produce a website. This can be set to the top level application being supported.
You can find more information on the Kubernetes labels, prefixed with `app.kubernetes.io`, in the [Kubernetes documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/).

@ -1,69 +0,0 @@
# Pods and PodTemplates
This part of the Best Practices Guide discusses formatting the Pod and PodTemplate
portions in chart manifests.
The following (non-exhaustive) list of resources use PodTemplates:
- Deployment
- ReplicationController
- ReplicaSet
- DaemonSet
- StatefulSet
## Images
A container image should use a fixed tag or the SHA of the image. It should not use the tags `latest`, `head`, `canary`, or other tags that are designed to be "floating".
Images _may_ be defined in the `values.yaml` file to make it easy to swap out images.
```
image: {{ .Values.redisImage | quote }}
```
An image and a tag _may_ be defined in `values.yaml` as two separate fields:
```
image: "{{ .Values.redisImage }}:{{ .Values.redisTag }}"
```
## ImagePullPolicy
`helm create` sets the `imagePullPolicy` to `IfNotPresent` by default by doing the following in your `deployment.yaml`:
```yaml
imagePullPolicy: {{ .Values.image.pullPolicy }}
```
And `values.yaml`:
```yaml
pullPolicy: IfNotPresent
```
Similarly, Kubernetes defaults the `imagePullPolicy` to `IfNotPresent` if it is not defined at all. If you want a value other than `IfNotPresent`, simply update the value in `values.yaml` to your desired value.
## PodTemplates Should Declare Selectors
All PodTemplate sections should specify a selector. For example:
```yaml
selector:
matchLabels:
app.kubernetes.io/name: MyName
template:
metadata:
labels:
app.kubernetes.io/name: MyName
```
This is a good practice because it makes the relationship between the set and
the pod.
But this is even more important for sets like Deployment.
Without this, the _entire_ set of labels is used to select matching pods, and
this will break if you use labels that change, like version or release date.

@ -1,63 +0,0 @@
# Role-Based Access Control
This part of the Best Practices Guide discusses the creation and formatting of RBAC resources in chart manifests.
RBAC resources are:
- ServiceAccount (namespaced)
- Role (namespaced)
- ClusterRole
- RoleBinding (namespaced)
- ClusterRoleBinding
## YAML Configuration
RBAC and ServiceAccount configuration should happen under separate keys. They are separate things. Splitting these two concepts out in the YAML disambiguates them and make this clearer.
```yaml
rbac:
# Specifies whether RBAC resources should be created
create: true
serviceAccount:
# Specifies whether a ServiceAccount should be created
create: true
# The name of the ServiceAccount to use.
# If not set and create is true, a name is generated using the fullname template
name:
```
This structure can be extended for more complex charts that require multiple ServiceAccounts.
```yaml
serviceAccounts:
client:
create: true
name:
server:
create: true
name:
```
## RBAC Resources Should be Created by Default
`rbac.create` should be a boolean value controlling whether RBAC resources are created. The default should be `true`. Users who wish to manage RBAC access controls themselves can set this value to `false` (in which case see below).
## Using RBAC Resources
`serviceAccount.name` should set to the name of the ServiceAccount to be used by access-controlled resources created by the chart. If `serviceAccount.create` is true, then a ServiceAccount with this name should be created. If the name is not set, then a name is generated using the `fullname` template, If `serviceAccount.create` is false, then it should not be created, but it should still be associated with the same resources so that manually-created RBAC resources created later that reference it will function correctly. If `serviceAccount.create` is false and the name is not specified, then the default ServiceAccount is used.
The following helper template should be used for the ServiceAccount.
```yaml
{{/*
Create the name of the service account to use
*/}}
{{- define "mychart.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{ default (include "mychart.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}
```

@ -1,47 +0,0 @@
# Dependencies
This section of the guide covers best practices for `dependencies` declared in `Chart.yaml`.
## Versions
Where possible, use version ranges instead of pinning to an exact version. The suggested default is to use a patch-level version match:
```yaml
version: ~1.2.3
```
This will match version `1.2.3` and any patches to that release. In other words, `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
For the complete version matching syntax, please see the [semver documentation](https://github.com/Masterminds/semver#checking-version-constraints)
### Repository URLs
Where possible, use `https://` repository URLs, followed by `http://` URLs.
If the repository has been added to the repository index file, the repository name can be used as an alias of URL. Use `alias:` or `@` followed by repository names.
File URLs (`file://...`) are considered a "special case" for charts that are assembled by a fixed deployment pipeline. Charts that use `file://` are not allowed in the official Helm repository.
## Conditions and Tags
Conditions or tags should be added to any dependencies that _are optional_.
The preferred form of a condition is:
```yaml
condition: somechart.enabled
```
Where `somechart` is the chart name of the dependency.
When multiple subcharts (dependencies) together provide an optional or swappable feature, those charts should share the same tags.
For example, if both `nginx` and `memcached` together provided performance optimizations for the main app in the chart, and were required to both be present when that feature is enabled, then they might both have a
tags section like this:
```
tags:
- webaccelerator
```
This allows a user to turn that feature on and off with one tag.

@ -1,198 +0,0 @@
# Templates
This part of the Best Practices Guide focuses on templates.
## Structure of templates/
The templates directory should be structured as follows:
- Template files should have the extension `.yaml` if they produce YAML output. The
extension `.tpl` may be used for template files that produce no formatted content.
- Template file names should use dashed notation (`my-example-configmap.yaml`), not camelcase.
- Each resource definition should be in its own template file.
- Template file names should reflect the resource kind in the name. e.g. `foo-pod.yaml`,
`bar-svc.yaml`
## Names of Defined Templates
Defined templates (templates created inside a `{{ define }} ` directive) are
globally accessible. That means that a chart and all of its subcharts will have
access to all of the templates created with `{{ define }}`.
For that reason, _all defined template names should be namespaced._
Correct:
```yaml
{{- define "nginx.fullname" }}
{{/* ... */}}
{{ end -}}
```
Incorrect:
```yaml
{{- define "fullname" -}}
{{/* ... */}}
{{ end -}}
```
It is highly recommended that new charts are created via `helm create` command as the template names are automatically defined as per this best practice.
## Formatting Templates
Templates should be indented using _two spaces_ (never tabs).
Template directives should have whitespace after the opening braces and before the
closing braces:
Correct:
```
{{ .foo }}
{{ print "foo" }}
{{- print "bar" -}}
```
Incorrect:
```
{{.foo}}
{{print "foo"}}
{{-print "bar"-}}
```
Templates should chomp whitespace where possible:
```
foo:
{{- range .Values.items }}
{{ . }}
{{ end -}}
```
Blocks (such as control structures) may be indented to indicate flow of the template code.
```
{{ if $foo -}}
{{- with .Bar }}Hello{{ end -}}
{{- end -}}
```
However, since YAML is a whitespace-oriented language, it is often not possible for code indentation to follow that convention.
## Whitespace in Generated Templates
It is preferable to keep the amount of whitespace in generated templates to
a minimum. In particular, numerous blank lines should not appear adjacent to each
other. But occasional empty lines (particularly between logical sections) is
fine.
This is best:
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: example
labels:
first: first
second: second
```
This is okay:
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: example
labels:
first: first
second: second
```
But this should be avoided:
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: example
labels:
first: first
second: second
```
## Comments (YAML Comments vs. Template Comments)
Both YAML and Helm Templates have comment markers.
YAML comments:
```yaml
# This is a comment
type: sprocket
```
Template Comments:
```yaml
{{- /*
This is a comment.
*/ -}}
type: frobnitz
```
Template comments should be used when documenting features of a template, such as explaining a defined template:
```yaml
{{- /*
mychart.shortname provides a 6 char truncated version of the release name.
*/ -}}
{{ define "mychart.shortname" -}}
{{ .Release.Name | trunc 6 }}
{{- end -}}
```
Inside of templates, YAML comments may be used when it is useful for Helm users to (possibly) see the comments during debugging.
```
# This may cause problems if the value is more than 100Gi
memory: {{ .Values.maxMem | quote }}
```
The comment above is visible when the user runs `helm install --debug`, while
comments specified in `{{- /* */ -}}` sections are not.
## Use of JSON in Templates and Template Output
YAML is a superset of JSON. In some cases, using a JSON syntax can be more
readable than other YAML representations.
For example, this YAML is closer to the normal YAML method of expressing lists:
```yaml
arguments:
- "--dirname"
- "/foo"
```
But it is easier to read when collapsed into a JSON list style:
```yaml
arguments: ["--dirname", "/foo"]
```
Using JSON for increased legibility is good. However, JSON syntax should not
be used for representing more complex constructs.
When dealing with pure JSON embedded inside of YAML (such as init container
configuration), it is of course appropriate to use the JSON format.

@ -1,155 +0,0 @@
# Values
This part of the best practices guide covers using values. In this part of the
guide, we provide recommendations on how you should structure and use your
values, with focus on designing a chart's `values.yaml` file.
## Naming Conventions
Variables names should begin with a lowercase letter, and words should be
separated with camelcase:
Correct:
```yaml
chicken: true
chickenNoodleSoup: true
```
Incorrect:
```yaml
Chicken: true # initial caps may conflict with built-ins
chicken-noodle-soup: true # do not use hyphens in the name
```
Note that all of Helm's built-in variables begin with an uppercase letter to
easily distinguish them from user-defined values: `.Release.Name`,
`.Capabilities.KubeVersion`.
## Flat or Nested Values
YAML is a flexible format, and values may be nested deeply or flattened.
Nested:
```yaml
server:
name: nginx
port: 80
```
Flat:
```yaml
serverName: nginx
serverPort: 80
```
In most cases, flat should be favored over nested. The reason for this is that
it is simpler for template developers and users.
For optimal safety, a nested value must be checked at every level:
```
{{ if .Values.server }}
{{ default "none" .Values.server.name }}
{{ end }}
```
For every layer of nesting, an existence check must be done. But for flat
configuration, such checks can be skipped, making the template easier to read
and use.
```
{{ default "none" .Values.serverName }}
```
When there are a large number of related variables, and at least one of them
is non-optional, nested values may be used to improve readability.
## Make Types Clear
YAML's type coercion rules are sometimes counterintuitive. For example,
`foo: false` is not the same as `foo: "false"`. Large integers like `foo: 12345678`
will get converted to scientific notation in some cases.
The easiest way to avoid type conversion errors is to be explicit about strings,
and implicit about everything else. Or, in short, _quote all strings_.
Often, to avoid the integer casting issues, it is advantageous to store your
integers as strings as well, and use `{{ int $value }}` in the template to convert
from a string back to an integer.
In most cases, explicit type tags are respected, so `foo: !!string 1234` should
treat `1234` as a string. _However_, the YAML parser consumes tags, so the type
data is lost after one parse.
## Consider How Users Will Use Your Values
There are three potential sources of values:
- A chart's `values.yaml` file
- A values file supplied by `helm install -f` or `helm upgrade -f`
- The values passed to a `--set` or `--set-string` flag on `helm install` or `helm upgrade`
When designing the structure of your values, keep in mind that users of your
chart may want to override them via either the `-f` flag or with the `--set`
option.
Since `--set` is more limited in expressiveness, the first guidelines for writing
your `values.yaml` file is _make it easy to override from `--set`_.
For this reason, it's often better to structure your values file using maps.
Difficult to use with `--set`:
```yaml
servers:
- name: foo
port: 80
- name: bar
port: 81
```
The above cannot be expressed with `--set` in Helm `<=2.4`. In Helm 2.5, the
accessing the port on foo is `--set servers[0].port=80`. Not only is it harder
for the user to figure out, but it is prone to errors if at some later time the
order of the `servers` is changed.
Easy to use:
```yaml
servers:
foo:
port: 80
bar:
port: 81
```
Accessing foo's port is much more obvious: `--set servers.foo.port=80`.
## Document 'values.yaml'
Every defined property in 'values.yaml' should be documented. The documentation string should begin with the name of the property that it describes, and then give at least a one-sentence description.
Incorrect:
```
# the host name for the webserver
serverHost = example
serverPort = 9191
```
Correct:
```
# serverHost is the host name for the webserver
serverHost = example
# serverPort is the HTTP listener port for the webserver
serverPort = 9191
```
Beginning each comment with the name of the parameter it documents makes it easy to grep out documentation, and will enable documentation tools to reliably correlate doc strings with the parameters they describe.

@ -1,294 +0,0 @@
# The Chart Repository Guide
This section explains how to create and work with Helm chart repositories. At a
high level, a chart repository is a location where packaged charts can be
stored and shared.
The official chart repository is maintained by the
[Kubernetes Charts](https://github.com/helm/charts), and we welcome
participation. But Helm also makes it easy to create and run your own chart
repository. This guide explains how to do so.
## Prerequisites
* Go through the [Quickstart](quickstart.md) Guide
* Read through the [Charts](charts.md) document
## Create a chart repository
A _chart repository_ is an HTTP server that houses an `index.yaml` file and
optionally some packaged charts. When you're ready to share your charts, the
preferred way to do so is by uploading them to a chart repository.
**Note:** For Helm 2.0.0, chart repositories do not have any intrinsic
authentication. There is an [issue tracking progress](https://github.com/helm/helm/issues/1038)
in GitHub.
Because a chart repository can be any HTTP server that can serve YAML and tar
files and can answer GET requests, you have a plethora of options when it comes
down to hosting your own chart repository. For example, you can use a Google
Cloud Storage (GCS) bucket, Amazon S3 bucket, Github Pages, or even create your
own web server.
### The chart repository structure
A chart repository consists of packaged charts and a special file called
`index.yaml` which contains an index of all of the charts in the repository.
Frequently, the charts that `index.yaml` describes are also hosted on the same
server, as are the [provenance files](provenance.md).
For example, the layout of the repository `https://example.com/charts` might
look like this:
```
charts/
|
|- index.yaml
|
|- alpine-0.1.2.tgz
|
|- alpine-0.1.2.tgz.prov
```
In this case, the index file would contain information about one chart, the Alpine
chart, and provide the download URL `https://example.com/charts/alpine-0.1.2.tgz`
for that chart.
It is not required that a chart package be located on the same server as the
`index.yaml` file. However, doing so is often the easiest.
### The index file
The index file is a yaml file called `index.yaml`. It
contains some metadata about the package, including the contents of a
chart's `Chart.yaml` file. A valid chart repository must have an index file. The
index file contains information about each chart in the chart repository. The
`helm repo index` command will generate an index file based on a given local
directory that contains packaged charts.
This is an example of an index file:
```
apiVersion: v1
entries:
alpine:
- created: 2016-10-06T16:23:20.499814565-06:00
description: Deploy a basic Alpine Linux pod
digest: 99c76e403d752c84ead610644d4b1c2f2b453a74b921f422b9dcb8a7c8b559cd
home: https://helm.sh/helm
name: alpine
sources:
- https://github.com/helm/helm
urls:
- https://technosophos.github.io/tscharts/alpine-0.2.0.tgz
version: 0.2.0
- created: 2016-10-06T16:23:20.499543808-06:00
description: Deploy a basic Alpine Linux pod
digest: 515c58e5f79d8b2913a10cb400ebb6fa9c77fe813287afbacf1a0b897cd78727
home: https://helm.sh/helm
name: alpine
sources:
- https://github.com/helm/helm
urls:
- https://technosophos.github.io/tscharts/alpine-0.1.0.tgz
version: 0.1.0
nginx:
- created: 2016-10-06T16:23:20.499543808-06:00
description: Create a basic nginx HTTP server
digest: aaff4545f79d8b2913a10cb400ebb6fa9c77fe813287afbacf1a0b897cdffffff
home: https://helm.sh/helm
name: nginx
sources:
- https://github.com/helm/charts
urls:
- https://technosophos.github.io/tscharts/nginx-1.1.0.tgz
version: 1.1.0
generated: 2016-10-06T16:23:20.499029981-06:00
```
A generated index and packages can be served from a basic webserver. You can test
things out locally with the `helm serve` command, which starts a local server.
```console
$ helm serve --repo-path ./charts
Regenerating index. This may take a moment.
Now serving you on 127.0.0.1:8879
```
The above starts a local webserver, serving the charts it finds in `./charts`. The
serve command will automatically generate an `index.yaml` file for you during
startup.
## Hosting Chart Repositories
This part shows several ways to serve a chart repository.
### Google Cloud Storage
The first step is to **create your GCS bucket**. We'll call ours
`fantastic-charts`.
![Create a GCS Bucket](images/create-a-bucket.png)
Next, make your bucket public by **editing the bucket permissions**.
![Edit Permissions](images/edit-permissions.png)
Insert this line item to **make your bucket public**:
![Make Bucket Public](images/make-bucket-public.png)
Congratulations, now you have an empty GCS bucket ready to serve charts!
You may upload your chart repository using the Google Cloud Storage command line
tool, or using the GCS web UI. This is the technique the official Kubernetes
Charts repository hosts its charts, so you may want to take a
[peek at that project](https://github.com/helm/charts) if you get stuck.
**Note:** A public GCS bucket can be accessed via simple HTTPS at this address
`https://bucket-name.storage.googleapis.com/`.
### JFrog Artifactory
You can also set up chart repositories using JFrog Artifactory.
Read more about chart repositories with JFrog Artifactory [here](https://www.jfrog.com/confluence/display/RTF/Helm+Chart+Repositories)
### Github Pages example
In a similar way you can create charts repository using GitHub Pages.
GitHub allows you to serve static web pages in two different ways:
- By configuring a project to serve the contents of its `docs/` directory
- By configuring a project to serve a particular branch
We'll take the second approach, though the first is just as easy.
The first step will be to **create your gh-pages branch**. You can do that
locally as.
```console
$ git checkout -b gh-pages
```
Or via web browser using **Branch** button on your Github repository:
![Create Github Pages branch](images/create-a-gh-page-button.png)
Next, you'll want to make sure your **gh-pages branch** is set as Github Pages,
click on your repo **Settings** and scroll down to **Github pages** section and
set as per below:
![Create Github Pages branch](images/set-a-gh-page.png)
By default **Source** usually gets set to **gh-pages branch**. If this is not set by default, then select it.
You can use a **custom domain** there if you wish so.
And check that **Enforce HTTPS** is ticked, so the **HTTPS** will be used when
charts are served.
In such setup you can use **master branch** to store your charts code, and
**gh-pages branch** as charts repository, e.g.:
`https://USERNAME.github.io/REPONAME`. The demonstration [TS Charts](https://github.com/technosophos/tscharts)
repository is accessible at `https://technosophos.github.io/tscharts/`.
### Ordinary web servers
To configure an ordinary web server to serve Helm charts, you merely need to do
the following:
- Put your index and charts in a directory that the server can serve
- Make sure the `index.yaml` file can be accessed with no authentication requirement
- Make sure `yaml` files are served with the correct content type (`text/yaml` or
`text/x-yaml`)
For example, if you want to serve your charts out of `$WEBROOT/charts`, make sure
there is a `charts/` directory in your web root, and put the index file and
charts inside of that folder.
## Managing Chart Repositories
Now that you have a chart repository, the last part of this guide explains how
to maintain charts in that repository.
### Store charts in your chart repository
Now that you have a chart repository, let's upload a chart and an index file to
the repository. Charts in a chart repository must be packaged
(`helm package chart-name/`) and versioned correctly (following
[SemVer 2](https://semver.org/) guidelines).
These next steps compose an example workflow, but you are welcome to use
whatever workflow you fancy for storing and updating charts in your chart
repository.
Once you have a packaged chart ready, create a new directory, and move your
packaged chart to that directory.
```console
$ helm package docs/examples/alpine/
$ mkdir fantastic-charts
$ mv alpine-0.1.0.tgz fantastic-charts/
$ helm repo index fantastic-charts --url https://fantastic-charts.storage.googleapis.com
```
The last command takes the path of the local directory that you just created and
the URL of your remote chart repository and composes an `index.yaml` file inside the
given directory path.
Now you can upload the chart and the index file to your chart repository using
a sync tool or manually. If you're using Google Cloud Storage, check out this
[example workflow](chart_repository_sync_example.md) using the gsutil client. For
GitHub, you can simply put the charts in the appropriate destination branch.
### Add new charts to an existing repository
Each time you want to add a new chart to your repository, you must regenerate
the index. The `helm repo index` command will completely rebuild the `index.yaml`
file from scratch, including only the charts that it finds locally.
However, you can use the `--merge` flag to incrementally add new charts to an
existing `index.yaml` file (a great option when working with a remote repository
like GCS). Run `helm repo index --help` to learn more,
Make sure that you upload both the revised `index.yaml` file and the chart. And
if you generated a provenance file, upload that too.
### Share your charts with others
When you're ready to share your charts, simply let someone know what the URL of
your repository is.
From there, they will add the repository to their helm client via the `helm
repo add [NAME] [URL]` command with any name they would like to use to
reference the repository.
```console
$ helm repo add fantastic-charts https://fantastic-charts.storage.googleapis.com
$ helm repo list
fantastic-charts https://fantastic-charts.storage.googleapis.com
```
If the charts are backed by HTTP basic authentication, you can also supply the
username and password here:
```console
$ helm repo add fantastic-charts https://fantastic-charts.storage.googleapis.com --username my-username --password my-password
$ helm repo list
fantastic-charts https://fantastic-charts.storage.googleapis.com
```
**Note:** A repository will not be added if it does not contain a valid
`index.yaml`.
After that, your users will be able to search through your charts. After you've updated
the repository, they can use the `helm repo update` command to get the latest
chart information.
*Under the hood, the `helm repo add` and `helm repo update` commands are
fetching the index.yaml file and storing them in the
`$HELM_HOME/repository/cache/` directory. This is where the `helm search`
function finds information about charts.*

@ -1,74 +0,0 @@
# Syncing Your Chart Repository
*Note: This example is specifically for a Google Cloud Storage (GCS) bucket which serves a chart repository.*
## Prerequisites
* Install the [gsutil](https://cloud.google.com/storage/docs/gsutil) tool. *We rely heavily on the gsutil rsync functionality*
* Be sure to have access to the Helm binary
* _Optional: We recommend you set [object versioning](https://cloud.google.com/storage/docs/gsutil/addlhelp/ObjectVersioningandConcurrencyControl#top_of_page) on your GCS bucket in case you accidentally delete something._
## Set up a local chart repository directory
Create a local directory like we did in [the chart repository guide](chart_repository.md), and place your packaged charts in that directory.
For example:
```console
$ mkdir fantastic-charts
$ mv alpine-0.1.0.tgz fantastic-charts/
```
## Generate an updated index.yaml
Use Helm to generate an updated index.yaml file by passing in the directory path and the url of the remote repository to the `helm repo index` command like this:
```console
$ helm repo index fantastic-charts/ --url https://fantastic-charts.storage.googleapis.com
```
This will generate an updated index.yaml file and place in the `fantastic-charts/` directory.
## Sync your local and remote chart repositories
Upload the contents of the directory to your GCS bucket by running `scripts/sync-repo.sh` and pass in the local directory name and the GCS bucket name.
For example:
```console
$ pwd
/Users/me/code/go/src/helm.sh/helm
$ scripts/sync-repo.sh fantastic-charts/ fantastic-charts
Getting ready to sync your local directory (fantastic-charts/) to a remote repository at gs://fantastic-charts
Verifying Prerequisites....
Thumbs up! Looks like you have gsutil. Let's continue.
Building synchronization state...
Starting synchronization
Would copy file://fantastic-charts/alpine-0.1.0.tgz to gs://fantastic-charts/alpine-0.1.0.tgz
Would copy file://fantastic-charts/index.yaml to gs://fantastic-charts/index.yaml
Are you sure you would like to continue with these changes?? [y/N]} y
Building synchronization state...
Starting synchronization
Copying file://fantastic-charts/alpine-0.1.0.tgz [Content-Type=application/x-tar]...
Uploading gs://fantastic-charts/alpine-0.1.0.tgz: 740 B/740 B
Copying file://fantastic-charts/index.yaml [Content-Type=application/octet-stream]...
Uploading gs://fantastic-charts/index.yaml: 347 B/347 B
Congratulations your remote chart repository now matches the contents of fantastic-charts/
```
## Updating your chart repository
You'll want to keep a local copy of the contents of your chart repository or use `gsutil rsync` to copy the contents of your remote chart repository to a local directory.
For example:
```console
$ gsutil rsync -d -n gs://bucket-name local-dir/ # the -n flag does a dry run
Building synchronization state...
Starting synchronization
Would copy gs://bucket-name/alpine-0.1.0.tgz to file://local-dir/alpine-0.1.0.tgz
Would copy gs://bucket-name/index.yaml to file://local-dir/index.yaml
$ gsutil rsync -d gs://bucket-name local-dir/ # performs the copy actions
Building synchronization state...
Starting synchronization
Copying gs://bucket-name/alpine-0.1.0.tgz...
Downloading file://local-dir/alpine-0.1.0.tgz: 740 B/740 B
Copying gs://bucket-name/index.yaml...
Downloading file://local-dir/index.yaml: 346 B/346 B
```
Helpful Links:
* Documentation on [gsutil rsync](https://cloud.google.com/storage/docs/gsutil/commands/rsync#description)
* [The Chart Repository Guide](chart_repository.md)
* Documentation on [object versioning and concurrency control](https://cloud.google.com/storage/docs/gsutil/addlhelp/ObjectVersioningandConcurrencyControl#overview) in Google Cloud Storage

@ -1,209 +0,0 @@
# Accessing Files Inside Templates
In the previous section we looked at several ways to create and access named templates. This makes it easy to import one template from within another template. But sometimes it is desirable to import a _file that is not a template_ and inject its contents without sending the contents through the template renderer.
Helm provides access to files through the `.Files` object. Before we get going with the template examples, though, there are a few things to note about how this works:
- It is okay to add extra files to your Helm chart. These files will be bundled. Be careful, though. Charts must be smaller than 1M because of the storage limitations of Kubernetes objects.
- Some files cannot be accessed through the `.Files` object, usually for security reasons.
- Files in `templates/` cannot be accessed.
- Files excluded using `.helmignore` cannot be accessed.
- Charts do not preserve UNIX mode information, so file-level permissions will have no impact on the availability of a file when it comes to the `.Files` object.
<!-- (see https://github.com/jonschlinkert/markdown-toc) -->
<!-- toc -->
- [Basic example](#basic-example)
- [Path helpers](#path-helpers)
- [Glob patterns](#glob-patterns)
- [ConfigMap and Secrets utility functions](#configmap-and-secrets-utility-functions)
- [Encoding](#encoding)
- [Lines](#lines)
<!-- tocstop -->
## Basic example
With those caveats behind, let's write a template that reads three files into our ConfigMap. To get started, we will add three files to the chart, putting all three directly inside of the `mychart/` directory.
`config1.toml`:
```toml
message = Hello from config 1
```
`config2.toml`:
```toml
message = This is config 2
```
`config3.toml`:
```toml
message = Goodbye from config 3
```
Each of these is a simple TOML file (think old-school Windows INI files). We know the names of these files, so we can use a `range` function to loop through them and inject their contents into our ConfigMap.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
{{- $files := .Files }}
{{- range tuple "config1.toml" "config2.toml" "config3.toml" }}
{{ . }}: |-
{{ $files.Get . }}
{{- end }}
```
This config map uses several of the techniques discussed in previous sections. For example, we create a `$files` variable to hold a reference to the `.Files` object. We also use the `tuple` function to create a list of files that we loop through. Then we print each file name (`{{.}}: |-`) followed by the contents of the file `{{ $files.Get . }}`.
Running this template will produce a single ConfigMap with the contents of all three files:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: quieting-giraf-configmap
data:
config1.toml: |-
message = Hello from config 1
config2.toml: |-
message = This is config 2
config3.toml: |-
message = Goodbye from config 3
```
## Path helpers
When working with files, it can be very useful to perform some standard
operations on the file paths themselves. To help with this, Helm imports many of
the functions from Go's [path](https://golang.org/pkg/path/) package for your
use. They are all accessible with the same names as in the Go package, but
with a lowercase first letter. For example, `Base` becomes `base`, etc.
The imported functions are:
- Base
- Dir
- Ext
- IsAbs
- Clean
## Glob patterns
As your chart grows, you may find you have a greater need to organize your
files more, and so we provide a `Files.Glob(pattern string)` method to assist
in extracting certain files with all the flexibility of [glob patterns](https://godoc.org/github.com/gobwas/glob).
`.Glob` returns a `Files` type, so you may call any of the `Files` methods on
the returned object.
For example, imagine the directory structure:
```
foo/:
foo.txt foo.yaml
bar/:
bar.go bar.conf baz.yaml
```
You have multiple options with Globs:
```yaml
{{ range $path := .Files.Glob "**.yaml" }}
{{ $path }}: |
{{ .Files.Get $path }}
{{ end }}
```
Or
```yaml
{{ range $path, $bytes := .Files.Glob "foo/*" }}
{{ $path }}: '{{ b64enc $bytes }}'
{{ end }}
```
## ConfigMap and Secrets utility functions
(Not present in version 2.0.2 or prior)
It is very common to want to place file content into both configmaps and
secrets, for mounting into your pods at run time. To help with this, we provide a
couple utility methods on the `Files` type.
For further organization, it is especially useful to use these methods in
conjunction with the `Glob` method.
Given the directory structure from the [Glob](#glob-patterns) example above:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: conf
data:
{{ (.Files.Glob "foo/*").AsConfig | indent 2 }}
---
apiVersion: v1
kind: Secret
metadata:
name: very-secret
type: Opaque
data:
{{ (.Files.Glob "bar/*").AsSecrets | indent 2 }}
```
## Encoding
You can import a file and have the template base-64 encode it to ensure successful transmission:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: {{ .Release.Name }}-secret
type: Opaque
data:
token: |-
{{ .Files.Get "config1.toml" | b64enc }}
```
The above will take the same `config1.toml` file we used before and encode it:
```yaml
# Source: mychart/templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: lucky-turkey-secret
type: Opaque
data:
token: |-
bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDEK
```
## Lines
Sometimes it is desirable to access each line of a file in your template. We
provide a convenient `Lines` method for this.
```yaml
data:
some-file.txt: {{ range .Files.Lines "foo/bar.txt" }}
{{ . }}{{ end }}
```
Currently, there is no way to pass files external to the chart during `helm install`. So if you are asking users to supply data, it must be loaded using `helm install -f` or `helm install --set`.
This discussion wraps up our dive into the tools and techniques for writing Helm templates. In the next section we will see how you can use one special file, `templates/NOTES.txt`, to send post-installation instructions to the users of your chart.

@ -1,34 +0,0 @@
# Built-in Objects
Objects are passed into a template from the template engine. And your code can pass objects around (we'll see examples when we look at the `with` and `range` statements). There are even a few ways to create new objects within your templates, like with the `tuple` function we'll see later.
Objects can be simple, and have just one value. Or they can contain other objects or functions. For example. the `Release` object contains several objects (like `Release.Name`) and the `Files` object has a few functions.
In the previous section, we use `{{.Release.Name}}` to insert the name of a release into a template. `Release` is one of the top-level objects that you can access in your templates.
- `Release`: This object describes the release itself. It has several objects inside of it:
- `Release.Name`: The release name
- `Release.Namespace`: The namespace to be released into (if the manifest doesnt override)
- `Release.IsUpgrade`: This is set to `true` if the current operation is an upgrade or rollback.
- `Release.IsInstall`: This is set to `true` if the current operation is an install.
- `Values`: Values passed into the template from the `values.yaml` file and from user-supplied files. By default, `Values` is empty.
- `Chart`: The contents of the `Chart.yaml` file. Any data in `Chart.yaml` will be accessible here. For example `{{.Chart.Name}}-{{.Chart.Version}}` will print out the `mychart-0.1.0`.
- The available fields are listed in the [Charts Guide](https://github.com/helm/helm/blob/master/docs/charts.md#the-chartyaml-file)
- `Files`: This provides access to all non-special files in a chart. While you cannot use it to access templates, you can use it to access other files in the chart. See the section _Accessing Files_ for more.
- `Files.Get` is a function for getting a file by name (`.Files.Get config.ini`)
- `Files.GetBytes` is a function for getting the contents of a file as an array of bytes instead of as a string. This is useful for things like images.
- `Capabilities`: This provides information about what capabilities the Kubernetes cluster supports.
- `Capabilities.APIVersions` is a set of versions.
- `Capabilities.APIVersions.Has $version` indicates whether a version (e.g., `batch/v1`) or resource (e.g., `apps/v1/Deployment`) is available on the cluster.
- `Capabilities.Kube.Version` is the Kubernetes version.
- `Capabilities.Kube` is a short form for Kubernetes version.
- `Capabilities.Kube.Major` is the Kubernetes major version.
- `Capabilities.Kube.Minor` is the Kubernetes minor version.
- `Template`: Contains information about the current template that is being executed
- `Name`: A namespaced filepath to the current template (e.g. `mychart/templates/mytemplate.yaml`)
- `BasePath`: The namespaced path to the templates directory of the current chart (e.g. `mychart/templates`).
The values are available to any top-level template. As we will see later, this does not necessarily mean that they will be available _everywhere_.
The built-in values always begin with a capital letter. This is in keeping with Go's naming convention. When you create your own names, you are free to use a convention that suits your team. Some teams, like the [Kubernetes Charts](https://github.com/helm/charts) team, choose to use only initial lower case letters in order to distinguish local names from those built-in. In this guide, we follow that convention.

@ -1,354 +0,0 @@
# Flow Control
Control structures (called "actions" in template parlance) provide you, the template author, with the ability to control the flow of a template's generation. Helm's template language provides the following control structures:
- `if`/`else` for creating conditional blocks
- `with` to specify a scope
- `range`, which provides a "for each"-style loop
In addition to these, it provides a few actions for declaring and using named template segments:
- `define` declares a new named template inside of your template
- `template` imports a named template
- `block` declares a special kind of fillable template area
In this section, we'll talk about `if`, `with`, and `range`. The others are covered in the "Named Templates" section later in this guide.
## If/Else
The first control structure we'll look at is for conditionally including blocks of text in a template. This is the `if`/`else` block.
The basic structure for a conditional looks like this:
```
{{ if PIPELINE }}
# Do something
{{ else if OTHER PIPELINE }}
# Do something else
{{ else }}
# Default case
{{ end }}
```
Notice that we're now talking about _pipelines_ instead of values. The reason for this is to make it clear that control structures can execute an entire pipeline, not just evaluate a value.
A pipeline is evaluated as _false_ if the value is:
- a boolean false
- a numeric zero
- an empty string
- a `nil` (empty or null)
- an empty collection (`map`, `slice`, `tuple`, `dict`, `array`)
Under all other conditions, the condition is true.
Let's add a simple conditional to our ConfigMap. We'll add another setting if the drink is set to coffee:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{ if eq .Values.favorite.drink "coffee" }}mug: true{{ end }}
```
Since we commented out `drink: coffee` in our last example, the output should not include a `mug: true` flag. But if we add that line back into our `values.yaml` file, the output should look like this:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: eyewitness-elk-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: true
```
## Controlling Whitespace
While we're looking at conditionals, we should take a quick look at the way whitespace is controlled in templates. Let's take the previous example and format it to be a little easier to read:
```
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{if eq .Values.favorite.drink "coffee"}}
mug: true
{{end}}
```
Initially, this looks good. But if we run it through the template engine, we'll get an unfortunate result:
```console
$ helm install --dry-run --debug ./mychart
SERVER: "localhost:44134"
CHART PATH: /Users/mattbutcher/Code/Go/src/helm.sh/helm/_scratch/mychart
Error: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 9: did not find expected key
```
What happened? We generated incorrect YAML because of the whitespacing above.
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: eyewitness-elk-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: true
```
`mug` is incorrectly indented. Let's simply out-dent that one line, and re-run:
```
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{if eq .Values.favorite.drink "coffee"}}
mug: true
{{end}}
```
When we sent that, we'll get YAML that is valid, but still looks a little funny:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: telling-chimp-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: true
```
Notice that we received a few empty lines in our YAML. Why? When the template engine runs, it _removes_ the contents inside of `{{` and `}}`, but it leaves the remaining whitespace exactly as is.
YAML ascribes meaning to whitespace, so managing the whitespace becomes pretty important. Fortunately, Helm templates have a few tools to help.
First, the curly brace syntax of template declarations can be modified with special characters to tell the template engine to chomp whitespace. `{{- ` (with the dash and space added) indicates that whitespace should be chomped left, while ` -}}` means whitespace to the right should be consumed. _Be careful! Newlines are whitespace!_
> Make sure there is a space between the `-` and the rest of your directive. `{{- 3 }}` means "trim left whitespace and print 3" while `{{-3}}` means "print -3".
Using this syntax, we can modify our template to get rid of those new lines:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{- if eq .Values.favorite.drink "coffee"}}
mug: true
{{- end}}
```
Just for the sake of making this point clear, let's adjust the above, and substitute an `*` for each whitespace that will be deleted following this rule. an `*` at the end of the line indicates a newline character that would be removed
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}*
**{{- if eq .Values.favorite.drink "coffee"}}
mug: true*
**{{- end}}
```
Keeping that in mind, we can run our template through Helm and see the result:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: clunky-cat-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: true
```
Be careful with the chomping modifiers. It is easy to accidentally do things like this:
```yaml
food: {{ .Values.favorite.food | upper | quote }}
{{- if eq .Values.favorite.drink "coffee" -}}
mug: true
{{- end -}}
```
That will produce `food: "PIZZA"mug:true` because it consumed newlines on both sides.
> For the details on whitespace control in templates, see the [Official Go template documentation](https://godoc.org/text/template)
Finally, sometimes it's easier to tell the template system how to indent for you instead of trying to master the spacing of template directives. For that reason, you may sometimes find it useful to use the `indent` function (`{{indent 2 "mug:true"}}`).
## Modifying scope using `with`
The next control structure to look at is the `with` action. This controls variable scoping. Recall that `.` is a reference to _the current scope_. So `.Values` tells the template to find the `Values` object in the current scope.
The syntax for `with` is similar to a simple `if` statement:
```
{{ with PIPELINE }}
# restricted scope
{{ end }}
```
Scopes can be changed. `with` can allow you to set the current scope (`.`) to a particular object. For example, we've been working with `.Values.favorites`. Let's rewrite our ConfigMap to alter the `.` scope to point to `.Values.favorites`:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
```
(Note that we removed the `if` conditional from the previous exercise)
Notice that now we can reference `.drink` and `.food` without qualifying them. That is because the `with` statement sets `.` to point to `.Values.favorite`. The `.` is reset to its previous scope after `{{ end }}`.
But here's a note of caution! Inside of the restricted scope, you will not be able to access the other objects from the parent scope. This, for example, will fail:
```yaml
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ .Release.Name }}
{{- end }}
```
It will produce an error because `Release.Name` is not inside of the restricted scope for `.`. However, if we swap the last two lines, all will work as expected because the scope is reset after `{{end}}`.
```yaml
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
release: {{ .Release.Name }}
```
After looking a `range`, we will take a look at template variables, which offer one solution to the scoping issue above.
## Looping with the `range` action
Many programming languages have support for looping using `for` loops, `foreach` loops, or similar functional mechanisms. In Helm's template language, the way to iterate through a collection is to use the `range` operator.
To start, let's add a list of pizza toppings to our `values.yaml` file:
```yaml
favorite:
drink: coffee
food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
```
Now we have a list (called a `slice` in templates) of `pizzaToppings`. We can modify our template to print this list into our ConfigMap:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
toppings: |-
{{- range .Values.pizzaToppings }}
- {{ . | title | quote }}
{{- end }}
```
Let's take a closer look at the `toppings:` list. The `range` function will "range over" (iterate through) the `pizzaToppings` list. But now something interesting happens. Just like `with` sets the scope of `.`, so does a `range` operator. Each time through the loop, `.` is set to the current pizza topping. That is, the first time, `.` is set to `mushrooms`. The second iteration it is set to `cheese`, and so on.
We can send the value of `.` directly down a pipeline, so when we do `{{ . | title | quote }}`, it sends `.` to `title` (title case function) and then to `quote`. If we run this template, the output will be:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: edgy-dragonfly-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
toppings: |-
- "Mushrooms"
- "Cheese"
- "Peppers"
- "Onions"
```
Now, in this example we've done something tricky. The `toppings: |-` line is declaring a multi-line string. So our list of toppings is actually not a YAML list. It's a big string. Why would we do this? Because the data in ConfigMaps `data` is composed of key/value pairs, where both the key and the value are simple strings. To understand why this is the case, take a look at the [Kubernetes ConfigMap docs](http://kubernetes.io/docs/user-guide/configmap/). For us, though, this detail doesn't matter much.
> The `|-` marker in YAML takes a multi-line string. This can be a useful technique for embedding big blocks of data inside of your manifests, as exemplified here.
Sometimes it's useful to be able to quickly make a list inside of your template, and then iterate over that list. Helm templates have a function to make this easy: `tuple`. In computer science, a tuple is a list-like collection of fixed size, but with arbitrary data types. This roughly conveys the way a `tuple` is used.
```yaml
sizes: |-
{{- range tuple "small" "medium" "large" }}
- {{ . }}
{{- end }}
```
The above will produce this:
```yaml
sizes: |-
- small
- medium
- large
```
In addition to lists and tuples, `range` can be used to iterate over collections that have a key and a value (like a `map` or `dict`). We'll see how to do that in the next section when we introduce template variables.

@ -1,14 +0,0 @@
# Appendix: Go Data Types and Templates
The Helm template language is implemented in the strongly typed Go programming language. For that reason, variables in templates are _typed_. For the most part, variables will be exposed as one of the following types:
- string: A string of text
- bool: a `true` or `false`
- int: An integer value (there are also 8, 16, 32, and 64 bit signed and unsigned variants of this)
- float64: a 64-bit floating point value (there are also 8, 16, and 32 bit varieties of this)
- a byte slice (`[]byte`), often used to hold (potentially) binary data
- struct: an object with properties and methods
- a slice (indexed list) of one of the previous types
- a string-keyed map (`map[string]interface{}`) where the value is one of the previous types
There are many other types in Go, and sometimes you will have to convert between them in your templates. The easiest way to debug an object's type is to pass it through `printf "%t"` in a template, which will print the type. Also see the `typeOf` and `kindOf` functions.

@ -1,30 +0,0 @@
# Debugging Templates
Debugging templates can be tricky because the rendered templates are sent to the Kubernetes API server, which may reject the YAML files for reasons other than formatting.
There are a few commands that can help you debug.
- `helm lint` is your go-to tool for verifying that your chart follows best practices
- `helm install --dry-run --debug`: We've seen this trick already. It's a great way to have the server render your templates, then return the resulting manifest file.
- `helm get manifest`: This is a good way to see what templates are installed on the server.
When your YAML is failing to parse, but you want to see what is generated, one
easy way to retrieve the YAML is to comment out the problem section in the template,
and then re-run `helm install --dry-run --debug`:
```YAML
apiVersion: v1
# some: problem section
# {{ .Values.foo | quote }}
```
The above will be rendered and returned with the comments intact:
```YAML
apiVersion: v1
# some: problem section
# "bar"
```
This provides a quick way of viewing the generated content without YAML parse
errors blocking.

@ -1,155 +0,0 @@
# Template Functions and Pipelines
So far, we've seen how to place information into a template. But that information is placed into the template unmodified. Sometimes we want to transform the supplied data in a way that makes it more useable to us.
Let's start with a best practice: When injecting strings from the `.Values` object into the template, we ought to quote these strings. We can do that by calling the `quote` function in the template directive:
```
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ quote .Values.favorite.drink }}
food: {{ quote .Values.favorite.food }}
```
Template functions follow the syntax `functionName arg1 arg2...`. In the snippet above, `quote .Values.favorite.drink` calls the `quote` function and passes it a single argument.
Helm has over 60 available functions. Some of them are defined by the [Go template language](https://godoc.org/text/template) itself. Most of the others are part of the [Sprig template library](https://godoc.org/github.com/Masterminds/sprig). We'll see many of them as we progress through the examples.
> While we talk about the "Helm template language" as if it is Helm-specific, it is actually a combination of the Go template language, some extra functions, and a variety of wrappers to expose certain objects to the templates. Many resources on Go templates may be helpful as you learn about templating.
## Pipelines
One of the powerful features of the template language is its concept of _pipelines_. Drawing on a concept from UNIX, pipelines are a tool for chaining together a series of template commands to compactly express a series of transformations. In other words, pipelines are an efficient way of getting several things done in sequence. Let's rewrite the above example using a pipeline.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | quote }}
food: {{ .Values.favorite.food | quote }}
```
In this example, instead of calling `quote ARGUMENT`, we inverted the order. We "sent" the argument to the function using a pipeline (`|`): `.Values.favorite.drink | quote`. Using pipelines, we can chain several functions together:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | quote }}
food: {{ .Values.favorite.food | upper | quote }}
```
> Inverting the order is a common practice in templates. You will see `.val | quote` more often than `quote .val`. Either practice is fine.
When evaluated, that template will produce this:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: trendsetting-p-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
```
Note that our original `pizza` has now been transformed to `"PIZZA"`.
When pipelining arguments like this, the result of the first evaluation (`.Values.favorite.drink`) is sent as the _last argument to the function_. We can modify the drink example above to illustrate with a function that takes two arguments: `repeat COUNT STRING`:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | repeat 5 | quote }}
food: {{ .Values.favorite.food | upper | quote }}
```
The `repeat` function will echo the given string the given number of times, so we will get this for output:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: melting-porcup-configmap
data:
myvalue: "Hello World"
drink: "coffeecoffeecoffeecoffeecoffee"
food: "PIZZA"
```
## Using the `default` function
One function frequently used in templates is the `default` function: `default DEFAULT_VALUE GIVEN_VALUE`. This function allows you to specify a default value inside of the template, in case the value is omitted. Let's use it to modify the drink example above:
```yaml
drink: {{ .Values.favorite.drink | default "tea" | quote }}
```
If we run this as normal, we'll get our `coffee`:
```
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: virtuous-mink-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
```
Now, we will remove the favorite drink setting from `values.yaml`:
```yaml
favorite:
#drink: coffee
food: pizza
```
Now re-running `helm install --dry-run --debug ./mychart` will produce this YAML:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: fair-worm-configmap
data:
myvalue: "Hello World"
drink: "tea"
food: "PIZZA"
```
In an actual chart, all static default values should live in the values.yaml, and should not be repeated using the `default` command (otherwise they would be redundant). However, the `default` command is perfect for computed values, which can not be declared inside values.yaml. For example:
```yaml
drink: {{ .Values.favorite.drink | default (printf "%s-tea" (include "fullname" .)) }}
```
In some places, an `if` conditional guard may be better suited than `default`. We'll see those in the next section.
Template functions and pipelines are a powerful way to transform information and then insert it into your YAML. But sometimes it's necessary to add some template logic that is a little more sophisticated than just inserting a string. In the next section we will look at the control structures provided by the template language.
## Operators are functions
For templates, the operators (`eq`, `ne`, `lt`, `gt`, `and`, `or` and so on) are all implemented as functions. In pipelines, operations can be grouped with parentheses (`(`, and `)`).
Now we can turn from functions and pipelines to flow control with conditions, loops, and scope modifiers.

@ -1,213 +0,0 @@
# Getting Started with a Chart Template
In this section of the guide, we'll create a chart and then add a first template. The chart we created here will be used throughout the rest of the guide.
To get going, let's take a brief look at a Helm chart.
## Charts
As described in the [Charts Guide](../charts.md), Helm charts are structured like
this:
```
mychart/
Chart.yaml
values.yaml
charts/
templates/
...
```
The `templates/` directory is for template files. When Helm evaluates a chart,
it will send all of the files in the `templates/` directory through the
template rendering engine. It then collects the results of those templates
and sends them on to Kubernetes.
The `values.yaml` file is also important to templates. This file contains the
_default values_ for a chart. These values may be overridden by users during
`helm install` or `helm upgrade`.
The `Chart.yaml` file contains a description of the chart. You can access it
from within a template. The `charts/` directory _may_ contain other charts (which
we call _subcharts_). Later in this guide we will see how those work when it
comes to template rendering.
## A Starter Chart
For this guide, we'll create a simple chart called `mychart`, and then we'll
create some templates inside of the chart.
```console
$ helm create mychart
Creating mychart
```
From here on, we'll be working in the `mychart` directory.
### A Quick Glimpse of `mychart/templates/`
If you take a look at the `mychart/templates/` directory, you'll notice a few files
already there.
- `NOTES.txt`: The "help text" for your chart. This will be displayed to your users
when they run `helm install`.
- `deployment.yaml`: A basic manifest for creating a Kubernetes [deployment](http://kubernetes.io/docs/user-guide/deployments/)
- `service.yaml`: A basic manifest for creating a [service endpoint](http://kubernetes.io/docs/user-guide/services/) for your deployment
- `_helpers.tpl`: A place to put template helpers that you can re-use throughout the chart
And what we're going to do is... _remove them all!_ That way we can work through our tutorial from scratch. We'll actually create our own `NOTES.txt` and `_helpers.tpl` as we go.
```console
$ rm -rf mychart/templates/*.*
```
When you're writing production grade charts, having basic versions of these charts can be really useful. So in your day-to-day chart authoring, you probably won't want to remove them.
## A First Template
The first template we are going to create will be a `ConfigMap`. In Kubernetes,
a ConfigMap is simply a container for storing configuration data. Other things,
like pods, can access the data in a ConfigMap.
Because ConfigMaps are basic resources, they make a great starting point for us.
Let's begin by creating a file called `mychart/templates/configmap.yaml`:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
```
**TIP:** Template names do not follow a rigid naming pattern. However, we recommend
using the suffix `.yaml` for YAML files and `.tpl` for helpers.
The YAML file above is a bare-bones ConfigMap, having the minimal necessary fields.
In virtue of the fact that this file is in the `templates/` directory, it will
be sent through the template engine.
It is just fine to put a plain YAML file like this in the `templates/` directory.
When Helm reads this template, it will simply send it to Kubernetes as-is.
With this simple template, we now have an installable chart. And we can install
it like this:
```console
$ helm install ./mychart
NAME: full-coral
LAST DEPLOYED: Tue Nov 1 17:36:01 2016
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
mychart-configmap 1 1m
```
In the output above, we can see that our ConfigMap was created. Using Helm, we
can retrieve the release and see the actual template that was loaded.
```console
$ helm get manifest full-coral
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
```
The `helm get manifest` command takes a release name (`full-coral`) and prints
out all of the Kubernetes resources that were uploaded to the server. Each file
begins with `---` to indicate the start of a YAML document, and then is followed
by an automatically generated comment line that tells us what template file
generated this YAML document.
From there on, we can see that the YAML data is exactly what we put in our
`configmap.yaml` file.
Now we can uninstall our release: `helm uninstall full-coral`.
### Adding a Simple Template Call
Hard-coding the `name:` into a resource is usually considered to be bad practice.
Names should be unique to a release. So we might want to generate a name field
by inserting the release name.
**TIP:** The `name:` field is limited to 63 characters because of limitations to
the DNS system. For that reason, release names are limited to 53 characters.
Kubernetes 1.3 and earlier limited to only 24 characters (thus 14 character names).
Let's alter `configmap.yaml` accordingly.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
```
The big change comes in the value of the `name:` field, which is now
`{{ .Release.Name }}-configmap`.
> A template directive is enclosed in `{{` and `}}` blocks.
The template directive `{{ .Release.Name }}` injects the release name into the template. The values that are passed into a template can be thought of as _namespaced objects_, where a dot (`.`) separates each namespaced element.
The leading dot before `Release` indicates that we start with the top-most namespace for this scope (we'll talk about scope in a bit). So we could read `.Release.Name` as "start at the top namespace, find the `Release` object, then look inside of it for an object called `Name`".
The `Release` object is one of the built-in objects for Helm, and we'll cover it in more depth later. But for now, it is sufficient to say that this will display the release name that the library assigns to our release.
Now when we install our resource, we'll immediately see the result of using this template directive:
```console
$ helm install ./mychart
NAME: clunky-serval
LAST DEPLOYED: Tue Nov 1 17:45:37 2016
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
clunky-serval-configmap 1 1m
```
Note that in the `RESOURCES` section, the name we see there is `clunky-serval-configmap`
instead of `mychart-configmap`.
You can run `helm get manifest clunky-serval` to see the entire generated YAML.
At this point, we've seen templates at their most basic: YAML files that have template directives embedded in `{{` and `}}`. In the next part, we'll take a deeper look into templates. But before moving on, there's one quick trick that can make building templates faster: When you want to test the template rendering, but not actually install anything, you can use `helm install --debug --dry-run ./mychart`. This will render the templates. But instead of installing the chart, it will return the rendered template to you so you can see the output:
```console
$ helm install --debug --dry-run ./mychart
SERVER: "localhost:44134"
CHART PATH: /Users/mattbutcher/Code/Go/src/helm.sh/helm/_scratch/mychart
NAME: goodly-guppy
TARGET NAMESPACE: default
CHART: mychart 0.1.0
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: goodly-guppy-configmap
data:
myvalue: "Hello World"
```
Using `--dry-run` will make it easier to test your code, but it won't ensure that Kubernetes itself will accept the templates you generate. It's best not to assume that your chart will install just because `--dry-run` works.
In the next few sections, we'll take the basic chart we defined here and explore the Helm template language in detail. And we'll get started with built-in objects.

@ -1,16 +0,0 @@
# The Chart Template Developer's Guide
This guide provides an introduction to Helm's chart templates, with emphasis on
the template language.
Templates generate manifest files, which are YAML-formatted resource descriptions
that Kubernetes can understand. We'll look at how templates are structured,
how they can be used, how to write Go templates, and how to debug your work.
This guide focuses on the following concepts:
- The Helm template language
- Using values
- Techniques for working with templates
This guide is oriented toward learning the ins and outs of the Helm template language. Other guides provide introductory material, examples, and best practices.

@ -1,264 +0,0 @@
# Named Templates
It is time to move beyond one template, and begin to create others. In this section, we will see how to define _named templates_ in one file, and then use them elsewhere. A _named template_ (sometimes called a _partial_ or a _subtemplate_) is simply a template defined inside of a file, and given a name. We'll see two ways to create them, and a few different ways to use them.
In the "Flow Control" section we introduced three actions for declaring and managing templates: `define`, `template`, and `block`. In this section, we'll cover those three actions, and also introduce a special-purpose `include` function that works similarly to the `template` action.
An important detail to keep in mind when naming templates: **template names are global**. If you declare two templates with the same name, whichever one is loaded last will be the one used. Because templates in subcharts are compiled together with top-level templates, you should be careful to name your templates with _chart-specific names_.
One popular naming convention is to prefix each defined template with the name of the chart: `{{ define "mychart.labels" }}`. By using the specific chart name as a prefix we can avoid any conflicts that may arise due to two different charts that implement templates of the same name.
## Partials and `_` files
So far, we've used one file, and that one file has contained a single template. But Helm's template language allows you to create named embedded templates, that can be accessed by name elsewhere.
Before we get to the nuts-and-bolts of writing those templates, there is file naming convention that deserves mention:
* Most files in `templates/` are treated as if they contain Kubernetes manifests
* The `NOTES.txt` is one exception
* But files whose name begins with an underscore (`_`) are assumed to _not_ have a manifest inside. These files are not rendered to Kubernetes object definitions, but are available everywhere within other chart templates for use.
These files are used to store partials and helpers. In fact, when we first created `mychart`, we saw a file called `_helpers.tpl`. That file is the default location for template partials.
## Declaring and using templates with `define` and `template`
The `define` action allows us to create a named template inside of a template file. Its syntax goes like this:
```yaml
{{ define "MY.NAME" }}
# body of template here
{{ end }}
```
For example, we can define a template to encapsulate a Kubernetes block of labels:
```yaml
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
```
Now we can embed this template inside of our existing ConfigMap, and then include it with the `template` action:
```yaml
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
{{- template "mychart.labels" }}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
```
When the template engine reads this file, it will store away the reference to `mychart.labels` until `template "mychart.labels"` is called. Then it will render that template inline. So the result will look like this:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: running-panda-configmap
labels:
generator: helm
date: 2016-11-02
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
```
Conventionally, Helm charts put these templates inside of a partials file, usually `_helpers.tpl`. Let's move this function there:
```yaml
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
```
By convention, `define` functions should have a simple documentation block (`{{/* ... */}}`) describing what they do.
Even though this definition is in `_helpers.tpl`, it can still be accessed in `configmap.yaml`:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
{{- template "mychart.labels" }}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
```
As mentioned above, **template names are global**. As a result of this, if two templates are declared with the same name the last occurrence will be the one that is used. Since templates in subcharts are compiled together with top-level templates, it is best to name your templates with _chart specific names_. A popular naming convention is to prefix each defined template with the name of the chart: `{{ define "mychart.labels" }}`.
## Setting the scope of a template
In the template we defined above, we did not use any objects. We just used functions. Let's modify our defined template to include the chart name and chart version:
```yaml
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
chart: {{ .Chart.Name }}
version: {{ .Chart.Version }}
{{- end }}
```
If we render this, the result will not be what we expect:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: moldy-jaguar-configmap
labels:
generator: helm
date: 2016-11-02
chart:
version:
```
What happened to the name and version? They weren't in the scope for our defined template. When a named template (created with `define`) is rendered, it will receive the scope passed in by the `template` call. In our example, we included the template like this:
```yaml
{{- template "mychart.labels" }}
```
No scope was passed in, so within the template we cannot access anything in `.`. This is easy enough to fix, though. We simply pass a scope to the template:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
{{- template "mychart.labels" . }}
```
Note that we pass `.` at the end of the `template` call. We could just as easily pass `.Values` or `.Values.favorite` or whatever scope we want. But what we want is the top-level scope.
Now when we execute this template with `helm install --dry-run --debug ./mychart`, we get this:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: plinking-anaco-configmap
labels:
generator: helm
date: 2016-11-02
chart: mychart
version: 0.1.0
```
Now `{{ .Chart.Name }}` resolves to `mychart`, and `{{ .Chart.Version }}` resolves to `0.1.0`.
## The `include` function
Say we've defined a simple template that looks like this:
```yaml
{{- define "mychart.app" -}}
app_name: {{ .Chart.Name }}
app_version: "{{ .Chart.Version }}"
{{- end -}}
```
Now say I want to insert this both into the `labels:` section of my template, and also the `data:` section:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
labels:
{{ template "mychart.app" .}}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
{{ template "mychart.app" . }}
```
The output will not be what we expect:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: measly-whippet-configmap
labels:
app_name: mychart
app_version: "0.1.0+1478129847"
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
app_name: mychart
app_version: "0.1.0+1478129847"
```
Note that the indentation on `app_version` is wrong in both places. Why? Because the template that is substituted in has the text aligned to the right. Because `template` is an action, and not a function, there is no way to pass the output of a `template` call to other functions; the data is simply inserted inline.
To work around this case, Helm provides an alternative to `template` that will import the contents of a template into the present pipeline where it can be passed along to other functions in the pipeline.
Here's the example above, corrected to use `indent` to indent the `mychart_app` template correctly:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
labels:
{{ include "mychart.app" . | indent 4 }}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
{{ include "mychart.app" . | indent 2 }}
```
Now the produced YAML is correctly indented for each section:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: edgy-mole-configmap
labels:
app_name: mychart
app_version: "0.1.0+1478129987"
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
app_name: mychart
app_version: "0.1.0+1478129987"
```
> It is considered preferable to use `include` over `template` in Helm templates simply so that the output formatting can be handled better for YAML documents.
Sometimes we want to import content, but not as templates. That is, we want to import files verbatim. We can achieve this by accessing files through the `.Files` object described in the next section.

@ -1,45 +0,0 @@
# Creating a NOTES.txt File
In this section we are going to look at Helm's tool for providing instructions to your chart users. At the end of a `chart install` or `chart upgrade`, Helm can print out a block of helpful information for users. This information is highly customizable using templates.
To add installation notes to your chart, simply create a `templates/NOTES.txt` file. This file is plain text, but it is processed like as a template, and has all the normal template functions and objects available.
Let's create a simple `NOTES.txt` file:
```
Thank you for installing {{ .Chart.Name }}.
Your release is named {{ .Release.Name }}.
To learn more about the release, try:
$ helm status {{ .Release.Name }}
$ helm get {{ .Release.Name }}
```
Now if we run `helm install ./mychart` we will see this message at the bottom:
```
RESOURCES:
==> v1/Secret
NAME TYPE DATA AGE
rude-cardinal-secret Opaque 1 0s
==> v1/ConfigMap
NAME DATA AGE
rude-cardinal-configmap 3 0s
NOTES:
Thank you for installing mychart.
Your release is named rude-cardinal.
To learn more about the release, try:
$ helm status rude-cardinal
$ helm get rude-cardinal
```
Using `NOTES.txt` this way is a great way to give your users detailed information about how to use their newly installed chart. Creating a `NOTES.txt` file is strongly recommended, though it is not required.

@ -1,207 +0,0 @@
# Subcharts and Global Values
To this point we have been working only with one chart. But charts can have dependencies, called _subcharts_, that also have their own values and templates. In this section we will create a subchart and see the different ways we can access values from within templates.
Before we dive into the code, there are a few important details to learn about subcharts.
1. A subchart is considered "stand-alone", which means a subchart can never explicitly depend on its parent chart.
2. For that reason, a subchart cannot access the values of its parent.
3. A parent chart can override values for subcharts.
4. Helm has a concept of _global values_ that can be accessed by all charts.
As we walk through the examples in this section, many of these concepts will become clearer.
## Creating a Subchart
For these exercises, we'll start with the `mychart/` chart we created at the beginning of this guide, and we'll add a new chart inside of it.
```console
$ cd mychart/charts
$ helm create mysubchart
Creating mysubchart
$ rm -rf mysubchart/templates/*.*
```
Notice that just as before, we deleted all of the base templates so that we can start from scratch. In this guide, we are focused on how templates work, not on managing dependencies. But the [Charts Guide](../charts.md) has more information on how subcharts work.
## Adding Values and a Template to the Subchart
Next, let's create a simple template and values file for our `mysubchart` chart. There should already be a `values.yaml` in `mychart/charts/mysubchart`. We'll set it up like this:
```yaml
dessert: cake
```
Next, we'll create a new ConfigMap template in `mychart/charts/mysubchart/templates/configmap.yaml`:
```
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cfgmap2
data:
dessert: {{ .Values.dessert }}
```
Because every subchart is a _stand-alone chart_, we can test `mysubchart` on its own:
```console
$ helm install --dry-run --debug mychart/charts/mysubchart
SERVER: "localhost:44134"
CHART PATH: /Users/mattbutcher/Code/Go/src/helm.sh/helm/_scratch/mychart/charts/mysubchart
NAME: newbie-elk
TARGET NAMESPACE: default
CHART: mysubchart 0.1.0
MANIFEST:
---
# Source: mysubchart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: newbie-elk-cfgmap2
data:
dessert: cake
```
## Overriding Values from a Parent Chart
Our original chart, `mychart` is now the _parent_ chart of `mysubchart`. This relationship is based entirely on the fact that `mysubchart` is within `mychart/charts`.
Because `mychart` is a parent, we can specify configuration in `mychart` and have that configuration pushed into `mysubchart`. For example, we can modify `mychart/values.yaml` like this:
```yaml
favorite:
drink: coffee
food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
mysubchart:
dessert: ice cream
```
Note the last two lines. Any directives inside of the `mysubchart` section will be sent to the `mysubchart` chart. So if we run `helm install --dry-run --debug mychart`, one of the things we will see is the `mysubchart` ConfigMap:
```yaml
# Source: mychart/charts/mysubchart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: unhinged-bee-cfgmap2
data:
dessert: ice cream
```
The value at the top level has now overridden the value of the subchart.
There's an important detail to notice here. We didn't change the template of `mychart/charts/mysubchart/templates/configmap.yaml` to point to `.Values.mysubchart.dessert`. From that template's perspective, the value is still located at `.Values.dessert`. As the template engine passes values along, it sets the scope. So for the `mysubchart` templates, only values specifically for `mysubchart` will be available in `.Values`.
Sometimes, though, you do want certain values to be available to all of the templates. This is accomplished using global chart values.
## Global Chart Values
Global values are values that can be accessed from any chart or subchart by exactly the same name. Globals require explicit declaration. You can't use an existing non-global as if it were a global.
The Values data type has a reserved section called `Values.global` where global values can be set. Let's set one in our `mychart/values.yaml` file.
```yaml
favorite:
drink: coffee
food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
mysubchart:
dessert: ice cream
global:
salad: caesar
```
Because of the way globals work, both `mychart/templates/configmap.yaml` and `mysubchart/templates/configmap.yaml` should be able to access that value as `{{ .Values.global.salad}}`.
`mychart/templates/configmap.yaml`:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
salad: {{ .Values.global.salad }}
```
`mysubchart/templates/configmap.yaml`:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cfgmap2
data:
dessert: {{ .Values.dessert }}
salad: {{ .Values.global.salad }}
```
Now if we run a dry run install, we'll see the same value in both outputs:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: silly-snake-configmap
data:
salad: caesar
---
# Source: mychart/charts/mysubchart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: silly-snake-cfgmap2
data:
dessert: ice cream
salad: caesar
```
Globals are useful for passing information like this, though it does take some planning to make sure the right templates are configured to use globals.
## Sharing Templates with Subcharts
Parent charts and subcharts can share templates. Any defined block in any chart is
available to other charts.
For example, we can define a simple template like this:
```yaml
{{- define "labels" }}from: mychart{{ end }}
```
Recall how the labels on templates are _globally shared_. Thus, the `labels` chart
can be included from any other chart.
While chart developers have a choice between `include` and `template`, one advantage
of using `include` is that `include` can dynamically reference templates:
```yaml
{{ include $mytemplate }}
```
The above will dereference `$mytemplate`. The `template` function, in contrast,
will only accept a string literal.
## Avoid Using Blocks
The Go template language provides a `block` keyword that allows developers to provide
a default implementation which is overridden later. In Helm charts, blocks are not
the best tool for overriding because it if multiple implementations of the same block
are provided, the one selected is unpredictable.
The suggestion is to instead use `include`.

@ -1,132 +0,0 @@
# Values Files
In the previous section we looked at the built-in objects that Helm templates offer. One of the four built-in objects is `Values`. This object provides access to values passed into the chart. Its contents come from four sources:
- The `values.yaml` file in the chart
- If this is a subchart, the `values.yaml` file of a parent chart
- A values file if passed into `helm install` or `helm upgrade` with the `-f` flag (`helm install -f myvals.yaml ./mychart`)
- Individual parameters passed with `--set` (such as `helm install --set foo=bar ./mychart`)
The list above is in order of specificity: `values.yaml` is the default, which can be overridden by a parent chart's `values.yaml`, which can in turn be overridden by a user-supplied values file, which can in turn be overridden by `--set` parameters.
Values files are plain YAML files. Let's edit `mychart/values.yaml` and then edit our ConfigMap template.
Removing the defaults in `values.yaml`, we'll set just one parameter:
```yaml
favoriteDrink: coffee
```
Now we can use this inside of a template:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favoriteDrink }}
```
Notice on the last line we access `favoriteDrink` as an attribute of `Values`: `{{ .Values.favoriteDrink}}`.
Let's see how this renders.
```console
$ helm install --dry-run --debug ./mychart
SERVER: "localhost:44134"
CHART PATH: /Users/mattbutcher/Code/Go/src/helm.sh/helm/_scratch/mychart
NAME: geared-marsupi
TARGET NAMESPACE: default
CHART: mychart 0.1.0
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: geared-marsupi-configmap
data:
myvalue: "Hello World"
drink: coffee
```
Because `favoriteDrink` is set in the default `values.yaml` file to `coffee`, that's the value displayed in the template. We can easily override that by adding a `--set` flag in our call to `helm install`:
```
helm install --dry-run --debug --set favoriteDrink=slurm ./mychart
SERVER: "localhost:44134"
CHART PATH: /Users/mattbutcher/Code/Go/src/helm.sh/helm/_scratch/mychart
NAME: solid-vulture
TARGET NAMESPACE: default
CHART: mychart 0.1.0
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: solid-vulture-configmap
data:
myvalue: "Hello World"
drink: slurm
```
Since `--set` has a higher precedence than the default `values.yaml` file, our template generates `drink: slurm`.
Values files can contain more structured content, too. For example, we could create a `favorite` section in our `values.yaml` file, and then add several keys there:
```yaml
favorite:
drink: coffee
food: pizza
```
Now we would have to modify the template slightly:
```
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink }}
food: {{ .Values.favorite.food }}
```
While structuring data this way is possible, the recommendation is that you keep your values trees shallow, favoring flatness. When we look at assigning values to subcharts, we'll see how values are named using a tree structure.
## Deleting a default key
If you need to delete a key from the default values, you may override the value of the key to be `null`, in which case Helm will remove the key from the overridden values merge.
For example, the stable Drupal chart allows configuring the liveness probe, in case you configure a custom image. Here are the default values:
```yaml
livenessProbe:
httpGet:
path: /user/login
port: http
initialDelaySeconds: 120
```
If you try to override the livenessProbe handler to `exec` instead of `httpGet` using `--set livenessProbe.exec.command=[cat,docroot/CHANGELOG.txt]`, Helm will coalesce the default and overridden keys together, resulting in the following YAML:
```yaml
livenessProbe:
httpGet:
path: /user/login
port: http
exec:
command:
- cat
- docroot/CHANGELOG.txt
initialDelaySeconds: 120
```
However, Kubernetes would then fail because you can not declare more than one livenessProbe handler. To overcome this, you may instruct Helm to delete the `livenessProbe.httpGet` by setting it to null:
```sh
helm install stable/drupal --set image=my-registry/drupal:0.1.0 --set livenessProbe.exec.command=[cat,docroot/CHANGELOG.txt] --set livenessProbe.httpGet=null
```
At this point, we've seen several built-in objects, and used them to inject information into a template. Now we will take a look at another aspect of the template engine: functions and pipelines.

@ -1,131 +0,0 @@
# Variables
With functions, pipelines, objects, and control structures under our belts, we can turn to one of the more basic ideas in many programming languages: variables. In templates, they are less frequently used. But we will see how to use them to simplify code, and to make better use of `with` and `range`.
In an earlier example, we saw that this code will fail:
```yaml
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ .Release.Name }}
{{- end }}
```
`Release.Name` is not inside of the scope that's restricted in the `with` block. One way to work around scoping issues is to assign objects to variables that can be accessed without respect to the present scope.
In Helm templates, a variable is a named reference to another object. It follows the form `$name`. Variables are assigned with a special assignment operator: `:=`. We can rewrite the above to use a variable for `Release.Name`.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- $relname := .Release.Name -}}
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ $relname }}
{{- end }}
```
Notice that before we start the `with` block, we assign `$relname := .Release.Name`. Now inside of the `with` block, the `$relname` variable still points to the release name.
Running that will produce this:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: viable-badger-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
release: viable-badger
```
Variables are particularly useful in `range` loops. They can be used on list-like objects to capture both the index and the value:
```yaml
toppings: |-
{{- range $index, $topping := .Values.pizzaToppings }}
{{ $index }}: {{ $topping }}
{{- end }}
```
Note that `range` comes first, then the variables, then the assignment operator, then the list. This will assign the integer index (starting from zero) to `$index` and the value to `$topping`. Running it will produce:
```yaml
toppings: |-
0: mushrooms
1: cheese
2: peppers
3: onions
```
For data structures that have both a key and a value, we can use `range` to get both. For example, we can loop through `.Values.favorite` like this:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end}}
```
Now on the first iteration, `$key` will be `drink` and `$val` will be `coffee`, and on the second, `$key` will be `food` and `$val` will be `pizza`. Running the above will generate this:
```yaml
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: eager-rabbit-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
```
Variables are normally not "global". They are scoped to the block in which they are declared. Earlier, we assigned `$relname` in the top level of the template. That variable will be in scope for the entire template. But in our last example, `$key` and `$val` will only be in scope inside of the `{{range...}}{{end}}` block.
However, there is one variable that is always global - `$` - this
variable will always point to the root context. This can be very
useful when you are looping in a range need to know the chart's release
name.
An example illustrating this:
```yaml
{{- range .Values.tlsSecrets }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .name }}
labels:
# Many helm templates would use `.` below, but that will not work,
# however `$` will work here
app.kubernetes.io/name: {{ template "fullname" $ }}
# I cannot reference .Chart.Name, but I can do $.Chart.Name
helm.sh/chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}"
app.kubernetes.io/instance: "{{ $.Release.Name }}"
# Value from appVersion in Chart.yaml
app.kubernetes.io/version: "{{ $.Chart.AppVersion }}"
app.kubernetes.io/managed-by: "{{ $.Release.Service }}"
type: kubernetes.io/tls
data:
tls.crt: {{ .certificate }}
tls.key: {{ .key }}
---
{{- end }}
```
So far we have looked at just one template declared in just one file. But one of the powerful features of the Helm template language is its ability to declare multiple templates and use them together. We'll turn to that in the next section.

@ -1,20 +0,0 @@
# Wrapping Up
This guide is intended to give you, the chart developer, a strong understanding of how to use Helm's template language. The guide focuses on the technical aspects of template development.
But there are many things this guide has not covered when it comes to the practical day-to-day development of charts. Here are some useful pointers to other documentation that will help you as you create new charts:
- The [Kubernetes Charts project](https://github.com/helm/charts) is an indispensable source of charts. That project is also sets the standard for best practices in chart development.
- The Kubernetes [User's Guide](http://kubernetes.io/docs/user-guide/) provides detailed examples of the various resource kinds that you can use, from ConfigMaps and Secrets to DaemonSets and Deployments.
- The Helm [Charts Guide](../charts.md) explains the workflow of using charts.
- The Helm [Chart Hooks Guide](../charts_hooks.md) explains how to create lifecycle hooks.
- The Helm [Charts Tips and Tricks](../charts_tips_and_tricks.md) article provides some useful tips for writing charts.
- The [Sprig documentation](https://github.com/Masterminds/sprig) documents more than sixty of the template functions.
- The [Go template docs](https://godoc.org/text/template) explain the template syntax in detail.
- The [Schelm tool](https://github.com/databus23/schelm) is a nice helper utility for debugging charts.
Sometimes it's easier to ask a few questions and get answers from experienced developers. The best place to do that is in the Kubernetes `#Helm` Slack channel:
- [Kubernetes Slack](https://slack.k8s.io/): `#helm`
Finally, if you find errors or omissions in this document, want to suggest some new content, or would like to contribute, visit [The Helm Project](https://github.com/helm/helm).

@ -1,349 +0,0 @@
# YAML Techniques
Most of this guide has been focused on writing the template language. Here,
we'll look at the YAML format. YAML has some useful features that we, as
template authors, can use to make our templates less error prone and easier
to read.
## Scalars and Collections
According to the [YAML spec](http://yaml.org/spec/1.2/spec.html), there are two
types of collections, and many scalar types.
The two types of collections are maps and sequences:
```yaml
map:
one: 1
two: 2
three: 3
sequence:
- one
- two
- three
```
Scalar values are individual values (as opposed to collections)
### Scalar Types in YAML
In Helm's dialect of YAML, the scalar data type of a value is determined by a
complex set of rules, including the Kubernetes schema for resource definitions.
But when inferring types, the following rules tend to hold true.
If an integer or float is an unquoted bare word, it is typically treated as
a numeric type:
```yaml
count: 1
size: 2.34
```
But if they are quoted, they are treated as strings:
```yaml
count: "1" # <-- string, not int
size: '2.34' # <-- string, not float
```
The same is true of booleans:
```yaml
isGood: true # bool
answer: "true" # string
```
The word for an empty value is `null` (not `nil`).
Note that `port: "80"` is valid YAML, and will pass through both the
template engine and the YAML parser, but will fail if Kubernetes expects
`port` to be an integer.
In some cases, you can force a particular type inference using YAML node tags:
```yaml
coffee: "yes, please"
age: !!str 21
port: !!int "80"
```
In the above, `!!str` tells the parser that `age` is a string, even if it looks
like an int. And `port` is treated as an int, even though it is quoted.
## Strings in YAML
Much of the data that we place in YAML documents are strings. YAML has more than
one way to represent a string. This section explains the ways and demonstrates
how to use some of them.
There are three "inline" ways of declaring a string:
```yaml
way1: bare words
way2: "double-quoted strings"
way3: 'single-quoted strings'
```
All inline styles must be on one line.
- Bare words are unquoted, and are not escaped. For this reason, you have to
be careful what characters you use.
- Double-quoted strings can have specific characters escaped with `\`. For
example `"\"Hello\", she said"`. You can escape line breaks with `\n`.
- Single-quoted strings are "literal" strings, and do not use the `\` to
escape characters. The only escape sequence is `''`, which is decoded as
a single `'`.
In addition to the one-line strings, you can declare multi-line strings:
```yaml
coffee: |
Latte
Cappuccino
Espresso
```
The above will treat the value of `coffee` as a single string equivalent to
`Latte\nCappuccino\nEspresso\n`.
Note that the first line after the `|` must be correctly indented. So we could
break the example above by doing this:
```yaml
coffee: |
Latte
Cappuccino
Espresso
```
Because `Latte` is incorrectly indented, we'd get an error like this:
```
Error parsing file: error converting YAML to JSON: yaml: line 7: did not find expected key
```
In templates, it is sometimes safer to put a fake "first line" of content in a
multi-line document just for protection from the above error:
```yaml
coffee: |
# Commented first line
Latte
Cappuccino
Espresso
```
Note that whatever that first line is, it will be preserved in the output of the
string. So if you are, for example, using this technique to inject a file's contents
into a ConfigMap, the comment should be of the type expected by whatever is
reading that entry.
### Controlling Spaces in Multi-line Strings
In the example above, we used `|` to indicate a multi-line string. But notice
that the content of our string was followed with a trailing `\n`. If we want
the YAML processor to strip off the trailing newline, we can add a `-` after the
`|`:
```yaml
coffee: |-
Latte
Cappuccino
Espresso
```
Now the `coffee` value will be: `Latte\nCappuccino\nEspresso` (with no trailing
`\n`).
Other times, we might want all trailing whitespace to be preserved. We can do
this with the `|+` notation:
```yaml
coffee: |+
Latte
Cappuccino
Espresso
another: value
```
Now the value of `coffee` will be `Latte\nCappuccino\nEspresso\n\n\n`.
Indentation inside of a text block is preserved, and results in the preservation
of line breaks, too:
```
coffee: |-
Latte
12 oz
16 oz
Cappuccino
Espresso
```
In the above case, `coffee` will be `Latte\n 12 oz\n 16 oz\nCappuccino\nEspresso`.
### Indenting and Templates
When writing templates, you may find yourself wanting to inject the contents of
a file into the template. As we saw in previous chapters, there are two ways
of doing this:
- Use `{{ .Files.Get "FILENAME" }}` to get the contents of a file in the chart.
- Use `{{ include "TEMPLATE" . }}` to render a template and then place its
contents into the chart.
When inserting files into YAML, it's good to understand the multi-line rules above.
Often times, the easiest way to insert a static file is to do something like
this:
```yaml
myfile: |
{{ .Files.Get "myfile.txt" | indent 2 }}
```
Note how we do the indentation above: `indent 2` tells the template engine to
indent every line in "myfile.txt" with two spaces. Note that we do not indent
that template line. That's because if we did, the file content of the first line
would be indented twice.
### Folded Multi-line Strings
Sometimes you want to represent a string in your YAML with multiple lines, but
want it to be treated as one long line when it is interpreted. This is called
"folding". To declare a folded block, use `>` instead of `|`:
```yaml
coffee: >
Latte
Cappuccino
Espresso
```
The value of `coffee` above will be `Latte Cappuccino Espresso\n`. Note that all
but the last line feed will be converted to spaces. You can combine the whitespace
controls with the folded text marker, so `>-` will replace or trim all newlines.
Note that in the folded syntax, indenting text will cause lines to be preserved.
```yaml
coffee: >-
Latte
12 oz
16 oz
Cappuccino
Espresso
```
The above will produce `Latte\n 12 oz\n 16 oz\nCappuccino Espresso`. Note that
both the spacing and the newlines are still there.
## Embedding Multiple Documents in One File
It is possible to place more than one YAML documents into a single file. This
is done by prefixing a new document with `---` and ending the document with
`...`
```yaml
---
document:1
...
---
document: 2
...
```
In many cases, either the `---` or the `...` may be omitted.
Some files in Helm cannot contain more than one doc. If, for example, more
than one document is provided inside of a `values.yaml` file, only the first
will be used.
Template files, however, may have more than one document. When this happens,
the file (and all of its documents) is treated as one object during
template rendering. But then the resulting YAML is split into multiple
documents before it is fed to Kubernetes.
We recommend only using multiple documents per file when it is absolutely
necessary. Having multiple documents in a file can be difficult to debug.
## YAML is a Superset of JSON
Because YAML is a superset of JSON, any valid JSON document _should_ be valid
YAML.
```json
{
"coffee": "yes, please",
"coffees": [
"Latte", "Cappuccino", "Espresso"
]
}
```
The above is another way of representing this:
```yaml
coffee: yes, please
coffees:
- Latte
- Cappuccino
- Espresso
```
And the two can be mixed (with care):
```yaml
coffee: "yes, please"
coffees: [ "Latte", "Cappuccino", "Espresso"]
```
All three of these should parse into the same internal representation.
While this means that files such as `values.yaml` may contain JSON data, Helm
does not treat the file extension `.json` as a valid suffix.
## YAML Anchors
The YAML spec provides a way to store a reference to a value, and later
refer to that value by reference. YAML refers to this as "anchoring":
```yaml
coffee: "yes, please"
favorite: &favoriteCoffee "Cappucino"
coffees:
- Latte
- *favoriteCoffee
- Espresso
```
In the above, `&favoriteCoffee` sets a reference to `Cappuccino`. Later, that
reference is used as `*favoriteCoffee`. So `coffees` becomes
`Latte, Cappuccino, Espresso`.
While there are a few cases where anchors are useful, there is one aspect of
them that can cause subtle bugs: The first time the YAML is consumed, the
reference is expanded and then discarded.
So if we were to decode and then re-encode the example above, the resulting
YAML would be:
```YAML
coffee: yes, please
favorite: Cappucino
coffees:
- Latte
- Cappucino
- Espresso
```
Because Helm and Kubernetes often read, modify, and then rewrite YAML files,
the anchors will be lost.

@ -1,83 +0,0 @@
# Chart Tests
A chart contains a number of Kubernetes resources and components that work together. As a chart author, you may want to write some tests that validate that your chart works as expected when it is installed. These tests also help the chart consumer understand what your chart is supposed to do.
A **test** in a helm chart lives under the `templates/` directory and is a pod definition that specifies a container with a given command to run. The container should exit successfully (exit 0) for a test to be considered a success. The pod definition must contain one of the helm test hook annotations: `helm.sh/hook: test-success` or `helm.sh/hook: test-failure`.
Example tests:
- Validate that your configuration from the values.yaml file was properly injected.
- Make sure your username and password work correctly
- Make sure an incorrect username and password does not work
- Assert that your services are up and correctly load balancing
- etc.
You can run the pre-defined tests in Helm on a release using the command `helm test <RELEASE_NAME>`. For a chart consumer, this is a great way to sanity check that their release of a chart (or application) works as expected.
## A Breakdown of the Helm Test Hooks
In Helm, there are two test hooks: `test-success` and `test-failure`
`test-success` indicates that test pod should complete successfully. In other words, the containers in the pod should exit 0.
`test-failure` is a way to assert that a test pod should not complete successfully. If the containers in the pod do not exit 0, that indicates success.
## Example Test
Here is an example of a helm test pod definition in an example mariadb chart:
```
mariadb/
Chart.yaml
README.md
values.yaml
charts/
templates/
templates/tests/test-mariadb-connection.yaml
```
In `wordpress/templates/tests/test-mariadb-connection.yaml`:
```
apiVersion: v1
kind: Pod
metadata:
name: "{{ .Release.Name }}-credentials-test"
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: {{ .Release.Name }}-credentials-test
image: {{ .Values.image }}
env:
- name: MARIADB_HOST
value: {{ template "mariadb.fullname" . }}
- name: MARIADB_PORT
value: "3306"
- name: WORDPRESS_DATABASE_NAME
value: {{ default "" .Values.mariadb.mariadbDatabase | quote }}
- name: WORDPRESS_DATABASE_USER
value: {{ default "" .Values.mariadb.mariadbUser | quote }}
- name: WORDPRESS_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: {{ template "mariadb.fullname" . }}
key: mariadb-password
command: ["sh", "-c", "mysql --host=$MARIADB_HOST --port=$MARIADB_PORT --user=$WORDPRESS_DATABASE_USER --password=$WORDPRESS_DATABASE_PASSWORD"]
restartPolicy: Never
```
## Steps to Run a Test Suite on a Release
1. `$ helm install mariadb`
```
NAME: quirky-walrus
LAST DEPLOYED: Mon Feb 13 13:50:43 2017
NAMESPACE: default
STATUS: DEPLOYED
```
2. `$ helm test quirky-walrus`
```
RUNNING: quirky-walrus-credentials-test
SUCCESS: quirky-walrus-credentials-test
```
## Notes
- You can define as many tests as you would like in a single yaml file or spread across several yaml files in the `templates/` directory
- You are welcome to nest your test suite under a `tests/` directory like `<chart-name>/templates/tests/` for more isolation

@ -1,935 +0,0 @@
# 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
values.schema.json # OPTIONAL: A JSON Schema for imposing a structure on the values.yaml file
charts/ # A directory containing any charts upon which this chart depends.
templates/ # 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 reserves use of the `charts/` and `templates/` directories, and of
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:
```yaml
name: The name of the chart (required)
version: A SemVer 2 version (required)
kubeVersion: A SemVer range of compatible Kubernetes versions (optional)
description: A single-sentence description of this project (optional)
type: It is the type of chart (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)
dependencies: # A list of the chart requirements (optional)
- name: The name of the chart (nginx)
version: The version of the chart ("1.2.3")
repository: The repository URL ("https://example.com/charts")
maintainers: # (optional)
- name: The maintainer's name (required for each maintainer)
email: The maintainer's email (optional for each maintainer)
url: A URL for the maintainer (optional for each maintainer)
icon: A URL to an SVG or PNG image to be used as an icon (optional).
appVersion: The version of the app that this contains (optional). This needn't be SemVer.
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
[SemVer 2](http://semver.org/) 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. 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.
### The appVersion field
Note that the `appVersion` field is not related to the `version` field. It is
a way of specifying the version of the application. For example, the `drupal`
chart may have an `appVersion: 8.2.1`, indicating that the version of Drupal
included in the chart (by default) is `8.2.1`. This field is informational, and
has no impact on chart version calculations.
### Deprecating Charts
When managing charts in a Chart Repository, it is sometimes necessary to
deprecate a chart. The optional `deprecated` field in `Chart.yaml` can be used
to mark a chart as deprecated. If the **latest** version of a chart in the
repository is marked as deprecated, then the chart as a whole is considered to
be deprecated. The chart name can later be reused by publishing a newer version
that is not marked as deprecated. The workflow for deprecating charts, as
followed by the [kubernetes/charts](https://github.com/helm/charts)
project is:
- Update chart's `Chart.yaml` to mark the chart as deprecated, bumping the
version
- 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 2 types: `application`
and `library`. Application is the default type and it is the standard chart
which can be operated on fully. The [library or helper chart](https://github.com/helm/charts/tree/master/incubator/common)
provides utilities or functions for the chart builder. A library chart differs
from an application chart because it has no resource object and is therefore not
installable.
**Note:** An application chart can be used as a library chart. This is enabled by setting the
type to `library`. The chart will then be rendered as a library chart where all utilities and
functions can be leveraged. All resource objects of 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 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](#templates-and-values), 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 can be dynamically linked using the `dependencies` field in `Chart.yaml` or brought 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 the `dependencies` field.
```yaml
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 defined dependencies, you can run `helm dependency update`
and it will use your dependency file to download all the specified
charts into your `charts/` directory for you.
```console
$ 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
```
#### Alias field in dependencies
In addition to the other fields above, each requirements entry may contain
the optional field `alias`.
Adding an alias for a dependency chart would put
a chart in dependencies using alias as name of new dependency.
One can use `alias` in cases where they need to access a chart
with other name(s).
```yaml
# parentchart/Chart.yaml
dependencies:
- name: subchart
repository: http://localhost:10191
version: 0.1.0
alias: new-subchart-1
- name: subchart
repository: http://localhost:10191
version: 0.1.0
alias: new-subchart-2
- name: subchart
repository: http://localhost:10191
version: 0.1.0
```
In the above example we will get 3 dependencies in all for `parentchart`
```
subchart
new-subchart-1
new-subchart-2
```
The manual way of achieving this is by copy/pasting the same chart in the
`charts/` directory multiple times with different names.
#### Tags and Condition fields in dependencies
In addition to the other fields above, each requirements entry may contain
the optional 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 are applied to.
Condition - The condition field holds one or more YAML paths (delimited by commas).
If this path exists in the top parent's values and resolves to a boolean value,
the chart will be enabled or disabled based on that boolean value. Only the first
valid path found in the list is evaluated and if no paths exist then the condition has no effect.
Tags - The tags field is a YAML list of labels to associate with this chart.
In the top parent's values, all charts with tags can be enabled or disabled by
specifying the tag and a boolean value.
````
# parentchart/Chart.yaml
dependencies:
- name: subchart1
repository: http://localhost:10191
version: 0.1.0
condition: subchart1.enabled, global.subchart1.enabled
tags:
- front-end
- subchart1
- name: subchart2
repository: http://localhost:10191
version: 0.1.0
condition: subchart2.enabled,global.subchart2.enabled
tags:
- back-end
- subchart2
````
````
# parentchart/values.yaml
subchart1:
enabled: true
tags:
front-end: false
back-end: true
````
In the above example all charts with the tag `front-end` would be disabled but since 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 a condition specified, there
is no corresponding path and value in the parent's values 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.
````
helm install --set tags.front-end=true --set subchart2.enabled=false
````
##### Tags and Condition Resolution
* **Conditions (when set in values) always override tags.** The first condition
path that exists wins and subsequent ones for that chart are ignored.
* Tags are evaluated as 'if any of the chart's tags are true then enable the chart'.
* 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 nested `tags:` 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 to the parent chart and be
shared as common defaults. An additional benefit of using the `exports` format is that it will enable future
tooling to introspect user-settable values.
The keys containing the values to be imported can be specified in the parent chart's `dependencies` in the field `input-values`
using a YAML list. Each item in 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 the [child-parent](#using-the-child-parent-format) format.
Examples of both formats are 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 the keys to import as in the example below:
```yaml
# parent's Chart.yaml file
dependencies:
- name: subchart
repository: http://localhost:10191
version: 0.1.0
import-values:
- data
```
```yaml
# child's values.yaml file
...
exports:
data:
myint: 99
```
Since we are specifying the key `data` in our import list, Helm looks in the `exports` field of the child
chart for `data` key and imports its contents.
The final parent values would contain our exported field:
```yaml
# parent's values file
...
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 child chart's values, you will need to
specify the source key of the values to be imported (`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 found at `child:` path and copy them
to the parent's values at the path specified in `parent:`
```yaml
# parent's Chart.yaml file
dependencies:
- name: subchart1
repository: http://localhost:10191
version: 0.1.0
...
import-values:
- child: default.data
parent: myimports
```
In the above example, values found at `default.data` in the subchart1's values will be imported
to the `myimports` key in the parent chart's values as detailed below:
```yaml
# parent's values.yaml file
myimports:
myint: 0
mybool: false
mystring: "helm rocks!"
```
```yaml
# subchart1's values.yaml file
default:
data:
myint: 999
mybool: true
```
The parent chart's resulting values would be:
```yaml
# parent's final values
myimports:
myint: 999
mybool: true
mystring: "helm rocks!"
```
The parent's final values now contains the `myint` and `mybool` fields imported from subchart1.
### Managing Dependencies manually via the `charts/` directory
If more control over dependencies is desired, these dependencies can
be 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.
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
# ...
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 pull` command_
### Operational aspects of using dependencies
The above sections explain how to specify chart dependencies, but how does this affect
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 the following order:
- A-Namespace
- B-Namespace
- A-StatefulSet
- B-ReplicaSet
- A-Service
- B-Service
This is because when Helm installs/upgrades charts,
the Kubernetes objects from the 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 its dependencies.
The install order of Kubernetes types is given by the enumeration InstallOrder in kind_sorter.go
(see [the Helm source file](https://github.com/helm/helm/blob/dev-v3/pkg/tiller/kind_sorter.go#L26)).
## Templates and Values
Helm Chart templates are written in the
[Go template language](https://golang.org/pkg/text/template/), with the
addition of 50 or so add-on template
functions [from the Sprig library](https://github.com/Masterminds/sprig) and a
few other [specialized functions](charts_tips_and_tricks.md).
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](https://golang.org/pkg/text/template/)
for details).
An example template file might look something like this:
```yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: deis-database
namespace: deis
labels:
app.kubernetes.io/managed-by: deis
spec:
replicas: 1
selector:
app.kubernetes.io/name: deis-database
template:
metadata:
labels:
app.kubernetes.io/name: 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](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.
To see many working charts, check out the [Kubernetes Charts
project](https://github.com/helm/charts)
### 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.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 an upgrade or rollback.
- `Release.IsInstall`: This is set to true if the current operation is an
install.
- `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 (unless they are excluded using `.helmignore`). 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}}`
- `Capabilities`: A map-like object that contains information about the versions
of Kubernetes (`{{.Capabilities.KubeVersion}}` and the supported Kubernetes
API versions (`{{.Capabilities.APIVersions.Has "batch/v1"`)
**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. The values
file can be used for that, though.
### Values files
Considering the template in the previous section, a `values.yaml` file
that supplies the necessary values would look like this:
```yaml
imageRegistry: "quay.io/deis"
dockerTag: "latest"
pullPolicy: "Always"
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:
```console
$ 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:
```yaml
storage: "gcs"
```
When this is merged with the `values.yaml` in the chart, the resulting
generated content will be:
```yaml
imageRegistry: "quay.io/deis"
dockerTag: "latest"
pullPolicy: "Always"
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.
**NOTE:** If the `--set` flag is used on `helm install` or `helm upgrade`, those
values are simply converted to YAML on the client side.
**NOTE:** If any required entries in the values file exist, they can be declared
as required in the chart template by using the ['required' function](charts_tips_and_tricks.md)
Any of these values are then accessible inside of templates using the
`.Values` object:
```yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: deis-database
namespace: deis
labels:
app.kubernetes.io/managed-by: deis
spec:
replicas: 1
selector:
app.kubernetes.io/name: deis-database
template:
metadata:
labels:
app.kubernetes.io/name: 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:
```yaml
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:
```yaml
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:
```yaml
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.
Also, global variables of parent charts take precedence over the global variables 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
schema is represented as a [JSON Schema](https://json-schema.org/).
It might look something like this:
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"image": {
"description": "Container Image",
"properties": {
"repo": {
"type": "string"
},
"tag": {
"type": "string"
}
},
"type": "object"
},
"name": {
"description": "Service name",
"type": "string"
},
"port": {
"description": "Port",
"minimum": 0,
"type": "integer"
},
"protocol": {
"type": "string"
}
},
"required": [
"protocol",
"port"
],
"title": "Values",
"type": "object"
}
```
This schema will be applied to the values to validate it. Validation occurs
when any of the following commands are invoked:
* `helm install`
* `helm upgrade`
* `helm lint`
* `helm template`
An example of a
`values.yaml` file that meets the requirements of this schema might look
something like this:
```yaml
name: frontend
protocol: https
port: 443
```
Note that the schema is applied to the final `.Values` object, and not just to
the `values.yaml` file. This means that the following `yaml` file is valid,
given that the chart is installed with the appropriate `--set` option shown
below.
```yaml
name: frontend
protocol: https
```
````
helm install --set port=443
````
Furthermore, the final `.Values` object is checked against *all* subchart
schemas. This means that restrictions on a subchart can't be circumvented by a
parent chart. This also works backwards - if a subchart has a requirement that
is not met in the subchart's `values.yaml` file, the parent chart *must*
satisfy those restrictions in order to be valid.
### References
When it comes to writing templates, values, and schema files, there are several
standard references that will help you out.
- [Go templates](https://godoc.org/text/template)
- [Extra template functions](https://godoc.org/github.com/Masterminds/sprig)
- [The YAML format](http://yaml.org/spec/)
- [JSON Schema](https://json-schema.org/)
## Using Helm to Manage Charts
The `helm` tool has several commands for working with charts.
It can create a new chart for you:
```console
$ helm create mychart
Created mychart/
```
Once you have edited a chart, `helm` can package it into a chart archive
for you:
```console
$ 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:
```console
$ 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.
## Chart Starter Packs
The `helm create` command takes an optional `--starter` option that lets you
specify a "starter chart".
Starters are just regular charts, but are located in `$HELM_HOME/starters`.
As a chart developer, you may author charts that are specifically designed
to be used as starters. Such charts should be designed with 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
should indicate how users can do so.
- All occurrences of `<CHARTNAME>` will be replaced with the specified chart
name so that starter charts can be used as templates.
Currently the only way to add a chart to `$HELM_HOME/starters` is to manually
copy it there. In your chart's documentation, you may want to explain that
process.

@ -1,199 +0,0 @@
# 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 back 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 Kubernetes apply operation).
- post-upgrade: Executes on an upgrade after all resources have been
upgraded.
- pre-rollback: Executes on a rollback request after templates are
rendered, but before any resources have been rolled back.
- post-rollback: Executes on a rollback request after all resources
have been modified.
## 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. The Helm library install API is called
3. After some verification, the library renders the `foo` templates
4. The library loads the resulting resources into Kubernetes
5. The library returns the release object (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. The Helm library install API is called
3. After some verification, the library renders the `foo` templates
4. The library prepares to execute the `pre-install` hooks (loading hook resources into
Kubernetes)
5. The library sorts hooks by weight (assigning a weight of 0 by default) and by name for those hooks with the same weight in ascending order.
6. The library then loads the hook with the lowest weight first (negative to positive)
7. The library waits until the hook is "Ready" (except for CRDs)
8. The library loads the resulting resources into Kubernetes. Note that if the `--wait`
flag is set, the library will wait until all resources are in a ready state
and will not run the `post-install` hook until they are ready.
9. The library executes the `post-install` hook (loading hook resources)
10. The library waits until the hook is "Ready"
11. The library returns the release object (and other data) to the client
12. 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, the library
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. If they
have hook weights (see below), they are executed in weighted order. Otherwise,
ordering is not guaranteed. (In Helm 2.3.0 and after, they are sorted
alphabetically. That behavior, though, is not considered binding and could change
in the future.) It is considered good practice to add a hook weight, and set it
to `0` if weight is not important.
### Hook resources are not managed with corresponding releases
The resources that a hook creates are not tracked or managed as part of the
release. Once Helm 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 uninstall` to remove the resources. To destroy such
resources, you need to either write code to perform this operation in a `pre-delete`
or `post-delete` hook or add `"helm.sh/hook-delete-policy"` annotation to the hook template file.
## Writing a Hook
Hooks are just Kubernetes manifest 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`:
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: "{{.Release.Name}}"
labels:
app.kubernetes.io/managed-by: {{.Release.Service | quote }}
app.kubernetes.io/instance: {{.Release.Name | quote }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
helm.sh/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
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
metadata:
name: "{{.Release.Name}}"
labels:
app.kubernetes.io/managed-by: {{.Release.Service | quote }}
app.kubernetes.io/instance: {{.Release.Name | quote }}
helm.sh/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
and a config map as a pre-install hook.
When subcharts declare hooks, those are also evaluated. There is no way
for a top-level chart to disable the hooks declared by subcharts.
It is possible to define a weight for a hook which will help build a
deterministic executing order. Weights are defined using the following annotation:
```
annotations:
"helm.sh/hook-weight": "5"
```
Hook weights can be positive or negative numbers but must be represented as
strings. When Helm starts the execution cycle of hooks of a particular Kind it
will sort those hooks in ascending order.
It is also possible to define policies that determine when to delete corresponding hook resources. Hook deletion policies are defined using the following annotation:
```
annotations:
"helm.sh/hook-delete-policy": hook-succeeded
```
You can choose one or more defined annotation values:
* `"hook-succeeded"` specifies Helm should delete the hook after the hook is successfully executed.
* `"hook-failed"` specifies Helm should delete the hook if the hook failed during execution.
* `"before-hook-creation"` specifies Helm should delete the previous hook before the new hook is launched.
### Automatically uninstall hook from previous release
When helm release being updated it is possible, that hook resource already exists in cluster. By default helm will try to create resource and fail with `"... already exists"` error.
One might choose `"helm.sh/hook-delete-policy": "before-hook-creation"` over `"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"` because:
* It is convenient to keep failed hook job resource in kubernetes for example for manual debug.
* It may be necessary to keep succeeded hook resource in kubernetes for some reason.
* At the same time it is not desirable to do manual resource deletion before helm release upgrade.
`"helm.sh/hook-delete-policy": "before-hook-creation"` annotation on hook causes Helm to remove the hook from previous release if there is one before the new hook is launched and can be used with another policy.

@ -1,248 +0,0 @@
# Chart Development Tips and Tricks
This guide covers some of the tips and tricks Helm chart developers have
learned while building production-quality charts.
## Know Your Template Functions
Helm uses [Go templates](https://godoc.org/text/template) for templating
your resource files. While Go ships several built-in functions, we have
added many others.
First, we added all of the functions in the
[Sprig library](https://godoc.org/github.com/Masterminds/sprig).
We also added two special template functions: `include` and `required`. The `include`
function allows you to bring in another template, and then pass the results to other
template functions.
For example, this template snippet includes a template called `mytpl`, then
lowercases the result, then wraps that in double quotes.
```yaml
value: {{include "mytpl" . | lower | quote}}
```
The `required` function allows you to declare a particular
values entry as required for template rendering. If the value is empty, the template
rendering will fail with a user submitted error message.
The following example of the `required` function declares an entry for .Values.who
is required, and will print an error message when that entry is missing:
```yaml
value: {{required "A valid .Values.who entry required!" .Values.who }}
```
## Quote Strings, Don't Quote Integers
When you are working with string data, you are always safer quoting the
strings than leaving them as bare words:
```
name: {{.Values.MyName | quote }}
```
But when working with integers _do not quote the values._ That can, in
many cases, cause parsing errors inside of Kubernetes.
```
port: {{ .Values.Port }}
```
This remark does not apply to env variables values which are expected to be string, even if they represent integers:
```
env:
-name: HOST
value: "http://host"
-name: PORT
value: "1234"
```
## Using the 'include' Function
Go provides a way of including one template in another using a built-in
`template` directive. However, the built-in function cannot be used in
Go template pipelines.
To make it possible to include a template, and then perform an operation
on that template's output, Helm has a special `include` function:
```
{{ include "toYaml" $value | indent 2 }}
```
The above includes a template called `toYaml`, passes it `$value`, and
then passes the output of that template to the `indent` function.
Because YAML ascribes significance to indentation levels and whitespace,
this is one great way to include snippets of code, but handle
indentation in a relevant context.
## Using the 'required' function
Go provides a way for setting template options to control behavior
when a map is indexed with a key that's not present in the map. This
is typically set with template.Options("missingkey=option"), where option
can be default, zero, or error. While setting this option to error will
stop execution with an error, this would apply to every missing key in the
map. There may be situations where a chart developer wants to enforce this
behavior for select values in the values.yml file.
The `required` function gives developers the ability to declare a value entry
as required for template rendering. If the entry is empty in values.yml, the
template will not render and will return an error message supplied by the
developer.
For example:
```
{{ required "A valid foo is required!" .Values.foo }}
```
The above will render the template when .Values.foo is defined, but will fail
to render and exit when .Values.foo is undefined.
## Creating Image Pull Secrets
Image pull secrets are essentially a combination of _registry_, _username_, and _password_. You may need them in an application you are deploying, but to create them requires running _base64_ a couple of times. We can write a helper template to compose the Docker configuration file for use as the Secret's payload. Here is an example:
First, assume that the credentials are defined in the `values.yaml` file like so:
```
imageCredentials:
registry: quay.io
username: someone
password: sillyness
```
We then define our helper template as follows:
```
{{- define "imagePullSecret" }}
{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.imageCredentials.registry (printf "%s:%s" .Values.imageCredentials.username .Values.imageCredentials.password | b64enc) | b64enc }}
{{- end }}
```
Finally, we use the helper template in a larger template to create the Secret manifest:
```
apiVersion: v1
kind: Secret
metadata:
name: myregistrykey
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ template "imagePullSecret" . }}
```
## Automatically Roll Deployments When ConfigMaps or Secrets change
Often times configmaps or secrets are injected as configuration
files in containers.
Depending on the application a restart may be required should those
be updated with a subsequent `helm upgrade`, but if the
deployment spec itself didn't change the application keeps running
with the old configuration resulting in an inconsistent deployment.
The `sha256sum` function can be used to ensure a deployment's
annotation section is updated if another file changes:
```yaml
kind: Deployment
spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
[...]
```
See also the `helm upgrade --recreate-pods` flag for a slightly
different way of addressing this issue.
## Tell Helm Not To Uninstall a Resource
Sometimes there are resources that should not be uninstalled when Helm runs a
`helm uninstall`. Chart developers can add an annotation to a resource to prevent
it from being uninstalled.
```yaml
kind: Secret
metadata:
annotations:
"helm.sh/resource-policy": keep
[...]
```
(Quotation marks are required)
The annotation `"helm.sh/resource-policy": keep` instructs Helm to skip this
resource during a `helm uninstall` operation. _However_, this resource becomes
orphaned. Helm will no longer manage it in any way. This can lead to problems
if using `helm install --replace` on a release that has already been uninstalled, but
has kept resources.
## Using "Partials" and Template Includes
Sometimes you want to create some reusable parts in your chart, whether
they're blocks or template partials. And often, it's cleaner to keep
these in their own files.
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
`_helpers.tpl` file.
## Complex Charts with Many Dependencies
Many of the charts in the [official charts repository](https://github.com/helm/charts)
are "building blocks" for creating more advanced applications. But charts may be
used to create instances of large-scale applications. In such cases, a single
umbrella chart may have multiple subcharts, each of which functions as a piece
of the whole.
The current best practice for composing a complex application from discrete parts
is to create a top-level umbrella chart that
exposes the global configurations, and then use the `charts/` subdirectory to
embed each of the components.
Two strong design patterns are illustrated by these projects:
**SAP's [OpenStack chart](https://github.com/sapcc/openstack-helm):** This chart
installs a full OpenStack IaaS on Kubernetes. All of the charts are collected
together in one GitHub repository.
**Deis's [Workflow](https://github.com/deis/workflow/tree/master/charts/workflow):**
This chart exposes the entire Deis PaaS system with one chart. But it's different
from the SAP chart in that this umbrella chart is built from each component, and
each component is tracked in a different Git repository. Check out the
`requirements.yaml` file to see how this chart is composed by their CI/CD
pipeline.
Both of these charts illustrate proven techniques for standing up complex environments
using Helm.
## YAML is a Superset of JSON
According to the YAML specification, YAML is a superset of JSON. That
means that any valid JSON structure ought to be valid in YAML.
This has an advantage: Sometimes template developers may find it easier
to express a datastructure with a JSON-like syntax rather than deal with
YAML's whitespace sensitivity.
As a best practice, templates should follow a YAML-like syntax _unless_
the JSON syntax substantially reduces the risk of a formatting issue.
## Be Careful with Generating Random Values
There are functions in Helm that allow you to generate random data,
cryptographic keys, and so on. These are fine to use. But be aware that
during upgrades, templates are re-executed. When a template run
generates data that differs from the last run, that will trigger an
update of that resource.
## Upgrade a release idempotently
In order to use the same command when installing and upgrading a release, use the following command:
```shell
helm upgrade --install <release name> --values <values file> <chart directory>
```

@ -1,148 +0,0 @@
# Developers Guide
This guide explains how to set up your environment for developing on
Helm.
## Prerequisites
- The latest version of Go
- The latest version of Dep
- A Kubernetes cluster w/ kubectl (optional)
- Git
## Building Helm
We use Make to build our programs. The simplest way to get started is:
```console
$ make
```
NOTE: This will fail if not running from the path `$GOPATH/src/helm.sh/helm`. The
directory `helm.sh` should not be a symlink or `build` will not find the relevant
packages.
If required, this will first install dependencies, rebuild the `vendor/` tree, and
validate configuration. It will then compile `helm` and place it in `bin/helm`.
To run all the tests (without running the tests for `vendor/`), run
`make test`.
To run Helm locally, you can run `bin/helm`.
- Helm is known to run on macOS and most Linux distributions, including Alpine.
### Man pages
Man pages and Markdown documentation are not pre-built in `docs/` but you can
generate the documentation using `make docs`.
To expose the Helm man pages to your `man` client, you can put the files in your
`$MANPATH`:
```
$ export MANPATH=$GOPATH/src/helm.sh/helm/docs/man:$MANPATH
$ man helm
```
## Docker Images
To build Docker images, use `make docker-build`.
Pre-build images are already available in the official Kubernetes Helm
GCR registry.
## Running a Local Cluster
For development, we highly recommend using the
[Kubernetes Minikube](https://github.com/kubernetes/minikube)
developer-oriented distribution.
## Contribution Guidelines
We welcome contributions. This project has set up some guidelines in
order to ensure that (a) code quality remains high, (b) the project
remains consistent, and (c) contributions follow the open source legal
requirements. Our intent is not to burden contributors, but to build
elegant and high-quality open source code so that our users will benefit.
Make sure you have read and understood the main CONTRIBUTING guide:
https://github.com/helm/helm/blob/master/CONTRIBUTING.md
### Structure of the Code
The code for the Helm project is organized as follows:
- The individual programs are located in `cmd/`. Code inside of `cmd/`
is not designed for library re-use.
- Shared libraries are stored in `pkg/`.
- The `scripts/` directory contains a number of utility scripts. Most of these
are used by the CI/CD pipeline.
- The `docs/` folder is used for documentation and examples.
Go dependencies are managed with
[Dep](https://github.com/golang/dep) and stored in the
`vendor/` directory.
### Git Conventions
We use Git for our version control system. The `master` branch is the
home of the current development candidate. Releases are tagged.
We accept changes to the code via GitHub Pull Requests (PRs). One
workflow for doing this is as follows:
1. Go to your `$GOPATH/src` directory, then `mkdir helm.sh; cd helm.sh` and `git clone` the
`github.com/helm/helm` repository.
2. Fork that repository into your GitHub account
3. Add your repository as a remote for `$GOPATH/src/helm.sh/helm`
4. Create a new working branch (`git checkout -b feat/my-feature`) and
do your work on that branch.
5. When you are ready for us to review, push your branch to GitHub, and
then open a new pull request with us.
For Git commit messages, we follow the [Semantic Commit Messages](http://karma-runner.github.io/0.13/dev/git-commit-msg.html):
```
fix(helm): add --foo flag to 'helm install'
When 'helm install --foo bar' is run, this will print "foo" in the
output regardless of the outcome of the installation.
Closes #1234
```
Common commit types:
- fix: Fix a bug or error
- feat: Add a new feature
- docs: Change documentation
- test: Improve testing
- ref: refactor existing code
Common scopes:
- helm: The Helm CLI
- pkg/lint: The lint package. Follow a similar convention for any
package
- `*`: two or more scopes
Read more:
- The [Deis Guidelines](https://github.com/deis/workflow/blob/master/src/contributing/submitting-a-pull-request.md)
were the inspiration for this section.
- Karma Runner [defines](http://karma-runner.github.io/0.13/dev/git-commit-msg.html) the semantic commit message idea.
### Go Conventions
We follow the Go coding style standards very closely. Typically, running
`go fmt` will make your code beautiful for you.
We also typically follow the conventions recommended by `go lint` and
`gometalinter`. Run `make test-style` to test the style conformance.
Read more:
- Effective Go [introduces formatting](https://golang.org/doc/effective_go.html#formatting).
- The Go Wiki has a great article on [formatting](https://github.com/golang/go/wiki/CodeReviewComments).

@ -1,19 +0,0 @@
# Helm Examples
This directory contains example charts to help you get started with
chart development.
## Alpine
The `alpine` chart is very simple, and is a good starting point.
It simply deploys a single pod running Alpine Linux.
## Nginx
The `nginx` chart shows how to compose several resources into one chart,
and it illustrates more complex template usage.
It deploys a `deployment` (which creates a `replica set`), a `config
map`, and a `service`. The replica set starts an nginx pod. The config
map stores the files that the nginx server can serve.

@ -1,8 +0,0 @@
apiVersion: v1
name: alpine
description: Deploy a basic Alpine Linux pod
version: 0.1.0
home: https://github.com/helm/helm
sources:
- https://github.com/helm/helm
appVersion: 3.3

@ -1,11 +0,0 @@
# Alpine: A simple Helm chart
Run a single pod of Alpine Linux.
The `templates/` directory contains a very simple pod resource with a
couple of parameters.
The `values.yaml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.

@ -1,16 +0,0 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "alpine.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "alpine.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

@ -1,24 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: {{ template "alpine.fullname" . }}
labels:
# The "app.kubernetes.io/managed-by" label is used to track which tool deployed a given chart.
# It is useful for admins who want to see what releases a particular tool
# is responsible for.
app.kubernetes.io/managed-by: {{ .Release.Service }}
# The "app.kubernetes.io/instance" convention makes it easy to tie a release to all of the
# Kubernetes resources that were created as part of that release.
app.kubernetes.io/instance: {{ .Release.Name | quote }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
# This makes it easy to audit chart usage.
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/name: {{ template "alpine.name" . }}
spec:
# This shows how to use a simple value. This will look for a passed-in value called restartPolicy.
restartPolicy: {{ .Values.restartPolicy }}
containers:
- name: waiter
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
command: ["/bin/sleep", "9000"]

@ -1,6 +0,0 @@
image:
repository: alpine
tag: 3.3
pullPolicy: IfNotPresent
restartPolicy: Never

@ -1,5 +0,0 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
.git

@ -1,16 +0,0 @@
apiVersion: v1
name: nginx
description: A basic NGINX HTTP server
version: 0.1.0
kubeVersion: ">=1.2.0"
keywords:
- http
- nginx
- www
- web
home: https://github.com/helm/helm
sources:
- https://hub.docker.com/_/nginx/
maintainers:
- name: technosophos
email: mbutcher@deis.com

@ -1,33 +0,0 @@
# nginx: An advanced example chart
This Helm chart provides examples of some of Helm's more powerful
features.
**This is not a production-grade chart. It is an example.**
The chart installs a simple nginx server according to the following
pattern:
- A `ConfigMap` is used to store the files the server will serve.
([templates/configmap.yaml](templates/configmap.yaml))
- A `Deployment` is used to create a Replica Set of nginx pods.
([templates/deployment.yaml](templates/deployment.yaml))
- A `Service` is used to create a gateway to the pods running in the
replica set ([templates/service.yaml](templates/service.yaml))
The [values.yaml](values.yaml) exposes a few of the configuration options in the
charts, though there are some that are not exposed there (like
`.image`).
The [templates/_helpers.tpl](templates/_helpers.tpl) file contains helper templates. The leading
underscore (`_`) on the filename is semantic. It tells the template renderer
that this file does not contain a manifest. That file declares some
templates that are used elsewhere in the chart.
Helpers (usually called "partials" in template languages) are an
advanced way for developers to structure their templates for optimal
reuse.
You can deploy this chart with `helm install docs/examples/nginx`. Or
you can see how this chart would render with `helm install --dry-run
--debug docs/examples/nginx`.

@ -1,8 +0,0 @@
apiVersion: v1
name: alpine
description: Deploy a basic Alpine Linux pod
version: 0.1.0
home: https://github.com/helm/helm
sources:
- https://github.com/helm/helm
appVersion: 3.3

@ -1,11 +0,0 @@
# Alpine: A simple Helm chart
Run a single pod of Alpine Linux.
The `templates/` directory contains a very simple pod resource with a
couple of parameters.
The `values.yaml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.

@ -1,16 +0,0 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "alpine.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "alpine.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

@ -1,24 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: {{ template "alpine.fullname" . }}
labels:
# The "app.kubernetes.io/managed-by" label is used to track which tool
# deployed a given chart. It is useful for admins who want to see what
# releases a particular tool is responsible for.
app.kubernetes.io/managed-by: {{.Release.Service | quote }}
# The "app.kubernetes.io/instance" convention makes it easy to tie a release
# to all of the Kubernetes resources that were created as part of that
# release.
app.kubernetes.io/instance: {{.Release.Name | quote }}
# This makes it easy to audit chart usage.
helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}"
app.kubernetes.io/name: {{ template "alpine.name" . }}
spec:
# This shows how to use a simple value. This will look for a passed-in value called restartPolicy.
restartPolicy: {{ .Values.restartPolicy }}
containers:
- name: waiter
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
command: ["/bin/sleep", "9000"]

@ -1,6 +0,0 @@
image:
repository: alpine
tag: 3.3
pullPolicy: IfNotPresent
restartPolicy: Never

@ -1 +0,0 @@
Sample notes for {{ .Chart.Name }}

@ -1,16 +0,0 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "nginx.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "nginx.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

@ -1,14 +0,0 @@
# This is a simple example of using a config map to create a single page static site.
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "nginx.fullname" . }}
labels:
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/name: {{ template "nginx.name" . }}
data:
# When the config map is mounted as a volume, these will be created as files.
index.html: {{ .Values.index | quote }}
test.txt: test

@ -1,57 +0,0 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
# This uses a "fullname" template (see _helpers)
# Basing names on .Release.Name means that the same chart can be installed
# multiple times into the same namespace.
name: {{ template "nginx.fullname" . }}
labels:
# The "app.kubernetes.io/managed-by" label is used to track which tool deployed a given chart.
# It is useful for admins who want to see what releases a particular tool
# is responsible for.
app.kubernetes.io/managed-by: {{ .Release.Service }}
# The "app.kubernetes.io/instance" convention makes it easy to tie a release to all of the
# Kubernetes resources that were created as part of that release.
app.kubernetes.io/instance: {{ .Release.Name }}
# This makes it easy to audit chart usage.
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/name: {{ template "nginx.name" . }}
spec:
replicas: {{ .Values.replicaCount }}
template:
metadata:
{{- if .Values.podAnnotations }}
# Allows custom annotations to be specified
annotations:
{{ toYaml .Values.podAnnotations | indent 8 }}
{{- end }}
labels:
app.kubernetes.io/name: {{ template "nginx.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
containers:
- name: {{ template "nginx.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
# This (and the volumes section below) mount the config map as a volume.
volumeMounts:
- mountPath: /usr/share/nginx/html
name: wwwdata-volume
resources:
# Allow chart users to specify resources. Usually, no default should be set, so this is left to be a conscious
# choice to the chart users and avoids that charts don't run out of the box on, e. g., Minikube when high resource
# requests are specified by default.
{{ toYaml .Values.resources | indent 12 }}
{{- if .Values.nodeSelector }}
nodeSelector:
# Node selectors can be important on mixed Windows/Linux clusters.
{{ toYaml .Values.nodeSelector | indent 8 }}
{{- end }}
volumes:
- name: wwwdata-volume
configMap:
name: {{ template "nginx.fullname" . }}

@ -1,37 +0,0 @@
apiVersion: batch/v1
kind: Job
metadata:
name: {{ template "nginx.fullname" . }}
labels:
# The "app.kubernetes.io/managed-by" label is used to track which tool deployed a given chart.
# It is useful for admins who want to see what releases a particular tool
# is responsible for.
app.kubernetes.io/managed-by: {{ .Release.Service }}
# The "app.kubernetes.io/instance" convention makes it easy to tie a release to all of the
# Kubernetes resources that were created as part of that release.
app.kubernetes.io/instance: {{ .Release.Name }}
# This makes it easy to audit chart usage.
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/name: {{ template "nginx.name" . }}
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: {{ template "nginx.fullname" . }}
labels:
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/name: {{ template "nginx.name" . }}
spec:
# This shows how to use a simple value. This will look for a passed-in value
# called restartPolicy. If it is not found, it will use the default value.
# {{ default "Never" .restartPolicy }} is a slightly optimized version of the
# more conventional syntax: {{ .restartPolicy | default "Never" }}
restartPolicy: {{ .Values.restartPolicy }}
containers:
- name: post-install-job
image: "alpine:3.3"
# All we're going to do is sleep for a while, then exit.
command: ["/bin/sleep", "{{ .Values.sleepyTime }}"]

@ -1,19 +0,0 @@
# This shows a secret as a pre-install hook.
# A pre-install hook is run before the rest of the chart is loaded.
apiVersion: v1
kind: Secret
metadata:
name: {{ template "nginx.fullname" . }}
labels:
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/name: {{ template "nginx.name" . }}
# This declares the resource to be a hook. By convention, we also name the
# file "pre-install-XXX.yaml", but Helm itself doesn't care about file names.
annotations:
"helm.sh/hook": pre-install
type: Opaque
data:
password: {{ b64enc "secret" }}
username: {{ b64enc "user1" }}

@ -1,18 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ template "nginx.fullname" . }}-service-test"
labels:
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/name: {{ template "nginx.name" . }}
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: curl
image: radial/busyboxplus:curl
command: ['curl']
args: ['{{ template "nginx.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

@ -1,39 +0,0 @@
apiVersion: v1
kind: Service
metadata:
{{- if .Values.service.annotations }}
annotations:
{{ toYaml .Values.service.annotations | indent 4 }}
{{- end }}
labels:
app.kubernetes.io/name: {{ template "nginx.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
name: {{ template "nginx.fullname" . }}
spec:
# Provides options for the service so chart users have the full choice
type: "{{ .Values.service.type }}"
clusterIP: "{{ .Values.service.clusterIP }}"
{{- if .Values.service.externalIPs }}
externalIPs:
{{ toYaml .Values.service.externalIPs | indent 4 }}
{{- end }}
{{- if .Values.service.loadBalancerIP }}
loadBalancerIP: "{{ .Values.service.loadBalancerIP }}"
{{- end }}
{{- if .Values.service.loadBalancerSourceRanges }}
loadBalancerSourceRanges:
{{ toYaml .Values.service.loadBalancerSourceRanges | indent 4 }}
{{- end }}
ports:
- name: http
port: {{ .Values.service.port }}
protocol: TCP
targetPort: http
{{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort))) }}
nodePort: {{ .Values.service.nodePort }}
{{- end }}
selector:
app.kubernetes.io/name: {{ template "nginx.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}

@ -1,34 +0,0 @@
# Default values for nginx.
# This is a YAML-formatted file.
# Declare name/value pairs to be passed into your templates.
replicaCount: 1
restartPolicy: Never
# Evaluated by the post-install hook
sleepyTime: "10"
index: >-
<h1>Hello</h1>
<p>This is a test</p>
image:
repository: nginx
tag: 1.11.0
pullPolicy: IfNotPresent
service:
annotations: {}
clusterIP: ""
externalIPs: []
loadBalancerIP: ""
loadBalancerSourceRanges: []
type: ClusterIP
port: 8888
nodePort: ""
podAnnotations: {}
resources: {}
nodeSelector: {}

@ -1,255 +0,0 @@
# Frequently Asked Questions
This page provides help with the most common questions about Helm.
**We'd love your help** making this document better. To add, correct, or remove
information, [file an issue](https://github.com/helm/helm/issues) or
send us a pull request.
## Changes since Helm 2
Here's an exhaustive list of all the major changes introduced in Helm 3.
### Removal of Tiller
During the Helm 2 development cycle, we introduced Tiller. Tiller played an important role for teams working on a shared
cluster - it made it possible for multiple different operators to interact with the same set of releases.
With role-based access controls (RBAC) enabled by default in Kubernetes 1.6, locking down Tiller for use in a production
scenario became more difficult to manage. Due to the vast number of possible security policies, our stance was to
provide a permissive default configuration. This allowed first-time users to start experimenting with Helm and
Kubernetes without having to dive headfirst into the security controls. Unfortunately, this permissive configuration
could grant a user a broad range of permissions they werent intended to have. DevOps and SREs had to learn additional
operational steps when installing Tiller into a multi-tenant cluster.
After hearing how community members were using Helm in certain scenarios, we found that Tillers release management
system did not need to rely upon an in-cluster operator to maintain state or act as a central hub for Helm release
information. Instead, we could simply fetch information from the Kubernetes API server, render the Charts client-side,
and store a record of the installation in Kubernetes.
Tillers primary goal could be accomplished without Tiller, so one of the first decisions we made regarding Helm 3 was
to completely remove Tiller.
With Tiller gone, the security model for Helm is radically simplified. Helm 3 now supports all the modern security,
identity, and authorization features of modern Kubernetes. Helms permissions are evaluated using your [kubeconfig file](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/).
Cluster administrators can restrict user permissions at whatever granularity they see fit. Releases are still recorded
in-cluster, and the rest of Helms functionality remains.
### Release Names are now scoped to the Namespace
With the removal of Tiller, the information about each release had to go somewhere. In Helm 2, this was stored in the
same namespace as Tiller. In practice, this meant that once a name was used by a release, no other release could use
that same name, even if it was deployed in a different namespace.
In Helm 3, release information about a particular release is now stored in the same namespace as the release itself.
This means that users can now `helm install wordpress stable/wordpress` in two separate namespaces, and each can be
referred with `helm list` by changing the current namespace context.
### Go import path changes
In Helm 3, Helm switched the Go import path over from `k8s.io/helm` to `helm.sh/helm`. If you intend
to upgrade to the Helm 3 Go client libraries, make sure to change your import paths.
### Capabilities
The `.Capabilities` built-in object available during the rendering stage has been simplified.
[Built-in Objects](chart_template_guide/builtin_objects.md)
### Validating Chart Values with JSONSchema
A JSON Schema can now be imposed upon chart values. This ensures that values provided by the user follow the schema
laid out by the chart maintainer, providing better error reporting when the user provides an incorrect set of values for
a chart.
Validation occurs when any of the following commands are invoked:
* `helm install`
* `helm upgrade`
* `helm template`
* `helm lint`
See the documentation on [Schema files](charts.md#schema-files) for more information.
### Consolidation of requirements.yaml into Chart.yaml
The Chart dependency management system moved from requirements.yaml and requirements.lock to Chart.yaml and Chart.lock,
meaning that charts that relied on the `helm dependency` subcommands will need some tweaking to work in Helm 3.
In Helm 2, this is how a requirements.yaml looked:
```
dependencies:
- name: mariadb
version: 5.x.x
repository: https://kubernetes-charts.storage.googleapis.com/
condition: mariadb.enabled
tags:
- database
```
In Helm 3, the dependency is expressed the same way, but now from your Chart.yaml:
```
dependencies:
- name: mariadb
version: 5.x.x
repository: https://kubernetes-charts.storage.googleapis.com/
condition: mariadb.enabled
tags:
- database
```
Charts are still downloaded and placed in the charts/ directory, so subcharts vendored into the charts/ directory will continue to work without modification.
### Name (or --generate-name) is now required on install
In Helm 2, if no name was provided, an auto-generated name would be given. In production, this proved to be more of a
nuisance than a helpful feature. In Helm 3, Helm will throw an error if no name is provided with `helm install`.
For those who still wish to have a name auto-generated for you, you can use the `--generate-name` flag to create one for
you.
### Pushing Charts to OCI Registries
At a high level, a Chart Repository is a location where Charts can be stored and shared. The Helm client packs and ships
Helm Charts to a Chart Repository. Simply put, a Chart Repository is a basic HTTP server that houses an index.yaml file
and some packaged charts.
While there are several benefits to the Chart Repository API meeting the most basic storage requirements, a few
drawbacks have started to show:
- Chart Repositories have a very hard time abstracting most of the security implementations required in a production environment. Having a standard API for authentication and authorization is very important in production scenarios.
- Helms Chart provenance tools used for signing and verifying the integrity and origin of a chart are an optional piece of the Chart publishing process.
- In multi-tenant scenarios, the same Chart can be uploaded by another tenant, costing twice the storage cost to store the same content. Smarter chart repositories have been designed to handle this, but its not a part of the formal specification.
- Using a single index file for search, metadata information, and fetching Charts has made it difficult or clunky to design around in secure multi-tenant implementations.
Dockers Distribution project (also known as Docker Registry v2) is the successor to the Docker Registry project. Many
major cloud vendors have a product offering of the Distribution project, and with so many vendors offering the same
product, the Distribution project has benefited from many years of hardening, security best practices, and
battle-testing.
Please have a look at `helm help chart` and `helm help registry` for more information on how to package a chart and
push it to a Docker registry.
For more info, please see [this page](./registries.md).
### Removal of helm serve
`helm serve` ran a local Chart Repository on your machine for development purposes. However, it didn't receive much
uptake as a development tool and had numerous issues with its design. In the end, we decided to remove it and split it
out as a plugin.
### Library chart support
Helm 3 supports a class of chart called a “library chart”. This is a chart that is shared by other charts, but does not
create any release artifacts of its own. A library charts templates can only declare `define` elements. Globally scoped
non-`define` content is simply ignored. This allows users to re-use and share snippets of code that can be re-used across
many charts, avoiding redundancy and keeping charts [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself).
Library charts are declared in the dependencies directive in Chart.yaml, and are installed and managed like any other
chart.
```
dependencies:
- name: mylib
version: 1.x.x
repository: quay.io
```
Were very excited to see the use cases this feature opens up for chart developers, as well as any best practices that
arise from consuming library charts.
### CLI Command Renames
In order to better align the verbiage from other package managers, `helm delete` was re-named to
`helm uninstall`. `helm delete` is still retained as an alias to `helm uninstall`, so either form
can be used.
In Helm 2, in order to purge the release ledger, the `--purge` flag had to be provided. This
functionality is now enabled by default. To retain the previous behaviour, use
`helm uninstall --keep-history`.
Additionally, several other commands were re-named to accommodate the same conventions:
- `helm inspect` -> `helm show`
- `helm fetch` -> `helm pull`
These commands have also retained their older verbs as aliases, so you can continue to use them in either form.
### Automatically creating namespaces
When creating a release in a namespace that does not exist, Helm 2 created the
namespace. Helm 3 follows the behavior of other Kubernetes objects and returns
an error if the namespace does not exist.
## Installing
### Why aren't there Debian/Fedora/... native packages of Helm?
We'd love to provide these or point you toward a trusted provider. If you're
interested in helping, we'd love it. This is how the Homebrew formula was
started.
### Why do you provide a `curl ...|bash` script?
There is a script in our repository (`scripts/get`) that can be executed as
a `curl ..|bash` script. The transfers are all protected by HTTPS, and the script
does some auditing of the packages it fetches. However, the script has all the
usual dangers of any shell script.
We provide it because it is useful, but we suggest that users carefully read the
script first. What we'd really like, though, are better packaged releases of
Helm.
### How do I put the Helm client files somewhere other than ~/.helm?
Set the `$HELM_HOME` environment variable, and then run `helm init`:
```console
export HELM_HOME=/some/path
helm init --client-only
```
Note that if you have existing repositories, you will need to re-add them
with `helm repo add...`.
## Uninstalling
### I want to delete my local Helm. Where are all its files?
Along with the `helm` binary, Helm stores some files in `$HELM_HOME`, which is
located by default in `~/.helm`.
## Troubleshooting
### On GKE (Google Container Engine) I get "No SSH tunnels currently open"
```
Error: Error forwarding ports: error upgrading connection: No SSH tunnels currently open. Were the targets able to accept an ssh-key for user "gke-[redacted]"?
```
Another variation of the error message is:
```
Unable to connect to the server: x509: certificate signed by unknown authority
```
The issue is that your local Kubernetes config file must have the correct credentials.
When you create a cluster on GKE, it will give you credentials, including SSL
certificates and certificate authorities. These need to be stored in a Kubernetes
config file (Default: `~/.kube/config` so that `kubectl` and `helm` can access
them.
### Why do I get a `unsupported protocol scheme ""` error when trying to pull a chart from my custom repo?**
(Helm < 2.5.0) This is likely caused by you creating your chart repo index without specifying the `--url` flag.
Try recreating your `index.yaml` file with a command like `helm repo index --url http://my-repo/charts .`,
and then re-uploading it to your custom charts repo.
This behavior was changed in Helm 2.5.0.

@ -1,168 +0,0 @@
# Helm Glossary
Helm uses a few special terms to describe components of the
architecture.
## Chart
A Helm package that contains information sufficient for installing a set
of Kubernetes resources into a Kubernetes cluster.
Charts contain a `Chart.yaml` file as well as templates, default values
(`values.yaml`), and dependencies.
Charts are developed in a well-defined directory structure, and then
packaged into an archive format called a _chart archive_.
## Chart Archive
A _chart archive_ is a tarred and gzipped (and optionally signed) chart.
## Chart Dependency (Subcharts)
Charts may depend upon other charts. There are two ways a dependency may
occur:
- Soft dependency: A chart may simply not function without another chart
being installed in a cluster. Helm does not provide tooling for this
case. In this case, dependencies may be managed separately.
- Hard dependency: A chart may contain (inside of its `charts/`
directory) another chart upon which it depends. In this case,
installing the chart will install all of its dependencies. In this
case, a chart and its dependencies are managed as a collection.
When a chart is packaged (via `helm package`) all of its hard dependencies
are bundled with it.
## Chart Version
Charts are versioned according to the [SemVer 2
spec](http://semver.org). A version number is required on every chart.
## Chart.yaml
Information about a chart is stored in a special file called
`Chart.yaml`. Every chart must have this file.
## Helm (and helm)
Helm is the package manager for Kubernetes. As an operating system
package manager makes it easy to install tools on an OS, Helm makes it
easy to install applications and resources into Kubernetes clusters.
While _Helm_ is the name of the project, the command line client is also
named `helm`. By convention, when speaking of the project, _Helm_ is
capitalized. When speaking of the client, _helm_ is in lowercase.
## Helm Home (HELM_HOME)
The Helm client stores information in a local directory referred to as
_helm home_. By default, this is in the `$HOME/.helm` directory.
This directory contains configuration and cache data, and is created by
`helm init`.
## Kube Config (KUBECONFIG)
The Helm client learns about Kubernetes clusters by using files in the _Kube
config_ file format. By default, Helm attempts to find this file in the
place where `kubectl` creates it (`$HOME/.kube/config`).
## Lint (Linting)
To _lint_ a chart is to validate that it follows the conventions and
requirements of the Helm chart standard. Helm provides tools to do this,
notably the `helm lint` command.
## Provenance (Provenance file)
Helm charts may be accompanied by a _provenance file_ which provides
information about where the chart came from and what it contains.
Provenance files are one part of the Helm security story. A provenance contains
a cryptographic hash of the chart archive file, the Chart.yaml data, and
a signature block (an OpenPGP "clearsign" block). When coupled with a
keychain, this provides chart users with the ability to:
- Validate that a chart was signed by a trusted party
- Validate that the chart file has not been tampered with
- Validate the contents of a chart metadata (`Chart.yaml`)
- Quickly match a chart to its provenance data
Provenance files have the `.prov` extension, and can be served from a
chart repository server or any other HTTP server.
## Release
When a chart is installed, the Helm library creates a _release_
to track that installation.
A single chart may be installed many times into the same cluster, and
create many different releases. For example, one can install three
PostgreSQL databases by running `helm install` three times with a
different release name.
(Prior to 2.0.0-Alpha.1, releases were called _deployments_. But this
caused confusion with the Kubernetes _Deployment_ kind.)
## Release Number (Release Version)
A single release can be updated multiple times. A sequential counter is
used to track releases as they change. After a first `helm install`, a
release will have _release number_ 1. Each time a release is upgraded or
rolled back, the release number will be incremented.
## Rollback
A release can be upgraded to a newer chart or configuration. But since
release history is stored, a release can also be _rolled back_ to a
previous release number. This is done with the `helm rollback` command.
Importantly, a rolled back release will receive a new release number.
Operation | Release Number
----------|---------------
install | release 1
upgrade | release 2
upgrade | release 3
rollback 1| release 4 (but running the same config as release 1)
The above table illustrates how release numbers increment across
install, upgrade, and rollback.
## Helm Library
It interacts directly with the Kubernetes API server to install,
upgrade, query, and remove Kubernetes resources.
## Repository (Repo, Chart Repository)
Helm charts may be stored on dedicated HTTP servers called _chart
repositories_ (_repositories_, or just _repos_).
A chart repository server is a simple HTTP server that can serve an
`index.yaml` file that describes a batch of charts, and provides
information on where each chart can be downloaded from. (Many chart
repositories serve the charts as well as the `index.yaml` file.)
A Helm client can point to zero or more chart repositories. By default,
Helm clients point to the `stable` official Kubernetes chart
repository.
## Values (Values Files, values.yaml)
Values provide a way to override template defaults with your own
information.
Helm Charts are "parameterized", which means the chart developer may
expose configuration that can be overridden at installation time. For
example, a chart may expose a `username` field that allows setting a
user name for a service.
These exposed variables are called _values_ in Helm parlance.
Values can be set during `helm install` and `helm upgrade` operations,
either by passing them in directly, or by uploading a `values.yaml`
file.

@ -1,28 +0,0 @@
## The History of the Project
Kubernetes Helm is the merged result of [Helm
Classic](https://github.com/helm/helm) and the Kubernetes port of GCS Deployment
Manager. The project was jointly started by Google and Deis, though it
is now part of the CNCF. Many companies now contribute regularly to Helm.
Differences from Helm Classic:
- Helm now has both a client (`helm`) and a library. In version 2 it had a server (`tiller`) but the capability is now contained within the library.
- Helm's chart format has changed for the better:
- Dependencies are immutable and stored inside of a chart's `charts/`
directory.
- Charts are strongly versioned using [SemVer 2](http://semver.org/spec/v2.0.0.html)
- Charts can be loaded from directories or from chart archive files
- Helm supports Go templates without requiring you to run `generate`
or `template` commands.
- Helm makes it easy to configure your releases -- and share the
configuration with the rest of your team.
- Helm chart repositories now use plain HTTP(S) instead of Git/GitHub.
There is no longer any GitHub dependency.
- A chart server is a simple HTTP server
- Charts are referenced by version
- The `helm serve` command will run a local chart server, though you
can easily use object storage (S3, GCS) or a regular web server.
- And you can still load charts from a local directory.
- The Helm workspace is gone. You can now work anywhere on your
filesystem that you want to work.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

@ -1,36 +0,0 @@
# Helm Documentation
- [Quick Start](quickstart.md) - Read me first!
- [Installing Helm](install.md) - Install Helm
- [Kubernetes Distribution Notes](kubernetes_distros.md)
- [Frequently Asked Questions](install_faq.md)
- [Using Helm](using_helm.md) - Learn the Helm tools
- [Plugins](plugins.md)
- [Role-based Access Control](rbac.md)
- [Developing Charts](charts.md) - An introduction to chart development
- [Chart Lifecycle Hooks](charts_hooks.md)
- [Chart Tips and Tricks](charts_tips_and_tricks.md)
- [Chart Repository Guide](chart_repository.md)
- [Syncing your Chart Repository](chart_repository_sync_example.md)
- [Signing Charts](provenance.md)
- [Writing Tests for Charts](chart_tests.md)
- [Chart Template Developer's Guide](chart_template_guide/index.md) - Master Helm templates
- [Getting Started with Templates](chart_template_guide/getting_started.md)
- [Built-in Objects](chart_template_guide/builtin_objects.md)
- [Values Files](chart_template_guide/values_files.md)
- [Functions and Pipelines](chart_template_guide/functions_and_pipelines.md)
- [Flow Control (if/else, with, range, whitespace management)](chart_template_guide/control_structures.md)
- [Variables](chart_template_guide/variables.md)
- [Named Templates (Partials)](chart_template_guide/named_templates.md)
- [Accessing Files Inside Templates](chart_template_guide/accessing_files.md)
- [Creating a NOTES.txt File](chart_template_guide/notes_files.md)
- [Subcharts and Global Values](chart_template_guide/subcharts_and_globals.md)
- [Debugging Templates](chart_template_guide/debugging.md)
- [Wrapping Up](chart_template_guide/wrapping_up.md)
- [Appendix A: YAML Techniques](chart_template_guide/yaml_techniques.md)
- [Appendix B: Go Data Types](chart_template_guide/data_types.md)
- [Related Projects](related.md) - More Helm tools, articles, and plugins
- [Architecture](architecture.md) - Overview of the Helm design
- [Developers](developers.md) - About the developers
- [History](history.md) - A brief history of the project
- [Glossary](glossary.md) - Decode the Helm vocabulary

@ -1,103 +0,0 @@
# Installing Helm
There are two parts to Helm: The Helm client (`helm`) and the Helm
library. This guide shows how to install both together.
## Installing Helm
Helm can be installed either from source, or from pre-built binary releases.
### From the Binary Releases
Every [release](https://github.com/helm/helm/releases) of Helm
provides binary releases for a variety of OSes. These binary versions
can be manually downloaded and installed.
1. Download your [desired version](https://github.com/helm/helm/releases)
2. Unpack it (`tar -zxvf helm-v2.0.0-linux-amd64.tgz`)
3. Find the `helm` binary in the unpacked directory, and move it to its
desired destination (`mv linux-amd64/helm /usr/local/bin/helm`)
From there, you should be able to run the client: `helm help`.
### From Homebrew (macOS)
Members of the Kubernetes community have contributed a Helm formula build to
Homebrew. This formula is generally up to date.
```
brew install kubernetes-helm
```
(Note: There is also a formula for emacs-helm, which is a different
project.)
### From Chocolatey (Windows)
Members of the Kubernetes community have contributed a [Helm package](https://chocolatey.org/packages/kubernetes-helm) build to
[Chocolatey](https://chocolatey.org/). This package is generally up to date.
```
choco install kubernetes-helm
```
## From Script
Helm now has an installer script that will automatically grab the latest version
of Helm and [install it locally](https://raw.githubusercontent.com/helm/helm/master/scripts/get).
You can fetch that script, and then execute it locally. It's well documented so
that you can read through it and understand what it is doing before you run it.
```
$ curl https://raw.githubusercontent.com/helm/helm/master/scripts/get > get_helm.sh
$ chmod 700 get_helm.sh
$ ./get_helm.sh
```
Yes, you can `curl https://raw.githubusercontent.com/helm/helm/master/scripts/get | bash` that if you want to live on the edge.
### From Canary Builds
"Canary" builds are versions of the Helm software that are built from
the latest master branch. They are not official releases, and may not be
stable. However, they offer the opportunity to test the cutting edge
features.
Canary Helm binaries are stored at [get.helm.sh](https://get.helm.sh).
Here are links to the common builds:
- [Linux AMD64](https://get.helm.sh/helm-canary-linux-amd64.tar.gz)
- [macOS AMD64](https://get.helm.sh/helm-canary-darwin-amd64.tar.gz)
- [Experimental Windows AMD64](https://get.helm.sh/helm-canary-windows-amd64.zip)
### From Source (Linux, macOS)
Building Helm from source is slightly more work, but is the best way to
go if you want to test the latest (pre-release) Helm version.
You must have a working Go environment with
[dep](https://github.com/golang/dep) installed.
```console
$ cd $GOPATH
$ mkdir -p src/helm.sh
$ cd src/helm.sh
$ git clone https://github.com/helm/helm.git
$ cd helm
$ make
```
If required, it will first install dependencies, rebuild the
`vendor/` tree, and validate configuration. It will then compile `helm` and
place it in `bin/helm`.
## Conclusion
In most cases, installation is as simple as getting a pre-built `helm` binary
and running `helm init`. This document covers additional cases for those
who want to do more sophisticated things with Helm.
Once you have the Helm Client successfully installed, you can
move on to using Helm to manage charts.

@ -1,46 +0,0 @@
# Kubernetes Distribution Guide
This document captures information about using Helm in specific Kubernetes
environments.
We are trying to add more details to this document. Please contribute via Pull
Requests if you can.
## MiniKube
Helm is tested and known to work with [minikube](https://github.com/kubernetes/minikube).
It requires no additional configuration.
## `scripts/local-cluster` and Hyperkube
Hyperkube configured via `scripts/local-cluster.sh` is known to work. For raw
Hyperkube you may need to do some manual configuration.
## GKE
Google's GKE hosted Kubernetes platform is known to work with Helm, and requires
no additional configuration.
## Ubuntu with 'kubeadm'
Kubernetes bootstrapped with `kubeadm` is known to work on the following Linux
distributions:
- Ubuntu 16.04
- Fedora release 25
Some versions of Helm (v2.0.0-beta2) require you to `export KUBECONFIG=/etc/kubernetes/admin.conf`
or create a `~/.kube/config`.
## Openshift
Helm works straightforward on OpenShift Online, OpenShift Dedicated, OpenShift Container Platform (version >= 3.6) or OpenShift Origin (version >= 3.6). To learn more read [this blog](https://blog.openshift.com/getting-started-helm-openshift/) post.
## Platform9
Helm is pre-installed with [Platform9 Managed Kubernetes](https://platform9.com/managed-kubernetes/?utm_source=helm_distro_notes). Platform9 provides access to all official Helm charts through the App Catalog UI and native Kubernetes CLI. Additional repositories can be manually added. Further details are available in this [Platform9 App Catalog article](https://platform9.com/support/deploying-kubernetes-apps-platform9-managed-kubernetes/?utm_source=helm_distro_notes).
## DC/OS
Helm has been tested and is working on Mesospheres DC/OS 1.11 Kubernetes platform, and requires no additional configuration.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

@ -1,207 +0,0 @@
# The Helm Plugins Guide
Helm 2.1.0 introduced the concept of a client-side Helm _plugin_. A plugin is a
tool that can be accessed through the `helm` CLI, but which is not part of the
built-in Helm codebase.
Existing plugins can be found on [related](related.md#helm-plugins) section or by searching [Github](https://github.com/search?q=topic%3Ahelm-plugin&type=Repositories).
This guide explains how to use and create plugins.
## An Overview
Helm plugins are add-on tools that integrate seamlessly with Helm. They provide
a way to extend the core feature set of Helm, but without requiring every new
feature to be written in Go and added to the core tool.
Helm plugins have the following features:
- They can be added and removed from a Helm installation without impacting the
core Helm tool.
- They can be written in any programming language.
- They integrate with Helm, and will show up in `helm help` and other places.
Helm plugins live in `$(helm home)/plugins`.
The Helm plugin model is partially modeled on Git's plugin model. To that end,
you may sometimes hear `helm` referred to as the _porcelain_ layer, with
plugins being the _plumbing_. This is a shorthand way of suggesting that
Helm provides the user experience and top level processing logic, while the
plugins do the "detail work" of performing a desired action.
## Installing a Plugin
Plugins are installed using the `$ helm plugin install <path|url>` command. You can pass in a path to a plugin on your local file system or a url of a remote VCS repo. The `helm plugin install` command clones or copies the plugin at the path/url given into `$ (helm home)/plugins`
```console
$ helm plugin install https://github.com/technosophos/helm-template
```
If you have a plugin tar distribution, simply untar the plugin into the `$(helm home)/plugins` directory. You can also install tarball plugins directly from url by issuing `helm plugin install http://domain/path/to/plugin.tar.gz`
Alternatively, a set of plugins can be installed during the `helm init` process by using the `--plugins <file.yaml>` flag, where `file.yaml` looks like this:
```
plugins:
- name: helm-template
url: https://github.com/technosophos/helm-template
- name: helm-diff
url: https://github.com/databus23/helm-diff
version: 2.11.0+3
```
The `name` field only exists to allow you to easily identify plugins, and does not serve a functional purpose. If a plugin specified in the file is already installed, it maintains its current version.
## Building Plugins
In many ways, a plugin is similar to a chart. Each plugin has a top-level
directory, and then a `plugin.yaml` file.
```
$(helm home)/plugins/
|- keybase/
|
|- plugin.yaml
|- keybase.sh
```
In the example above, the `keybase` plugin is contained inside of a directory
named `keybase`. It has two files: `plugin.yaml` (required) and an executable
script, `keybase.sh` (optional).
The core of a plugin is a simple YAML file named `plugin.yaml`.
Here is a plugin YAML for a plugin that adds support for Keybase operations:
```
name: "last"
version: "0.1.0"
usage: "get the last release name"
description: "get the last release name""
ignoreFlags: false
command: "$HELM_BIN --host $TILLER_HOST list --short --max 1 --date -r"
platformCommand:
- os: linux
arch: i386
command: "$HELM_BIN list --short --max 1 --date -r"
- os: linux
arch: amd64
command: "$HELM_BIN list --short --max 1 --date -r"
- os: windows
arch: amd64
command: "$HELM_BIN list --short --max 1 --date -r"
```
The `name` is the name of the plugin. When Helm executes it plugin, this is the
name it will use (e.g. `helm NAME` will invoke this plugin).
_`name` should match the directory name._ In our example above, that means the
plugin with `name: keybase` should be contained in a directory named `keybase`.
Restrictions on `name`:
- `name` cannot duplicate one of the existing `helm` top-level commands.
- `name` must be restricted to the characters ASCII a-z, A-Z, 0-9, `_` and `-`.
`version` is the SemVer 2 version of the plugin.
`usage` and `description` are both used to generate the help text of a command.
The `ignoreFlags` switch tells Helm to _not_ pass flags to the plugin. So if a
plugin is called with `helm myplugin --foo` and `ignoreFlags: true`, then `--foo`
is silently discarded.
Finally, and most importantly, `platformCommand` or `command` is the command
that this plugin will execute when it is called. The `platformCommand` section
defines the OS/Architecture specific variations of a command. The following
rules will apply in deciding which command to use:
- If `platformCommand` is present, it will be searched first.
- If both `os` and `arch` match the current platform, search will stop and the
command will be used.
- If `os` matches and there is no more specific `arch` match, the command
will be used.
- If no `platformCommand` match is found, the default `command` will be used.
- If no matches are found in `platformCommand` and no `command` is present,
Helm will exit with an error.
Environment variables are interpolated before the plugin is executed. The
pattern above illustrates the preferred way to indicate where the plugin
program lives.
There are some strategies for working with plugin commands:
- If a plugin includes an executable, the executable for a
`platformCommand:` or a `command:` should be packaged in the plugin directory.
- The `platformCommand:` or `command:` line will have any environment
variables expanded before execution. `$HELM_PLUGIN_DIR` will point to the
plugin directory.
- The command itself is not executed in a shell. So you can't oneline a shell script.
- Helm injects lots of configuration into environment variables. Take a look at
the environment to see what information is available.
- Helm makes no assumptions about the language of the plugin. You can write it
in whatever you prefer.
- Commands are responsible for implementing specific help text for `-h` and `--help`.
Helm will use `usage` and `description` for `helm help` and `helm help myplugin`,
but will not handle `helm myplugin --help`.
## Downloader Plugins
By default, Helm is able to pull Charts using HTTP/S. As of Helm 2.4.0, plugins
can have a special capability to download Charts from arbitrary sources.
Plugins shall declare this special capability in the `plugin.yaml` file (top level):
```
downloaders:
- command: "bin/mydownloader"
protocols:
- "myprotocol"
- "myprotocols"
```
If such plugin is installed, Helm can interact with the repository using the specified
protocol scheme by invoking the `command`. The special repository shall be added
similarly to the regular ones: `helm repo add favorite myprotocol://example.com/`
The rules for the special repos are the same to the regular ones: Helm must be able
to download the `index.yaml` file in order to discover and cache the list of
available Charts.
The defined command will be invoked with the following scheme:
`command certFile keyFile caFile full-URL`. The SSL credentials are coming from the
repo definition, stored in `$HELM_HOME/repository/repositories.yaml`. Downloader
plugin is expected to dump the raw content to stdout and report errors on stderr.
The downloader command also supports sub-commands or arguments, allowing you to specify
for example `bin/mydownloader subcommand -d` in the `plugin.yaml`. This is useful
if you want to use the same executable for the main plugin command and the downloader
command, but with a different sub-command for each.
## Environment Variables
When Helm executes a plugin, it passes the outer environment to the plugin, and
also injects some additional environment variables.
Variables like `KUBECONFIG` are set for the plugin if they are set in the
outer environment.
The following variables are guaranteed to be set:
- `HELM_PLUGIN`: The path to the plugins directory
- `HELM_PLUGIN_NAME`: The name of the plugin, as invoked by `helm`. So
`helm myplug` will have the short name `myplug`.
- `HELM_PLUGIN_DIR`: The directory that contains the plugin.
- `HELM_BIN`: The path to the `helm` command (as executed by the user).
- `HELM_HOME`: The path to the Helm home.
- `HELM_PATH_*`: Paths to important Helm files and directories are stored in
environment variables prefixed by `HELM_PATH`.
## A Note on Flag Parsing
When executing a plugin, Helm will parse global flags for its own use. Some of
these flags are _not_ passed on to the plugin.
- `--debug`: If this is specified, `$HELM_DEBUG` is set to `1`
- `--home`: This is converted to `$HELM_HOME`
- `--kube-context`: This is simply dropped.
Plugins _should_ display help text and then exit for `-h` and `--help`. In all
other cases, plugins may use flags as appropriate.

@ -1,277 +0,0 @@
# Helm Provenance and Integrity
Helm has provenance tools which help chart users verify the integrity and origin
of a package. Using industry-standard tools based on PKI, GnuPG, and well-respected
package managers, Helm can generate and verify signature files.
## Overview
Integrity is established by comparing a chart to a provenance record. Provenance
records are stored in _provenance files_, which are stored alongside a packaged
chart. For example, if a chart is named `myapp-1.2.3.tgz`, its provenance file
will be `myapp-1.2.3.tgz.prov`.
Provenance files are generated at packaging time (`helm package --sign ...`), and
can be checked by multiple commands, notable `helm install --verify`.
## The Workflow
This section describes a potential workflow for using provenance data effectively.
Prerequisites:
- A valid PGP keypair in a binary (not ASCII-armored) format
- The `helm` command line tool
- GnuPG command line tools (optional)
- Keybase command line tools (optional)
**NOTE:** If your PGP private key has a passphrase, you will be prompted to enter
that passphrase for any commands that support the `--sign` option.
Creating a new chart is the same as before:
```
$ helm create mychart
Creating mychart
```
Once ready to package, add the `--sign` flag to `helm package`. Also, specify
the name under which the signing key is known and the keyring containing the corresponding private key:
```
$ helm package --sign --key 'helm signing key' --keyring path/to/keyring.secret mychart
```
**TIP:** for GnuPG users, your secret keyring is in `~/.gnupg/secring.gpg`. You can
use `gpg --list-secret-keys` to list the keys you have.
**Warning:** the GnuPG v2 store your secret keyring using a new format 'kbx' on the default location '~/.gnupg/pubring.kbx'. Please use the following command to convert your keyring to the legacy gpg format:
```
$ gpg --export-secret-keys >~/.gnupg/secring.gpg
```
At this point, you should see both `mychart-0.1.0.tgz` and `mychart-0.1.0.tgz.prov`.
Both files should eventually be uploaded to your desired chart repository.
You can verify a chart using `helm verify`:
```
$ helm verify mychart-0.1.0.tgz
```
A failed verification looks like this:
```
$ helm verify topchart-0.1.0.tgz
Error: sha256 sum does not match for topchart-0.1.0.tgz: "sha256:1939fbf7c1023d2f6b865d137bbb600e0c42061c3235528b1e8c82f4450c12a7" != "sha256:5a391a90de56778dd3274e47d789a2c84e0e106e1a37ef8cfa51fd60ac9e623a"
```
To verify during an install, use the `--verify` flag.
```
$ helm install --verify mychart-0.1.0.tgz
```
If the keyring (containing the public key associated with the signed chart) is not in the default location, you may need to point to the
keyring with `--keyring PATH` as in the `helm package` example.
If verification fails, the install will be aborted before the chart is even rendered.
### Using Keybase.io credentials
The [Keybase.io](https://keybase.io) service makes it easy to establish a chain of
trust for a cryptographic identity. Keybase credentials can be used to sign charts.
Prerequisites:
- A configured Keybase.io account
- GnuPG installed locally
- The `keybase` CLI installed locally
#### Signing packages
The first step is to import your keybase keys into your local GnuPG keyring:
```
$ keybase pgp export -s | gpg --import
```
This will convert your Keybase key into the OpenPGP format, and then import it
locally into your `~/.gnupg/secring.gpg` file.
You can double check by running `gpg --list-secret-keys`.
```
$ gpg --list-secret-keys 1 ↵
/Users/mattbutcher/.gnupg/secring.gpg
-------------------------------------
sec 2048R/1FC18762 2016-07-25
uid technosophos (keybase.io/technosophos) <technosophos@keybase.io>
ssb 2048R/D125E546 2016-07-25
```
Note that your secret key will have an identifier string:
```
technosophos (keybase.io/technosophos) <technosophos@keybase.io>
```
That is the full name of your key.
Next, you can package and sign a chart with `helm package`. Make sure you use at
least part of that name string in `--key`.
```
$ helm package --sign --key technosophos --keyring ~/.gnupg/secring.gpg mychart
```
As a result, the `package` command should produce both a `.tgz` file and a `.tgz.prov`
file.
#### Verifying packages
You can also use a similar technique to verify a chart signed by someone else's
Keybase key. Say you want to verify a package signed by `keybase.io/technosophos`.
To do this, use the `keybase` tool:
```
$ keybase follow technosophos
$ keybase pgp pull
```
The first command above tracks the user `technosophos`. Next `keybase pgp pull`
downloads the OpenPGP keys of all of the accounts you follow, placing them in
your GnuPG keyring (`~/.gnupg/pubring.gpg`).
At this point, you can now use `helm verify` or any of the commands with a `--verify`
flag:
```
$ helm verify somechart-1.2.3.tgz
```
### Reasons a chart may not verify
These are common reasons for failure.
- The prov file is missing or corrupt. This indicates that something is misconfigured
or that the original maintainer did not create a provenance file.
- The key used to sign the file is not in your keyring. This indicate that the
entity who signed the chart is not someone you've already signaled that you trust.
- The verification of the prov file failed. This indicates that something is wrong
with either the chart or the provenance data.
- The file hashes in the provenance file do not match the hash of the archive file. This
indicates that the archive has been tampered with.
If a verification fails, there is reason to distrust the package.
## The Provenance File
The provenance file contains a charts YAML file plus several pieces of
verification information. Provenance files are designed to be automatically
generated.
The following pieces of provenance data are added:
* The chart file (Chart.yaml) is included to give both humans and tools an easy
view into the contents of the chart.
* The signature (SHA256, just like Docker) of the chart package (the .tgz file)
is included, and may be used to verify the integrity of the chart package.
* The entire body is signed using the algorithm used by PGP (see
[http://keybase.io] for an emerging way of making crypto signing and
verification easy).
The combination of this gives users the following assurances:
* The package itself has not been tampered with (checksum package tgz).
* The entity who released this package is known (via the GnuPG/PGP signature).
The format of the file looks something like this:
```
-----BEGIN PGP SIGNED MESSAGE-----
name: nginx
description: The nginx web server as a replication controller and service pair.
version: 0.5.1
keywords:
- https
- http
- web server
- proxy
source:
- https://github.com/foo/bar
home: http://nginx.com
...
files:
nginx-0.5.1.tgz: “sha256:9f5270f50fc842cfcb717f817e95178f”
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
iEYEARECAAYFAkjilUEACgQkB01zfu119ZnHuQCdGCcg2YxF3XFscJLS4lzHlvte
WkQAmQGHuuoLEJuKhRNo+Wy7mhE7u1YG
=eifq
-----END PGP SIGNATURE-----
```
Note that the YAML section contains two documents (separated by `...\n`). The
first is the Chart.yaml. The second is the checksums, a map of filenames to
SHA-256 digests (value shown is fake/truncated)
The signature block is a standard PGP signature, which provides [tamper
resistance](http://www.rossde.com/PGP/pgp_signatures.html).
## Chart Repositories
Chart repositories serve as a centralized collection of Helm charts.
Chart repositories must make it possible to serve provenance files over HTTP via
a specific request, and must make them available at the same URI path as the chart.
For example, if the base URL for a package is `https://example.com/charts/mychart-1.2.3.tgz`,
the provenance file, if it exists, MUST be accessible at `https://example.com/charts/mychart-1.2.3.tgz.prov`.
From the end user's perspective, `helm install --verify myrepo/mychart-1.2.3`
should result in the download of both the chart and the provenance file with no
additional user configuration or action.
## Establishing Authority and Authenticity
When dealing with chain-of-trust systems, it is important to be able to
establish the authority of a signer. Or, to put this plainly, the system
above hinges on the fact that you trust the person who signed the chart.
That, in turn, means you need to trust the public key of the signer.
One of the design decisions with Kubernetes Helm has been that the Helm
project would not insert itself into the chain of trust as a necessary
party. We don't want to be "the certificate authority" for all chart
signers. Instead, we strongly favor a decentralized model, which is part
of the reason we chose OpenPGP as our foundational technology.
So when it comes to establishing authority, we have left this
step more-or-less undefined in Helm 2.0.0.
However, we have some pointers and recommendations for those interested
in using the provenance system:
- The [Keybase](https://keybase.io) platform provides a public
centralized repository for trust information.
- You can use Keybase to store your keys or to get the public keys of others.
- Keybase also has fabulous documentation available
- While we haven't tested it, Keybase's "secure website" feature could
be used to serve Helm charts.
- The [official Kubernetes Charts project](https://github.com/helm/charts)
is trying to solve this problem for the official chart repository.
- There is a long issue there [detailing the current thoughts](https://github.com/helm/charts/issues/23).
- The basic idea is that an official "chart reviewer" signs charts with
her or his key, and the resulting provenance file is then uploaded
to the chart repository.
- There has been some work on the idea that a list of valid signing
keys may be included in the `index.yaml` file of a repository.
Finally, chain-of-trust is an evolving feature of Helm, and some
community members have proposed adapting part of the OSI model for
signatures. This is an open line of inquiry in the Helm team. If you're
interested, jump on in.

@ -1,114 +0,0 @@
# Quickstart Guide
This guide covers how you can quickly get started using Helm.
## Prerequisites
The following prerequisites are required for a successful and properly secured use of Helm.
1. A Kubernetes cluster
2. Deciding what security configurations to apply to your installation, if any
3. Installing and configuring Helm.
### Install Kubernetes or have access to a cluster
- You must have Kubernetes installed. For the latest release of Helm, we recommend the latest stable release of Kubernetes, which in most cases is the second-latest minor release.
- You should also have a local configured copy of `kubectl`.
NOTE: Kubernetes versions prior to 1.6 have limited or no support for role-based access controls (RBAC).
### Understand your Security Context
As with all powerful tools, ensure you are installing it correctly for your scenario.
If you're using Helm on a cluster that you completely control, like minikube or a cluster on a private network in which sharing is not a concern, the default installation -- which applies no security configuration -- is fine, and it's definitely the easiest. To install Helm without additional security steps, [install Helm](#Install-Helm) and then [initialize Helm](#initialize-helm).
However, if your cluster is exposed to a larger network or if you share your cluster with others -- production clusters fall into this category -- you must take extra steps to secure your installation to prevent careless or malicious actors from damaging the cluster or its data. To apply configurations that secure Helm for use in production environments and other multi-tenant scenarios, see [Securing a Helm installation](securing_installation.md)
If your cluster has Role-Based Access Control (RBAC) enabled, you may want
to [configure a service account and rules](rbac.md) before proceeding.
## Install Helm
Download a binary release of the Helm client. You can use tools like
`homebrew`, or look at [the official releases page](https://github.com/helm/helm/releases).
For more details, or for other options, see [the installation
guide](install.md).
## Initialize Helm
Once you have Helm ready, you can initialize the local CLI:
```console
$ helm init
```
## Install an Example Chart
To install a chart, you can run the `helm install` command. Helm has
several ways to find and install a chart, but the easiest is to use one
of the official `stable` charts.
```console
$ helm repo update # Make sure we get the latest list of charts
$ helm install stable/mysql
Released smiling-penguin
```
In the example above, the `stable/mysql` chart was released, and the name of
our new release is `smiling-penguin`. You get a simple idea of the
features of this MySQL chart by running `helm inspect stable/mysql`.
Whenever you install a chart, a new release is created. So one chart can
be installed multiple times into the same cluster. And each can be
independently managed and upgraded.
The `helm install` command is a very powerful command with many
capabilities. To learn more about it, check out the [Using Helm
Guide](using_helm.md)
## Learn About Releases
It's easy to see what has been released using Helm:
```console
$ helm ls
NAME VERSION UPDATED                   STATUS   CHART
smiling-penguin 1 Wed Sep 28 12:59:46 2016 DEPLOYED mysql-0.1.0
```
The `helm list` function will show you a list of all deployed releases.
## Uninstall a Release
To uninstall a release, use the `helm uninstall` command:
```console
$ helm uninstall smiling-penguin
Removed smiling-penguin
```
This will uninstall `smiling-penguin` from Kubernetes, but you will
still be able to request information about that release:
```console
$ helm status smiling-penguin
Status: UNINSTALLED
...
```
Because Helm tracks your releases even after you've uninstalled them, you
can audit a cluster's history, and even undelete a release (with `helm
rollback`).
## Reading the Help Text
To learn more about the available Helm commands, use `helm help` or type
a command followed by the `-h` flag:
```console
$ helm get -h
```

@ -1,175 +0,0 @@
# Registries
Helm 3 uses <a href="https://www.opencontainers.org/" target="_blank">OCI</a> for package distribution. Chart packages are stored and shared across OCI-based registries.
## Running a registry
Starting a registry for test purposes is trivial. As long as you have Docker installed, run the following command:
```
docker run -dp 5000:5000 --restart=always --name registry registry
```
This will start a registry server at `localhost:5000`.
Use `docker logs -f registry` to see the logs and `docker rm -f registry` to stop.
If you wish to persist storage, you can add `-v $(pwd)/registry:/var/lib/registry` to the command above.
For more configuration options, please see [the docs](https://docs.docker.com/registry/deploying/).
### Auth
If you wish to enable auth on the registry, you can do the following-
First, create file `auth.htpasswd` with username and password combo:
```
htpasswd -cB -b auth.htpasswd myuser mypass
```
Then, start the server, mounting that file and setting the `REGISTRY_AUTH` env var:
```
docker run -dp 5000:5000 --restart=always --name registry \
-v $(pwd)/auth.htpasswd:/etc/docker/registry/auth.htpasswd \
-e REGISTRY_AUTH="{htpasswd: {realm: localhost, path: /etc/docker/registry/auth.htpasswd}}" \
registry
```
## Commands for working with registries
Commands are available under both `helm registry` and `helm chart` that allow you to work with registries and local cache.
### The `registry` subcommand
#### `login`
login to a registry (with manual password entry)
```
$ helm registry login -u myuser localhost:5000
Password:
Login succeeded
```
#### `logout`
logout from a registry
```
$ helm registry logout localhost:5000
Logout succeeded
```
### The `chart` subcommand
#### `save`
save a chart directory to local cache
```
$ helm chart save mychart/ localhost:5000/myrepo/mychart:2.7.0
Name: mychart
Version: 2.7.0
Meta: sha256:ca9588a9340fb83a62777cd177dae4ba5ab52061a1618ce2e21930b86c412d9e
Content: sha256:a66666c6b35ee25aa8ecd7d0e871389b5a2a0576295d6c366aefe836001cb90d
2.7.0: saved
```
#### `list`
list all saved charts
```
$ helm chart list
REF NAME VERSION DIGEST SIZE CREATED
localhost:5000/myrepo/mychart:2.7.0 mychart 2.7.0 84059d7 454 B 27 seconds
localhost:5000/stable/acs-engine-autoscaler:2.2.2 acs-engine-autoscaler 2.2.2 d8d6762 4.3 KiB 2 hours
localhost:5000/stable/aerospike:0.2.1 aerospike 0.2.1 4aff638 3.7 KiB 2 hours
localhost:5000/stable/airflow:0.13.0 airflow 0.13.0 c46cc43 28.1 KiB 2 hours
localhost:5000/stable/anchore-engine:0.10.0 anchore-engine 0.10.0 3f3dcd7 34.3 KiB 2 hours
...
```
#### `export`
export a chart to directory
```
$ helm chart export localhost:5000/myrepo/mychart:2.7.0
Name: mychart
Version: 2.7.0
Meta: sha256:3344059bb81c49cc6f2599a379da0a6c14313cf969f7b821aca18e489ba3991b
Content: sha256:84059d7403f496a1c63caf97fdc5e939ea39e561adbd98d0aa864d1b9fc9653f
Exported to mychart/
```
#### `push`
push a chart to remote
```
$ helm chart push localhost:5000/myrepo/mychart:2.7.0
The push refers to repository [localhost:5000/myrepo/mychart]
Name: mychart
Version: 2.7.0
Meta: sha256:ca9588a9340fb83a62777cd177dae4ba5ab52061a1618ce2e21930b86c412d9e
Content: sha256:a66666c6b35ee25aa8ecd7d0e871389b5a2a0576295d6c366aefe836001cb90d
2.7.0: pushed to remote (2 layers, 478 B total)
```
#### `remove`
remove a chart from cache
```
$ helm chart remove localhost:5000/myrepo/mychart:2.7.0
2.7.0: removed
```
#### `pull`
pull a chart from remote
```
$ helm chart pull localhost:5000/myrepo/mychart:2.7.0
2.7.0: Pulling from localhost:5000/myrepo/mychart
Name: mychart
Version: 2.7.0
Meta: sha256:ca9588a9340fb83a62777cd177dae4ba5ab52061a1618ce2e21930b86c412d9e
Content: sha256:a66666c6b35ee25aa8ecd7d0e871389b5a2a0576295d6c366aefe836001cb90d
Status: Chart is up to date for localhost:5000/myrepo/mychart:2.7.0
```
## Where are my charts?
Charts stored using the commands above will be cached on disk at `~/.helm/registry` (or somewhere else depending on `$HELM_HOME`).
Chart content (tarball) and chart metadata (json) are stored as separate content-addressable blobs. This prevents storing the same content twice when, for example, you are simply modifying some fields in `Chart.yaml`. They are joined together and converted back into regular chart format when using the `export` command.
The chart name and chart version are treated as "first-class" properties and stored separately. They are extracted out of `Chart.yaml` prior to building the metadata blob.
The following shows an example of a single chart stored in the cache (`localhost:5000/myrepo/mychart:2.7.0`):
```
$ tree ~/.helm/registry
/Users/me/.helm/registry
├── blobs
│   └── sha256
│   ├── 3344059bb81c49cc6f2599a379da0a6c14313cf969f7b821aca18e489ba3991b
│   └── 84059d7403f496a1c63caf97fdc5e939ea39e561adbd98d0aa864d1b9fc9653f
├── charts
│ └── mychart
│ └── versions
│ └── 2.7.0
└── refs
└── localhost_5000
└── myrepo
└── mychart
└── tags
└── 2.7.0
├── chart -> /Users/me/.helm/registry/charts/mychart/versions/2.7.0
├── content -> /Users/me/.helm/registry/blobs/sha256/3344059bb81c49cc6f2599a379da0a6c14313cf969f7b821aca18e489ba3991b
└── meta -> /Users/me/.helm/registry/blobs/sha256/84059d7403f496a1c63caf97fdc5e939ea39e561adbd98d0aa864d1b9fc9653f
```
## Migrating from chart repos
Migrating from classic [chart repositories](./chart_repository.md) (index.yaml-based repos) is as simple as a `helm fetch` (Helm 2 CLI), `helm chart save`, `helm chart push`.

@ -1,82 +0,0 @@
# Related Projects and Documentation
The Helm community has produced many extra tools, plugins, and documentation about
Helm. We love to hear about these projects. If you have anything you'd like to
add to this list, please open an [issue](https://github.com/helm/helm/issues)
or [pull request](https://github.com/helm/helm/pulls).
## Article, Blogs, How-Tos, and Extra Documentation
- [Using Helm to Deploy to Kubernetes](https://daemonza.github.io/2017/02/20/using-helm-to-deploy-to-kubernetes/)
- [Honestbee's Helm Chart Conventions](https://gist.github.com/so0k/f927a4b60003cedd101a0911757c605a)
- [Deploying Kubernetes Applications with Helm](http://cloudacademy.com/blog/deploying-kubernetes-applications-with-helm/)
- [Releasing backward-incompatible changes: Kubernetes, Jenkins, Prometheus Operator, Helm and Traefik](https://medium.com/@enxebre/releasing-backward-incompatible-changes-kubernetes-jenkins-plugin-prometheus-operator-helm-self-6263ca61a1b1#.e0c7elxhq)
- [CI/CD with Kubernetes, Helm & Wercker ](http://www.slideshare.net/Diacode/cicd-with-kubernetes-helm-wercker-madscalability)
- [The missing CI/CD Kubernetes component: Helm package manager](https://hackernoon.com/the-missing-ci-cd-kubernetes-component-helm-package-manager-1fe002aac680#.691sk2zhu)
- [The Workflow "Umbrella" Helm Chart](https://deis.com/blog/2017/workflow-chart-assembly)
- [GitLab, Consumer Driven Contracts, Helm and Kubernetes](https://medium.com/@enxebre/gitlab-consumer-driven-contracts-helm-and-kubernetes-b7235a60a1cb#.xwp1y4tgi)
- [Writing a Helm Chart](https://www.influxdata.com/packaged-kubernetes-deployments-writing-helm-chart/)
- [Creating a Helm Plugin in 3 Steps](http://technosophos.com/2017/03/21/creating-a-helm-plugin.html)
## Video, Audio, and Podcast
- [CI/CD with Jenkins, Kubernetes, and Helm](https://www.youtube.com/watch?v=NVoln4HdZOY): AKA "The Infamous Croc Hunter Video".
- [KubeCon2016: Delivering Kubernetes-Native Applications by Michelle Noorali](https://www.youtube.com/watch?v=zBc1goRfk3k&index=49&list=PLj6h78yzYM2PqgIGU1Qmi8nY7dqn9PCr4)
- [Helm with Michelle Noorali and Matthew Butcher](https://gcppodcast.com/post/episode-50-helm-with-michelle-noorali-and-matthew-butcher/): The official Google CloudPlatform Podcast interviews Michelle and Matt about Helm.
## Helm Plugins
- [Technosophos's Helm Plugins](https://github.com/technosophos/helm-plugins) - Plugins for GitHub, Keybase, and GPG
- [helm-template](https://github.com/technosophos/helm-template) - Debug/render templates client-side
- [Helm Value Store](https://github.com/skuid/helm-value-store) - Plugin for working with Helm deployment values
- [Helm Diff](https://github.com/databus23/helm-diff) - Preview `helm upgrade` as a coloured diff
- [helm-env](https://github.com/adamreese/helm-env) - Plugin to show current environment
- [helm-last](https://github.com/adamreese/helm-last) - Plugin to show the latest release
- [helm-nuke](https://github.com/adamreese/helm-nuke) - Plugin to destroy all releases
- [App Registry](https://github.com/app-registry/helm-plugin) - Plugin to manage charts via the [App Registry specification](https://github.com/app-registry/spec)
- [helm-secrets](https://github.com/futuresimple/helm-secrets) - Plugin to manage and store secrets safely
- [helm-edit](https://github.com/mstrzele/helm-edit) - Plugin for editing release's values
- [helm-gcs](https://github.com/nouney/helm-gcs) - Plugin to manage repositories on Google Cloud Storage
- [helm-github](https://github.com/sagansystems/helm-github) - Plugin to install Helm Charts from Github repositories
- [helm-monitor](https://github.com/ContainerSolutions/helm-monitor) - Plugin to monitor a release and rollback based on Prometheus/ElasticSearch query
- [helm-k8comp](https://github.com/cststack/k8comp) - Plugin to create Helm Charts from hiera using k8comp
- [helm-hashtag](https://github.com/balboah/helm-hashtag) - Plugin for tracking docker tag hash digests as values
- [helm-unittest](https://github.com/lrills/helm-unittest) - Plugin for unit testing chart locally with YAML
We also encourage GitHub authors to use the [helm-plugin](https://github.com/search?q=topic%3Ahelm-plugin&type=Repositories)
tag on their plugin repositories.
## Additional Tools
Tools layered on top of Helm.
- [Quay App Registry](https://coreos.com/blog/quay-application-registry-for-kubernetes.html) - Open Kubernetes application registry, including a Helm access client
- [Chartify](https://github.com/appscode/chartify) - Generate Helm charts from existing Kubernetes resources.
- [VIM-Kubernetes](https://github.com/andrewstuart/vim-kubernetes) - VIM plugin for Kubernetes and Helm
- [Landscaper](https://github.com/Eneco/landscaper/) - "Landscaper takes a set of Helm Chart references with values (a desired state), and realizes this in a Kubernetes cluster."
- [Helmfile](https://github.com/roboll/helmfile) - Helmfile is a declarative spec for deploying helm charts
- [Autohelm](https://github.com/reactiveops/autohelm) - Autohelm is _another_ simple declarative spec for deploying helm charts. Written in python and supports git urls as a source for helm charts.
- [Helmsman](https://github.com/Praqma/helmsman) - Helmsman is a helm-charts-as-code tool which enables installing/upgrading/protecting/moving/deleting releases from version controlled desired state files (described in a simple TOML format).
- [Schelm](https://github.com/databus23/schelm) - Render a Helm manifest to a directory
- [Drone.io Helm Plugin](http://plugins.drone.io/ipedrazas/drone-helm/) - Run Helm inside of the Drone CI/CD system
- [Cog](https://github.com/ohaiwalt/cog-helm) - Helm chart to deploy Cog on Kubernetes
- [Monocular](https://github.com/helm/monocular) - Web UI for Helm Chart repositories
- [Helm Chart Publisher](https://github.com/luizbafilho/helm-chart-publisher) - HTTP API for publishing Helm Charts in an easy way
- [Armada](https://github.com/att-comdev/armada) - Manage prefixed releases throughout various Kubernetes namespaces, and removes completed jobs for complex deployments. Used by the [Openstack-Helm](https://github.com/openstack/openstack-helm) team.
- [ChartMuseum](https://github.com/chartmuseum/chartmuseum) - Helm Chart Repository with support for Amazon S3 and Google Cloud Storage
- [Codefresh](https://codefresh.io) - Kubernetes native CI/CD and management platform with UI dashboards for managing Helm charts and releases
## Helm Included
Platforms, distributions, and services that include Helm support.
- [Kubernetic](https://kubernetic.com/) - Kubernetes Desktop Client
- [Cabin](http://www.skippbox.com/cabin/) - Mobile App for Managing Kubernetes
- [Qstack](https://qstack.com)
- [Fabric8](https://fabric8.io) - Integrated development platform for Kubernetes
- [Jenkins X](http://jenkins-x.io/) - open source automated CI/CD for Kubernetes which uses Helm for [promoting](http://jenkins-x.io/about/features/#promotion) applications through [environments via GitOps](http://jenkins-x.io/about/features/#environments)
## Misc
Grab bag of useful things for Chart authors and Helm users
- [Await](https://github.com/saltside/await) - Docker image to "await" different conditions--especially useful for init containers. [More Info](http://blog.slashdeploy.com/2017/02/16/introducing-await/)

@ -1,240 +0,0 @@
# Release Checklist
**IMPORTANT**: If your experience deviates from this document, please document the changes to keep it up-to-date.
## A Maintainer's Guide to Releasing Helm
So you're in charge of a new release for helm? Cool. Here's what to do...
![TODO: Nothing](images/nothing.png)
Just kidding! :trollface:
All releases will be of the form vX.Y.Z where X is the major version number, Y is the minor version number and Z is the patch release number. This project strictly follows [semantic versioning](http://semver.org/) so following this step is critical.
It is important to note that this document assumes that the git remote in your repository that corresponds to "https://github.com/helm/helm" is named "upstream". If yours is not (for example, if you've chosen to name it "origin" or something similar instead), be sure to adjust the listed snippets for your local environment accordingly. If you are not sure what your upstream remote is named, use a command like `git remote -v` to find out.
If you don't have an upstream remote, you can add one easily using something like:
```shell
git remote add upstream git@github.com:helm/helm.git
```
In this doc, we are going to reference a few environment variables as well, which you may want to set for convenience. For major/minor releases, use the following:
```shell
export RELEASE_NAME=vX.Y.0
export RELEASE_BRANCH_NAME="release-$RELEASE_NAME"
export RELEASE_CANDIDATE_NAME="$RELEASE_NAME-rc1"
```
If you are creating a patch release, you may want to use the following instead:
```shell
export PREVIOUS_PATCH_RELEASE=vX.Y.Z
export RELEASE_NAME=vX.Y.Z+1
export RELEASE_BRANCH_NAME="release-X.Y"
export RELEASE_CANDIDATE_NAME="$RELEASE_NAME-rc1"
```
## 1. Create the Release Branch
### Major/Minor Releases
Major releases are for new feature additions and behavioral changes *that break backwards compatibility*. Minor releases are for new feature additions that do not break backwards compatibility. To create a major or minor release, start by creating a `release-vX.Y.0` branch from master.
```shell
git fetch upstream
git checkout upstream/master
git checkout -b $RELEASE_BRANCH_NAME
```
This new branch is going to be the base for the release, which we are going to iterate upon later.
### Patch releases
Patch releases are a few critical cherry-picked fixes to existing releases. Start by creating a `release-vX.Y.Z` branch from the latest patch release.
```shell
git fetch upstream --tags
git checkout $PREVIOUS_PATCH_RELEASE
git checkout -b $RELEASE_BRANCH_NAME
```
From here, we can cherry-pick the commits we want to bring into the patch release:
```shell
# get the commits ids we want to cherry-pick
git log --oneline
# cherry-pick the commits starting from the oldest one, without including merge commits
git cherry-pick -x <commit-id>
git cherry-pick -x <commit-id>
```
This new branch is going to be the base for the release, which we are going to iterate upon later.
## 2. Change the Version Number in Git
When doing a minor release, make sure to update pkg/version/version.go with the new release version.
```shell
$ git diff pkg/version/version.go
diff --git a/pkg/version/version.go b/pkg/version/version.go
index 2109a0a..6f5a1a4 100644
--- a/pkg/version/version.go
+++ b/pkg/version/version.go
@@ -26,7 +26,7 @@ var (
// Increment major number for new feature additions and behavioral changes.
// Increment minor number for bug fixes and performance enhancements.
// Increment patch number for critical fixes to existing releases.
- Version = "v2.6"
+ Version = "v2.7"
// BuildMetadata is extra build time data
BuildMetadata = "unreleased"
```
For patch releases, the old version number will be the latest patch release, so just bump the patch number, incrementing Z by one.
```shell
git add .
git commit -m "bump version to $RELEASE_CANDIDATE_NAME"
```
## 3. Commit and Push the Release Branch
In order for others to start testing, we can now push the release branch upstream and start the test process.
```shell
git push upstream $RELEASE_BRANCH_NAME
```
Make sure to check [helm on CircleCI](https://circleci.com/gh/helm/helm) and make sure the release passed CI before proceeding.
If anyone is available, let others peer-review the branch before continuing to ensure that all the proper changes have been made and all of the commits for the release are there.
## 4. Create a Release Candidate
Now that the release branch is out and ready, it is time to start creating and iterating on release candidates.
```shell
git tag --sign --annotate "${RELEASE_CANDIDATE_NAME}" --message "Helm release ${RELEASE_CANDIDATE_NAME}"
git push upstream $RELEASE_CANDIDATE_NAME
```
CircleCI will automatically create a tagged release image and client binary to test with.
After CircleCI finishes building the artifacts, use the following commands to fetch the client for testing:
linux/amd64, using /bin/bash:
```shell
wget https://get.helm.sh/helm-$RELEASE_CANDIDATE_NAME-linux-amd64.tar.gz
```
darwin/amd64, using Terminal.app:
```shell
wget https://get.helm.sh/helm-$RELEASE_CANDIDATE_NAME-darwin-amd64.tar.gz
```
windows/amd64, using PowerShell:
```shell
PS C:\> Invoke-WebRequest -Uri "https://get.helm.sh/helm-$RELEASE_CANDIDATE_NAME-windows-amd64.tar.gz" -OutFile "helm-$ReleaseCandidateName-windows-amd64.tar.gz"
```
Then, unpack and move the binary to somewhere on your $PATH, or move it somewhere and add it to your $PATH (e.g. /usr/local/bin/helm for linux/macOS, C:\Program Files\helm\helm.exe for Windows).
## 5. Iterate on Successive Release Candidates
Spend several days explicitly investing time and resources to try and break helm in every possible way, documenting any findings pertinent to the release. This time should be spent testing and finding ways in which the release might have caused various features or upgrade environments to have issues, not coding. During this time, the release is in code freeze, and any additional code changes will be pushed out to the next release.
During this phase, the $RELEASE_BRANCH_NAME branch will keep evolving as you will produce new release candidates. The frequency of new candidates is up to the release manager: use your best judgement taking into account the severity of reported issues, testers' availability, and the release deadline date. Generally speaking, it is better to let a release roll over the deadline than to ship a broken release.
Each time you'll want to produce a new release candidate, you will start by adding commits to the branch by cherry-picking from master:
```shell
git cherry-pick -x <commit_id>
```
You will also want to update the release version number and the CHANGELOG as we did in steps 2 and 3 as separate commits.
After that, tag it and notify users of the new release candidate:
```shell
export RELEASE_CANDIDATE_NAME="$RELEASE_NAME-rc2"
git tag --sign --annotate "${RELEASE_CANDIDATE_NAME}" --message "Helm release ${RELEASE_CANDIDATE_NAME}"
git push upstream $RELEASE_CANDIDATE_NAME
```
From here on just repeat this process, continuously testing until you're happy with the release candidate.
## 6. Finalize the Release
When you're finally happy with the quality of a release candidate, you can move on and create the real thing. Double-check one last time to make sure everything is in order, then finally push the release tag.
```shell
git checkout $RELEASE_BRANCH_NAME
git tag --sign --annotate "${RELEASE_NAME}" --message "Helm release ${RELEASE_NAME}"
git push upstream $RELEASE_NAME
```
## 7. Write the Release Notes
We will auto-generate a changelog based on the commits that occurred during a release cycle, but it is usually more beneficial to the end-user if the release notes are hand-written by a human being/marketing team/dog.
If you're releasing a major/minor release, listing notable user-facing features is usually sufficient. For patch releases, do the same, but make note of the symptoms and who is affected.
An example release note for a minor release would look like this:
```markdown
## vX.Y.Z
Helm vX.Y.Z is a feature release. This release, we focused on <insert focal point>. Users are encouraged to upgrade for the best experience.
The community keeps growing, and we'd love to see you there.
- Join the discussion in [Kubernetes Slack](https://slack.k8s.io/):
- `#helm-users` for questions and just to hang out
- `#helm-dev` for discussing PRs, code, and bugs
- Hang out at the Public Developer Call: Thursday, 9:30 Pacific via [Zoom](https://zoom.us/j/4526666954)
- Test, debug, and contribute charts: [GitHub/kubernetes/charts](https://github.com/helm/charts)
## Installation and Upgrading
Download Helm X.Y. The common platform binaries are here:
- [OSX](https://get.helm.sh/helm-vX.Y.Z-darwin-amd64.tar.gz)
- [Linux](https://get.helm.sh/helm-vX.Y.Z-linux-amd64.tar.gz)
- [Windows](https://get.helm.sh/helm-vX.Y.Z-windows-amd64.tar.gz)
The [Quickstart Guide](https://docs.helm.sh/using_helm/#quickstart-guide) will get you going from there. For **upgrade instructions** or detailed installation notes, check the [install guide](https://docs.helm.sh/using_helm/#installing-helm). You can also use a [script to install](https://raw.githubusercontent.com/helm/helm/master/scripts/get) on any system with `bash`.
## What's Next
- vX.Y.Z+1 will contain only bug fixes.
- vX.Y+1.Z is the next feature release. This release will focus on ...
## Changelog
- chore(*): bump version to v2.7.0 08c1144f5eb3e3b636d9775617287cc26e53dba4 (Adam Reese)
- fix circle not building tags f4f932fabd197f7e6d608c8672b33a483b4b76fa (Matthew Fisher)
```
The changelog at the bottom of the release notes can be generated with this command:
```shell
PREVIOUS_RELEASE=vX.Y.Z
git log --no-merges --pretty=format:'- %s %H (%aN)' $RELEASE_NAME $PREVIOUS_RELEASE
```
Once finished, go into GitHub and edit the release notes for the tagged release with the notes written here.
## 9. Evangelize
Congratulations! You're done. Go grab yourself a $DRINK_OF_CHOICE. You've earned it.
After enjoying a nice $DRINK_OF_CHOICE, go forth and announce the glad tidings of the new release in Slack and on Twitter. You should also notify any key partners in the helm community such as the homebrew formula maintainers, the owners of incubator projects (e.g. ChartMuseum) and any other interested parties.
Optionally, write a blog post about the new release and showcase some of the new features on there!

@ -1,505 +0,0 @@
# Using Helm
This guide explains the basics of using Helm to manage
packages on your Kubernetes cluster. It assumes that you have already
[installed](install.md) the Helm client and library (typically by `helm
init`).
If you are simply interested in running a few quick commands, you may
wish to begin with the [Quickstart Guide](quickstart.md). This chapter
covers the particulars of Helm commands, and explains how to use Helm.
## Three Big Concepts
A *Chart* is a Helm package. It contains all of the resource definitions
necessary to run an application, tool, or service inside of a Kubernetes
cluster. Think of it like the Kubernetes equivalent of a Homebrew formula,
an Apt dpkg, or a Yum RPM file.
A *Repository* is the place where charts can be collected and shared.
It's like Perl's [CPAN archive](http://www.cpan.org) or the
[Fedora Package Database](https://admin.fedoraproject.org/pkgdb/), but for
Kubernetes packages.
A *Release* is an instance of a chart running in a Kubernetes cluster.
One chart can often be installed many times into the same cluster. And
each time it is installed, a new _release_ is created. Consider a MySQL
chart. If you want two databases running in your cluster, you can
install that chart twice. Each one will have its own _release_, which
will in turn have its own _release name_.
With these concepts in mind, we can now explain Helm like this:
Helm installs _charts_ into Kubernetes, creating a new _release_ for
each installation. And to find new charts, you can search Helm chart
_repositories_.
## 'helm search': Finding Charts
When you first install Helm, it is preconfigured to talk to the official
Kubernetes charts repository. This repository contains a number of
carefully curated and maintained charts. This chart repository is named
`stable` by default.
You can see which charts are available by running `helm search`:
```
$ helm search
NAME VERSION DESCRIPTION
stable/drupal 0.3.2 One of the most versatile open source content m...
stable/jenkins 0.1.0 A Jenkins Helm chart for Kubernetes.
stable/mariadb 0.5.1 Chart for MariaDB
stable/mysql 0.1.0 Chart for MySQL
...
```
With no filter, `helm search` shows you all of the available charts. You
can narrow down your results by searching with a filter:
```
$ helm search mysql
NAME VERSION DESCRIPTION
stable/mysql 0.1.0 Chart for MySQL
stable/mariadb 0.5.1 Chart for MariaDB
```
Now you will only see the results that match your filter.
Why is
`mariadb` in the list? Because its package description relates it to
MySQL. We can use `helm inspect chart` to see this:
```
$ helm inspect stable/mariadb
Fetched stable/mariadb to mariadb-0.5.1.tgz
description: Chart for MariaDB
home: https://mariadb.org
keywords:
- mariadb
- mysql
- database
- sql
...
```
Search is a good way to find available packages. Once you have found a
package you want to install, you can use `helm install` to install it.
## 'helm install': Installing a Package
To install a new package, use the `helm install` command. At its
simplest, it takes only one argument: The name of the chart.
```
$ helm install --generate-name stable/mariadb
Fetched stable/mariadb-0.3.0 to /Users/mattbutcher/Code/Go/src/helm.sh/helm/mariadb-0.3.0.tgz
happy-panda
Last Deployed: Wed Sep 28 12:32:28 2016
Namespace: default
Status: DEPLOYED
Resources:
==> extensions/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
happy-panda-mariadb 1 0 0 0 1s
==> v1/Secret
NAME TYPE DATA AGE
happy-panda-mariadb Opaque 2 1s
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
happy-panda-mariadb 10.0.0.70 <none> 3306/TCP 1s
Notes:
MariaDB can be accessed via port 3306 on the following DNS name from within your cluster:
happy-panda-mariadb.default.svc.cluster.local
To connect to your database run the following command:
kubectl run happy-panda-mariadb-client --rm --tty -i --image bitnami/mariadb --command -- mysql -h happy-panda-mariadb
```
Now the `mariadb` chart is installed. Note that installing a chart
creates a new _release_ object. The release above is named
`happy-panda`. (If you want to use your own release name, simply use the
`--name` flag on `helm install`.)
During installation, the `helm` client will print useful information
about which resources were created, what the state of the release is,
and also whether there are additional configuration steps you can or
should take.
Helm does not wait until all of the resources are running before it
exits. Many charts require Docker images that are over 600M in size, and
may take a long time to install into the cluster.
To keep track of a release's state, or to re-read configuration
information, you can use `helm status`:
```
$ helm status happy-panda
Last Deployed: Wed Sep 28 12:32:28 2016
Namespace: default
Status: DEPLOYED
Resources:
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
happy-panda-mariadb 10.0.0.70 <none> 3306/TCP 4m
==> extensions/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
happy-panda-mariadb 1 1 1 1 4m
==> v1/Secret
NAME TYPE DATA AGE
happy-panda-mariadb Opaque 2 4m
Notes:
MariaDB can be accessed via port 3306 on the following DNS name from within your cluster:
happy-panda-mariadb.default.svc.cluster.local
To connect to your database run the following command:
kubectl run happy-panda-mariadb-client --rm --tty -i --image bitnami/mariadb --command -- mysql -h happy-panda-mariadb
```
The above shows the current state of your release.
### Customizing the Chart Before Installing
Installing the way we have here will only use the default configuration
options for this chart. Many times, you will want to customize the chart
to use your preferred configuration.
To see what options are configurable on a chart, use `helm inspect
values`:
```console
helm inspect values stable/mariadb
Fetched stable/mariadb-0.3.0.tgz to /Users/mattbutcher/Code/Go/src/helm.sh/helm/mariadb-0.3.0.tgz
## Bitnami MariaDB image version
## ref: https://hub.docker.com/r/bitnami/mariadb/tags/
##
## Default: none
imageTag: 10.1.14-r3
## Specify a imagePullPolicy
## Default to 'Always' if imageTag is 'latest', else set to 'IfNotPresent'
## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images
##
# imagePullPolicy:
## Specify password for root user
## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#setting-the-root-password-on-first-run
##
# mariadbRootPassword:
## Create a database user
## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#creating-a-database-user-on-first-run
##
# mariadbUser:
# mariadbPassword:
## Create a database
## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#creating-a-database-on-first-run
##
# mariadbDatabase:
```
You can then override any of these settings in a YAML formatted file,
and then pass that file during installation.
```console
$ echo '{mariadbUser: user0, mariadbDatabase: user0db}' > config.yaml
$ helm install -f config.yaml stable/mariadb
```
The above will create a default MariaDB user with the name `user0`, and
grant this user access to a newly created `user0db` database, but will
accept all the rest of the defaults for that chart.
There are two ways to pass configuration data during install:
- `--values` (or `-f`): Specify a YAML file with overrides. This can be specified multiple times
and the rightmost file will take precedence
- `--set`: Specify overrides on the command line.
If both are used, `--set` values are merged into `--values` with higher precedence.
Overrides specified with `--set` are persisted in a configmap. Values that have been
`--set` can be viewed for a given release with `helm get values <release-name>`.
Values that have been `--set` can be cleared by running `helm upgrade` with `--reset-values`
specified.
#### The Format and Limitations of `--set`
The `--set` option takes zero or more name/value pairs. At its simplest, it is
used like this: `--set name=value`. The YAML equivalent of that is:
```yaml
name: value
```
Multiple values are separated by `,` characters. So `--set a=b,c=d` becomes:
```yaml
a: b
c: d
```
More complex expressions are supported. For example, `--set outer.inner=value` is
translated into this:
```yaml
outer:
inner: value
```
Lists can be expressed by enclosing values in `{` and `}`. For example,
`--set name={a, b, c}` translates to:
```yaml
name:
- a
- b
- c
```
As of Helm 2.5.0, it is possible to access list items using an array index syntax.
For example, `--set servers[0].port=80` becomes:
```yaml
servers:
- port: 80
```
Multiple values can be set this way. The line `--set servers[0].port=80,servers[0].host=example` becomes:
```yaml
servers:
- port: 80
host: example
```
Sometimes you need to use special characters in your `--set` lines. You can use
a backslash to escape the characters; `--set name=value1\,value2` will become:
```yaml
name: "value1,value2"
```
Similarly, you can escape dot sequences as well, which may come in handy when charts use the
`toYaml` function to parse annotations, labels and node selectors. The syntax for
`--set nodeSelector."kubernetes\.io/role"=master` becomes:
```yaml
nodeSelector:
kubernetes.io/role: master
```
Deeply nested data structures can be difficult to express using `--set`. Chart
designers are encouraged to consider the `--set` usage when designing the format
of a `values.yaml` file.
### More Installation Methods
The `helm install` command can install from several sources:
- A chart repository (as we've seen above)
- A local chart archive (`helm install foo-0.1.1.tgz`)
- An unpacked chart directory (`helm install path/to/foo`)
- A full URL (`helm install https://example.com/charts/foo-1.2.3.tgz`)
## 'helm upgrade' and 'helm rollback': Upgrading a Release, and Recovering on Failure
When a new version of a chart is released, or when you want to change
the configuration of your release, you can use the `helm upgrade`
command.
An upgrade takes an existing release and upgrades it according to the
information you provide. Because Kubernetes charts can be large and
complex, Helm tries to perform the least invasive upgrade. It will only
update things that have changed since the last release.
```console
$ helm upgrade -f panda.yaml happy-panda stable/mariadb
Fetched stable/mariadb-0.3.0.tgz to /Users/mattbutcher/Code/Go/src/helm.sh/helm/mariadb-0.3.0.tgz
happy-panda has been upgraded. Happy Helming!
Last Deployed: Wed Sep 28 12:47:54 2016
Namespace: default
Status: DEPLOYED
...
```
In the above case, the `happy-panda` release is upgraded with the same
chart, but with a new YAML file:
```yaml
mariadbUser: user1
```
We can use `helm get values` to see whether that new setting took
effect.
```console
$ helm get values happy-panda
mariadbUser: user1
```
The `helm get` command is a useful tool for looking at a release in the
cluster. And as we can see above, it shows that our new values from
`panda.yaml` were deployed to the cluster.
Now, if something does not go as planned during a release, it is easy to
roll back to a previous release using `helm rollback [RELEASE] [REVISION]`.
```console
$ helm rollback happy-panda 1
```
The above rolls back our happy-panda to its very first release version.
A release version is an incremental revision. Every time an install,
upgrade, or rollback happens, the revision number is incremented by 1.
The first revision number is always 1. And we can use `helm history [RELEASE]`
to see revision numbers for a certain release.
## Helpful Options for Install/Upgrade/Rollback
There are several other helpful options you can specify for customizing the
behavior of Helm during an install/upgrade/rollback. Please note that this
is not a full list of cli flags. To see a description of all flags, just run
`helm <command> --help`.
- `--timeout`: A value in seconds to wait for Kubernetes commands to complete
This defaults to 300 (5 minutes)
- `--wait`: Waits until all Pods are in a ready state, PVCs are bound, Deployments
have minimum (`Desired` minus `maxUnavailable`) Pods in ready state and
Services have an IP address (and Ingress if a `LoadBalancer`) before
marking the release as successful. It will wait for as long as the
`--timeout` value. If timeout is reached, the release will be marked as
`FAILED`. Note: In scenario where Deployment has `replicas` set to 1 and
`maxUnavailable` is not set to 0 as part of rolling update strategy,
`--wait` will return as ready as it has satisfied the minimum Pod in ready condition.
- `--no-hooks`: This skips running hooks for the command
- `--recreate-pods` (only available for `upgrade` and `rollback`): This flag
will cause all pods to be recreated (with the exception of pods belonging to
deployments)
## 'helm uninstall': Uninstalling a Release
When it is time to uninstall or uninstall a release from the cluster, use
the `helm uninstall` command:
```
$ helm uninstall happy-panda
```
This will remove the release from the cluster. You can see all of your
currently deployed releases with the `helm list` command:
```
$ helm list
NAME VERSION UPDATED STATUS CHART
inky-cat 1 Wed Sep 28 12:59:46 2016 DEPLOYED alpine-0.1.0
```
From the output above, we can see that the `happy-panda` release was
uninstalled.
However, Helm always keeps records of what releases happened. Need to
see the uninstalled releases? `helm list --uninstalled` shows those, and `helm
list --all` shows all of the releases (uninstalled and currently deployed,
as well as releases that failed):
```console
⇒ helm list --all
NAME VERSION UPDATED STATUS CHART
happy-panda 2 Wed Sep 28 12:47:54 2016 UNINSTALLED mariadb-0.3.0
inky-cat 1 Wed Sep 28 12:59:46 2016 DEPLOYED alpine-0.1.0
kindred-angelf 2 Tue Sep 27 16:16:10 2016 UNINSTALLED alpine-0.1.0
```
Because Helm keeps records of uninstalled releases, a release name cannot
be re-used. (If you _really_ need to re-use a release name, you can use
the `--replace` flag, but it will simply re-use the existing release and
replace its resources.)
Note that because releases are preserved in this way, you can rollback a
uninstalled resource, and have it re-activate.
## 'helm repo': Working with Repositories
So far, we've been installing charts only from the `stable` repository.
But you can configure `helm` to use other repositories. Helm provides
several repository tools under the `helm repo` command.
You can see which repositories are configured using `helm repo list`:
```console
$ helm repo list
NAME URL
stable https://kubernetes-charts.storage.googleapis.com
local http://localhost:8879/charts
mumoshu https://mumoshu.github.io/charts
```
And new repositories can be added with `helm repo add`:
```console
$ helm repo add dev https://example.com/dev-charts
```
Because chart repositories change frequently, at any point you can make
sure your Helm client is up to date by running `helm repo update`.
## Creating Your Own Charts
The [Chart Development Guide](charts.md) explains how to develop your own
charts. But you can get started quickly by using the `helm create`
command:
```console
$ helm create deis-workflow
Creating deis-workflow
```
Now there is a chart in `./deis-workflow`. You can edit it and create
your own templates.
As you edit your chart, you can validate that it is well-formatted by
running `helm lint`.
When it's time to package the chart up for distribution, you can run the
`helm package` command:
```console
$ helm package deis-workflow
deis-workflow-0.1.0.tgz
```
And that chart can now easily be installed by `helm install`:
```console
$ helm install ./deis-workflow-0.1.0.tgz
...
```
Charts that are archived can be loaded into chart repositories. See the
documentation for your chart repository server to learn how to upload.
Note: The `stable` repository is managed on the [Kubernetes Charts
GitHub repository](https://github.com/helm/charts). That project
accepts chart source code, and (after audit) packages those for you.
## Conclusion
This chapter has covered the basic usage patterns of the `helm` client,
including searching, installation, upgrading, and uninstalling. It has also
covered useful utility commands like `helm status`, `helm get`, and
`helm repo`.
For more information on these commands, take a look at Helm's built-in
help: `helm help`.
In the next chapter, we look at the process of developing charts.

@ -6,4 +6,4 @@ couple of parameters.
The `values.toml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -6,4 +6,4 @@ couple of parameters.
The `values.toml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -6,4 +6,4 @@ couple of parameters.
The `values.toml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -26,8 +26,6 @@ type Maintainer struct {
}
// Metadata for a Chart file. This models the structure of a Chart.yaml file.
//
// Spec: https://helm.sh/helm/blob/master/docs/design/chart_format.md#the-chart-file
type Metadata struct {
// The name of the chart
Name string `json:"name,omitempty"`

@ -6,4 +6,4 @@ couple of parameters.
The `values.toml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -6,4 +6,4 @@ couple of parameters.
The `values.toml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -6,4 +6,4 @@ couple of parameters.
The `values.toml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -6,4 +6,4 @@ couple of parameters.
The `values.toml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -6,4 +6,4 @@ couple of parameters.
The `values.toml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -6,4 +6,4 @@ couple of parameters.
The `values.toml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -6,4 +6,4 @@ couple of parameters.
The `values.toml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -6,4 +6,4 @@ couple of parameters.
The `values.yaml` file contains the default values for the
`alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`.
You can install this example using `helm install ./alpine`.

@ -1,55 +0,0 @@
#!/usr/bin/env bash
# Copyright The Helm Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -euo pipefail
source scripts/util.sh
if LANG=C sed --help 2>&1 | grep -q GNU; then
SED="sed"
elif which gsed &>/dev/null; then
SED="gsed"
else
echo "Failed to find GNU sed as sed or gsed. If you are on Mac: brew install gnu-sed." >&2
exit 1
fi
kube::util::ensure-temp-dir
export HELM_NO_PLUGINS=1
# Reset Helm Home because it is used in the generation of docs.
OLD_HELM_HOME=${HELM_HOME:-}
HELM_HOME="$HOME/.helm"
bin/helm init
mkdir -p docs/helm
mkdir -p ${KUBE_TEMP}/docs/helm
bin/helm docs --dir ${KUBE_TEMP}/docs/helm
HELM_HOME=$OLD_HELM_HOME
FILES=$(find ${KUBE_TEMP} -type f)
${SED} -i -e "s:${HOME}:~:" ${FILES}
for i in ${FILES}; do
ret=0
truepath=$(echo ${i} | ${SED} "s:${KUBE_TEMP}/::")
diff -NauprB -I 'Auto generated' "${i}" "${truepath}" > /dev/null || ret=$?
if [[ $ret -ne 0 ]]; then
echo "${truepath} changed. Updating.."
cp "${i}" "${truepath}"
fi
done

@ -1,55 +0,0 @@
#!/usr/bin/env bash
# Copyright The Helm Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -euo pipefail
source scripts/util.sh
if LANG=C sed --help 2>&1 | grep -q GNU; then
SED="sed"
elif which gsed &>/dev/null; then
SED="gsed"
else
echo "Failed to find GNU sed as sed or gsed. If you are on Mac: brew install gnu-sed." >&2
exit 1
fi
kube::util::ensure-temp-dir
export HELM_NO_PLUGINS=1
# Reset Helm Home because it is used in the generation of docs.
OLD_HELM_HOME=${HELM_HOME:-}
HELM_HOME="$HOME/.helm"
bin/helm init
mkdir -p ${KUBE_TEMP}/docs/helm
bin/helm docs --dir ${KUBE_TEMP}/docs/helm
HELM_HOME=$OLD_HELM_HOME
FILES=$(find ${KUBE_TEMP} -type f)
${SED} -i -e "s:${HOME}:~:" ${FILES}
ret=0
for i in ${FILES}; do
diff -NauprB -I 'Auto generated' ${i} $(echo ${i} | ${SED} "s:${KUBE_TEMP}/::") || ret=$?
done
if [[ $ret -eq 0 ]]; then
echo "helm docs up to date."
else
echo "helm docs are out of date. Please run \"make docs\""
exit 1
fi
Loading…
Cancel
Save