20 KiB
Common: The Helm Helper Chart
This chart is designed to make it easier for you to build and maintain Helm charts.
It provides utilities that reflect best practices of Kubernetes chart development, making it faster for you to write charts.
Tips
A few tips for working with Common:
- Be careful when using functions that generate random data (like
common.fullname.unique
). They may trigger unwanted upgrades or have other side effects.
In this document, we use release-name
as the name of the release.
Resource Kinds
Kubernetes defines a variety of resource kinds, from Secret
to StatefulSet
.
We define some of the most common kinds in a way that lets you easily work with
them.
The resource kind templates are designed to make it much faster for you to define basic versions of these resources. They allow you to extend and modify just what you need, without having to copy around lots of boilerplate.
To make use of these templates you must define a template that will extend the base template (though it can be empty). The name of this template is then passed to the base template, for example:
{{- template "common.service" (list . "mychart.service") -}}
{{- define "mychart.service" -}}
## Define overrides for your Service resource here, e.g.
# metadata:
# labels:
# custom: label
# spec:
# ports:
# - port: 8080
{{- end -}}
Note that the common.service
template defines two parameters:
- The root context (usually
.
) - A template name containing the service definition overrides
A limitation of the Go template library is that a template can only take a
single argument. The list
function is used to work around this by constructing
a list or array of arguments that is passed to the template.
The common.service
template is responsible for rendering the templates with
the root context and merging any overrides. As you can see, this makes it very
easy to create a basic Service
resource without having to copy around the
standard metadata and labels.
Each implemented base resource is described in greater detail below.
common.service
The common.service
template creates a basic Service
resource with the
following defaults:
- Service type (ClusterIP, NodePort, LoadBalancer) made configurable by
.Values.service.type
- Named port
http
configured on port 80 - Selector set to
app.kubernetes.io/name: {{ template "common.name" }}, app.kubernetes.io/instance: {{ .Release.Name | quote }}
to match the default used in theDeployment
resource
Example template:
{{- template "common.service" (list . "mychart.mail.service") -}}
{{- define "mychart.mail.service" -}}
metadata:
name: {{ template "common.fullname" . }}-mail # overrides the default name to add a suffix
labels: # appended to the labels section
protocol: mail
spec:
ports: # composes the `ports` section of the service definition.
- name: smtp
port: 25
targetPort: 25
- name: imaps
port: 993
targetPort: 993
selector: # this is appended to the default selector
protocol: mail
{{- end -}}
---
{{ template "common.service" (list . "mychart.web.service") -}}
{{- define "mychart.web.service" -}}
metadata:
name: {{ template "common.fullname" . }}-www # overrides the default name to add a suffix
labels: # appended to the labels section
protocol: www
spec:
ports: # composes the `ports` section of the service definition.
- name: www
port: 80
targetPort: 8080
{{- end -}}
The above template defines two services: a web service and a mail service.
The most important part of a service definition is the ports
object, which
defines the ports that this service will listen on. Most of the time,
selector
is computed for you. But you can replace it or add to it.
The output of the example above is:
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: service
helm.sh/chart: service-0.1.0
app.kubernetes.io/managed-by: Helm
protocol: mail
app.kubernetes.io/instance: release-name
name: release-name-service-mail
spec:
ports:
- name: smtp
port: 25
targetPort: 25
- name: imaps
port: 993
targetPort: 993
selector:
app.kubernetes.io/name: service
app.kubernetes.io/instance: release-name
protocol: mail
type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: service
helm.sh/chart: service-0.1.0
app.kubernetes.io/managed-by: Helm
protocol: www
app.kubernetes.io/instance: release-name
name: release-name-service-www
spec:
ports:
- name: www
port: 80
targetPort: 8080
type: ClusterIP
common.deployment
The common.deployment
template defines a basic Deployment
. Underneath the
hood, it uses common.container
(see next section).
By default, the pod template within the deployment defines the labels app: {{ template "common.name" . }}
and release: {{ .Release.Name | quote }
as this is also used as the selector. The
standard set of labels are not used as some of these can change during upgrades,
which causes the replica sets and pods to not correctly match.
Example use:
{{- template "common.deployment" (list . "mychart.deployment") -}}
{{- define "mychart.deployment" -}}
## Define overrides for your Deployment resource here, e.g.
spec:
replicas: {{ .Values.replicaCount }}
{{- end -}}
common.container
The common.container
template creates a basic Container
spec to be used
within a Deployment
or ReplicaSet
. It holds the following defaults:
- The name is set to the chart name
- Uses
.Values.image
to describe the image to run, with the following spec:image: repository: nginx tag: stable pullPolicy: IfNotPresent
- Exposes the named port
http
as port 80 - Lays out the compute resources using
.Values.resources
Example use:
{{- template "common.deployment" (list . "mychart.deployment") -}}
{{- define "mychart.deployment" -}}
## Define overrides for your Deployment resource here, e.g.
spec:
template:
spec:
containers:
- {{ template "common.container" (list . "mychart.deployment.container") }}
{{- end -}}
{{- define "mychart.deployment.container" -}}
## Define overrides for your Container here, e.g.
livenessProbe:
httpGet:
path: /
port: 80
readinessProbe:
httpGet:
path: /
port: 80
{{- end -}}
The above example creates a Deployment
resource which makes use of the
common.container
template to populate the PodSpec's container list. The usage
of this template is similar to the other resources, you must define and
reference a template that contains overrides for the container object.
The most important part of a container definition is the image you want to run.
As mentioned above, this is derived from .Values.image
by default. It is a
best practice to define the image, tag and pull policy in your charts' values as
this makes it easy for an operator to change the image registry, or use a
specific tag or version. Another example of configuration that should be exposed
to chart operators is the container's required compute resources, as this is
also very specific to an operators environment. An example values.yaml
for
your chart could look like:
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
The output of running the above values through the earlier template is:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: deployment
helm.sh/chart: deployment-0.1.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/instance: release-name
name: release-name-deployment
spec:
template:
metadata:
labels:
app.kubernetes.io/name: deployment
spec:
containers:
- image: nginx:stable
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
path: /
port: 80
name: deployment
ports:
- containerPort: 80
name: http
readinessProbe:
httpGet:
path: /
port: 80
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
common.configmap
The common.configmap
template creates an empty ConfigMap
resource that you
can override with your configuration.
Example use:
{{- template "common.configmap" (list . "mychart.configmap") -}}
{{- define "mychart.configmap" -}}
data:
zeus: cat
athena: cat
julius: cat
one: |-
{{ .Files.Get "file1.txt" }}
{{- end -}}
Output:
apiVersion: v1
data:
athena: cat
julius: cat
one: This is a file.
zeus: cat
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/name: configmap
helm.sh/chart: configmap-0.1.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/instance: release-name
name: release-name-configmap
common.secret
The common.secret
template creates an empty Secret
resource that you
can override with your secrets.
Example use:
{{- template "common.secret" (list . "mychart.secret") -}}
{{- define "mychart.secret" -}}
data:
zeus: {{ print "cat" | b64enc }}
athena: {{ print "cat" | b64enc }}
julius: {{ print "cat" | b64enc }}
one: |-
{{ .Files.Get "file1.txt" | b64enc }}
{{- end -}}
Output:
apiVersion: v1
data:
athena: Y2F0
julius: Y2F0
one: VGhpcyBpcyBhIGZpbGUuCg==
zeus: Y2F0
kind: Secret
metadata:
labels:
app.kubernetes.io/name: secret
helm.sh/chart: secret-0.1.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/instance: release-name
name: release-name-secret
type: Opaque
common.ingress
The common.ingress
template is designed to give you a well-defined Ingress
resource, that can be configured using .Values.ingress
. An example values file
that can be used to configure the Ingress
resource is:
ingress:
hosts:
- chart-example.local
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
tls:
- secretName: chart-example-tls
hosts:
- chart-example.local
Example use:
{{- template "common.ingress" (list . "mychart.ingress") -}}
{{- define "mychart.ingress" -}}
{{- end -}}
Output:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
labels:
app.kubernetes.io/name: ingress
helm.sh/chart: ingress-0.1.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/instance: release-name
name: release-name-ingress
spec:
rules:
- host: chart-example.local
http:
paths:
- backend:
serviceName: release-name-ingress
servicePort: 80
path: /
tls:
- hosts:
- chart-example.local
secretName: chart-example-tls
common.persistentvolumeclaim
common.persistentvolumeclaim
can be used to easily add a
PersistentVolumeClaim
resource to your chart that can be configured using
.Values.persistence
:
Value | Description |
---|---|
persistence.enabled | Whether or not to claim a persistent volume. If false, common.volume.pvc will use an emptyDir instead |
persistence.storageClass | StorageClass name |
persistence.accessMode | Access mode for persistent volume |
persistence.size | Size of persistent volume |
persistence.existingClaim | If defined, PersistentVolumeClaim is not created and common.volume.pvc helper uses this claim |
An example values file that can be used to configure the
PersistentVolumeClaim
resource is:
persistence:
enabled: true
storageClass: fast
accessMode: ReadWriteOnce
size: 8Gi
Example use:
{{- template "common.persistentvolumeclaim" (list . "mychart.persistentvolumeclaim") -}}
{{- define "mychart.persistentvolumeclaim" -}}
{{- end -}}
Output:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
labels:
app.kubernetes.io/name: persistentvolumeclaim
helm.sh/chart: persistentvolumeclaim-0.1.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/instance: release-name
name: release-name-persistentvolumeclaim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8Gi
storageClassName: "fast"
Partial API Objects
When writing Kubernetes resources, you may find the following helpers useful to construct parts of the spec.
EnvVar
Use the EnvVar helpers within a container spec to simplify specifying key-value environment variables or referencing secrets as values.
Example Use:
{{- template "common.deployment" (list . "mychart.deployment") -}}
{{- define "mychart.deployment" -}}
spec:
template:
spec:
containers:
- {{ template "common.container" (list . "mychart.deployment.container") }}
{{- end -}}
{{- define "mychart.deployment.container" -}}
{{- $fullname := include "common.fullname" . -}}
env:
- {{ template "common.envvar.value" (list "ZEUS" "cat") }}
- {{ template "common.envvar.secret" (list "ATHENA" "secret-name" "athena") }}
{{- end -}}
Output:
...
spec:
containers:
- env:
- name: ZEUS
value: cat
- name: ATHENA
valueFrom:
secretKeyRef:
key: athena
name: secret-name
...
Volume
Use the Volume helpers within a Deployment
spec to help define ConfigMap and
PersistentVolumeClaim volumes.
Example Use:
{{- template "common.deployment" (list . "mychart.deployment") -}}
{{- define "mychart.deployment" -}}
spec:
template:
spec:
volumes:
- {{ template "common.volume.configMap" (list "config" "configmap-name") }}
- {{ template "common.volume.pvc" (list "data" "pvc-name" .Values.persistence) }}
{{- end -}}
Output:
...
spec:
volumes:
- configMap:
name: configmap-name
name: config
- name: data
persistentVolumeClaim:
claimName: pvc-name
...
The common.volume.pvc
helper uses the following configuration from the .Values.persistence
object:
Value | Description |
---|---|
persistence.enabled | If false, creates an emptyDir instead |
persistence.existingClaim | If set, uses this instead of the passed in claim name |
Utilities
common.fullname
The common.fullname
template generates a name suitable for the name:
field
in Kubernetes metadata. It is used like this:
name: {{ template "common.fullname" . }}
The following different values can influence it:
# By default, fullname uses '{{ .Release.Name }}-{{ .Chart.Name }}'. This
# overrides that and uses the given string instead.
fullnameOverride: "some-name"
# This adds a prefix
fullnamePrefix: "pre-"
# This appends a suffix
fullnameSuffix: "-suf"
# Global versions of the above
global:
fullnamePrefix: "pp-"
fullnameSuffix: "-ps"
Example output:
---
# with the values above
name: pp-pre-some-name-suf-ps
---
# the default, for release "happy-panda" and chart "wordpress"
name: happy-panda-wordpress
Output of this function is truncated at 54 characters, which leaves 9 additional characters for customized overriding. Thus you can easily extend this name in your own charts:
{{- define "my.fullname" -}}
{{ template "common.fullname" . }}-my-stuff
{{- end -}}
common.fullname.unique
The common.fullname.unique
variant of fullname appends a unique seven-character
sequence to the end of the common name field.
This takes all of the same parameters as common.fullname
Example template:
uniqueName: {{ template "common.fullname.unique" . }}
Example output:
uniqueName: release-name-fullname-jl0dbwx
It is also impacted by the prefix and suffix definitions, as well as by
.Values.fullnameOverride
Note that the effective maximum length of this function is 63 characters, not 54.
common.name
The common.name
template generates a name suitable for the app
label. It is used like this:
app: {{ template "common.name" . }}
The following different values can influence it:
# By default, name uses '{{ .Chart.Name }}'. This
# overrides that and uses the given string instead.
nameOverride: "some-name"
# This adds a prefix
namePrefix: "pre-"
# This appends a suffix
nameSuffix: "-suf"
# Global versions of the above
global:
namePrefix: "pp-"
nameSuffix: "-ps"
Example output:
---
# with the values above
name: pp-pre-some-name-suf-ps
---
# the default, for chart "wordpress"
name: wordpress
Output of this function is truncated at 54 characters, which leaves 9 additional characters for customized overriding. Thus you can easily extend this name in your own charts:
{{- define "my.name" -}}
{{ template "common.name" . }}-my-stuff
{{- end -}}
common.metadata
The common.metadata
helper generates the metadata:
section of a Kubernetes
resource.
This takes three objects:
- .top: top context
- .fullnameOverride: override the fullname with this name
- .metadata
- .labels: key/value list of labels
- .annotations: key/value list of annotations
- .hook: name(s) of hook(s)
It generates standard labels, annotations, hooks, and a name field.
Example template:
{{ template "common.metadata" (dict "top" . "metadata" .Values.bio) }}
---
{{ template "common.metadata" (dict "top" . "metadata" .Values.pet "fullnameOverride" .Values.pet.fullnameOverride) }}
Example values:
bio:
name: example
labels:
first: matt
last: butcher
nick: technosophos
annotations:
format: bio
destination: archive
hook: pre-install
pet:
fullnameOverride: Zeus
Example output:
metadata:
name: release-name-metadata
labels:
app.kubernetes.io/name: metadata
app.kubernetes.io/managed-by: "Helm"
app.kubernetes.io/instance: "release-name"
helm.sh/chart: metadata-0.1.0
first: "matt"
last: "butcher"
nick: "technosophos"
annotations:
"destination": "archive"
"format": "bio"
"helm.sh/hook": "pre-install"
---
metadata:
name: Zeus
labels:
app.kubernetes.io/name: metadata
app.kubernetes.io/managed-by: "Helm"
app.kubernetes.io/instance: "release-name"
helm.sh/chart: metadata-0.1.0
annotations:
Most of the common templates that define a resource type (e.g. common.configmap
or common.job
) use this to generate the metadata, which means they inherit
the same labels
, annotations
, nameOverride
, and hook
fields.
common.labelize
common.labelize
turns a map into a set of labels.
Example template:
{{- $map := dict "first" "1" "second" "2" "third" "3" -}}
{{- template "common.labelize" $map -}}
Example output:
first: "1"
second: "2"
third: "3"
common.labels.standard
common.labels.standard
prints the standard set of labels.
Example usage:
{{ template "common.labels.standard" . }}
Example output:
app.kubernetes.io/name: labelizer
app.kubernetes.io/managed-by: "Tiller"
app.kubernetes.io/instance: "release-name"
helm.sh/chart: labelizer-0.1.0
common.hook
The common.hook
template is a convenience for defining hooks.
Example template:
{{ template "common.hook" "pre-install,post-install" }}
Example output:
"helm.sh/hook": "pre-install,post-install"
common.chartref
The common.chartref
helper prints the chart name and version, escaped to be
legal in a Kubernetes label field.
Example template:
chartref: {{ template "common.chartref" . }}
For the chart foo
with version 1.2.3-beta.55+1234
, this will render:
chartref: foo-1.2.3-beta.55_1234
(Note that +
is an illegal character in label values)