×
Community Blog Helm Charts and Template Basics - Part 2

Helm Charts and Template Basics - Part 2

In this tutorial, we will briefly discuss how Helm can help simplify Kubernetes app management, and learn how to use Helm to create a basic chart for us.

By Alwyn Botha, Alibaba Cloud Community Blog author.

This tutorial explains how the deployment.yaml Helm template gets converted from template to YAML manifest.

It does not follow the traditional programming reference guide: statements and functions listed in alphabetical order.

It explains template syntax as needed to explain deployment.yaml top to bottom.

Using values in templates

Here is the complete deployment.yaml for reference:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "myhelm1.fullname" . }}
  labels:
    app.kubernetes.io/name: {{ include "myhelm1.name" . }}
    helm.sh/chart: {{ include "myhelm1.chart" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ include "myhelm1.name" . }}
      app.kubernetes.io/instance: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ include "myhelm1.name" . }}
        app.kubernetes.io/instance: {{ .Release.Name }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          
          terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
          
          command: ['sh', '-c', 'sleep 60']
                    
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
    {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
    {{- end }}
    {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
    {{- end }}

Extract of this deployment.yaml :

    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
  replicas: {{ .Values.replicaCount }}
      app.kubernetes.io/instance: {{ .Release.Name }}
        app.kubernetes.io/instance: {{ .Release.Name }}
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}

.Release.Name and .Release.Service are built in objects - complete list at https://docs.helm.sh/chart_template_guide/ ( Unfortunately there are no links to specific parts of their VERY long web pages - you have to scroll down to find it ) ... Built-in Objects

Below is how the final deployment.yaml gets rendered if you use:

helm install .\myhelm1\ --name test5 --dry-run --debug

For this top 50% part of the tutorial you do not run any commands, just read. ( Even debug has too much output if all we want is to investigate the syntax of a 3 line template. )

( After you have read the full tutorial once you may want to read it again, but this time editing the template and value files and running helm install with debug to play / learn )

    app.kubernetes.io/instance: test5
    app.kubernetes.io/managed-by: Tiller
      app.kubernetes.io/instance: test5
        - name: myhelm1
          image: "radial/busyboxplus:base"
          imagePullPolicy: IfNotPresent

These 3 values below are pulled in from the values.yaml file:

          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}

Extract of values.yaml

image:
  repository: radial/busyboxplus
  tag: base
  pullPolicy: IfNotPresent

- name: {{ .Chart.Name }} is from the Chart.yaml file. Its contents is shown below.

apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: myhelm1
version: 0.1.0

Probably half of all templates are just such simple values replacements.

You have seen that within YAML files we have template directives embedded in {{ and }}.

You must have blank space after opening {{ and a blank space before closing }}.

Those leading dots are needed.

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 Chart indicates that we start with the top-most namespace. Read .Chart.name as "start at the top namespace, find the Chart object, then look inside of it for an object called name".

with

**values.yaml** extract: 

nodeSelector:
    disktype: ssd
    gpu: Nvidia
**deployment.yaml** extract: 

      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}

Gets rendered as:

      nodeSelector:
        disktype: ssd
        gpu: Nvidia

VERY important: spaces have syntax meaning in YAML.

The rendered two selectors have 8 spaces before them since in deployment.yaml we have {{- toYaml . | nindent 8 }}

nindent 8 indents it 8 spaces.

with is a loop construct. With the values in .Values.nodeSelector: convert it toYaml.

That dot after toYaml is the current value of .Values.nodeSelector in the loop. It must be there.

Consider it similar to sum(1,34,454) ... as toYaml(.) ... it is the value of the parm passed.

The pipe symbol | works as you are familiar in Linux shell.

affinity: and tolerations: with work exactly the same.

Unfortunately these examples do not show how with is also a current scope modifier. That is explained well at MODIFYING SCOPE USING WITH

Except for include you now fully understand how the whole deployment.yaml gets rendering by using values from values.yaml, Chart.yaml, and Built-in Objects.

The full service.yaml below:

You now fully understand it as well.

apiVersion: v1
kind: Service
metadata:
  name: {{ include "myhelm1.fullname" . }}
  labels:
    app.kubernetes.io/name: {{ include "myhelm1.name" . }}
    helm.sh/chart: {{ include "myhelm1.chart" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: {{ include "myhelm1.name" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}

Helm variables and range

Extract of first and last 3 lines of ingress.yaml

{{- if .Values.ingress.enabled -}}
{{- $fullName := include "myhelm1.fullname" . -}}
{{- $ingressPaths := .Values.ingress.paths -}}
... rest of yaml ....
    {{- end }}
  {{- end }}
{{- end }}
**values.yaml** extract: 
ingress:
  enabled: false

All the content of ingress.yaml is wrapped in a big if ... starting at line 1 and ending at very last line. If ingress enabled is false NO yaml content gets generated - as we want it to be.

Line 2 and 3 demonstrates how to declare Helm template variables.

Note the hyphens at {{ and }}

Those hyphens/dashes eat whitespace characters. {{- eats all whitespaces to the left

-}} means whitespace to the right should be consumed - including the newline - the line is entirely removed.

Extract of values.yaml

ingress:
  enabled: false
  hosts:
    - chart-example.local
  tls:
    - secretName: chart-example-tls
      hosts:
        - chart-example.local-1
        - chart-example.local-2
        - chart-example.local-3

Extract of deployment.yaml :

{{- if .Values.ingress.tls }}
  tls:
  {{- range .Values.ingress.tls }}
    - hosts:
      {{- range .hosts }}
        - {{ . | quote }}
      {{- end }}
      secretName: {{ .secretName }}
  {{- end }}
{{- end }}

Gets rendered as:

spec:
  tls:
    - hosts:
        - "chart-example.local-1"
        - "chart-example.local-2"
        - "chart-example.local-3"
      secretName: chart-example-tls

Note how the range loop generates the list of hosts. The quote surrounds each host with quotes.

There is also a range .Values.ingress.tls loop that loops only once. Giving this loop 3 values will demonstrate how it will range over the values.

Extract of **values.yaml** 

ingress:
  enabled: false
  hosts:
    - chart-example.local
  tls:
    - secretName: chart-example-tls-a
      hosts:
        - chart-example.local-1-a
        - chart-example.local-2-a
        - chart-example.local-3-a

    - secretName: chart-example-tls-b
      hosts:
        - chart-example.local-1-b
        - chart-example.local-2-b

    - secretName: chart-example-tls-c
      hosts:
        - chart-example.local-1-c
        - chart-example.local-2-c
        - chart-example.local-3-c
        - chart-example.local-4-c

Gets rendered as:

  tls:
    - hosts:
        - "chart-example.local-1-a"
        - "chart-example.local-2-a"
        - "chart-example.local-3-a"
      secretName: chart-example-tls-a
    - hosts:
        - "chart-example.local-1-b"
        - "chart-example.local-2-b"
      secretName: chart-example-tls-b
    - hosts:
        - "chart-example.local-1-c"
        - "chart-example.local-2-c"
        - "chart-example.local-3-c"
        - "chart-example.local-4-c"
      secretName: chart-example-tls-c

importance of -

Original template with hyphens.

{{- if .Values.ingress.tls }}
  tls:
  {{- range .Values.ingress.tls }}
    - hosts:
      {{- range .hosts }}
        - {{ . | quote }}
      {{- end }}
      secretName: {{ .secretName }}
  {{- end }}
{{- end }}

template with hyphens removed:

{{ if .Values.ingress.tls }}
  tls:
  {{ range .Values.ingress.tls }}
    - hosts:
      {{ range .hosts }}
        - {{ . | quote }}
      {{ end }}
      secretName: {{ .secretName }}
  {{ end }}
{{ end }}

Renders as:

  tls:
    - hosts:

        - "chart-example.local-1-a"

        - "chart-example.local-2-a"

        - "chart-example.local-3-a"

      secretName: chart-example-tls-a
      
    - hosts:

        - "chart-example.local-1-b"

        - "chart-example.local-2-b"

      secretName: chart-example-tls-b
      
    - hosts:

        - "chart-example.local-1-c"

        - "chart-example.local-2-c"

        - "chart-example.local-3-c"

        - "chart-example.local-4-c"

      secretName: chart-example-tls-c
      

You need to have the space-and-line-end eating hyphens.

_helpers.tpl

We now understand how values are used to generate all our templates.

One exception: name: {{ include "myhelm1.fullname" . }} - the include.

We now explore the include

We use include to include other templates into our YAML templates.

The file _helpers.tpl is the standard way to define several short template snippets we want to include in other templates.

Here is the first named template in _helpers.tpl :

{{- define "myhelm1.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}

On the first line we give the template snippet a name. We then refer to this name to include it.

The second line gives "myhelm1.name" a default value: .Chart.Name

If the default value does not exist "myhelm1.name" gets the value of .Values.nameOverride

trunc 63 truncates it to 63 characters in length.

trimSuffix "-" removes ONE trailing - if one exists.

but

trimSuffix "--" removes only two trailing -- if it exists.

( It does not work as in some programming languages where trim will remove all trailing characters )

app.kubernetes.io/name: {{ include "myhelm1.name" . }}

render as

app.kubernetes.io/name: myhelm1

Next: the template code

helm.sh/chart: {{ include "myhelm1.chart" . }}

renders as

helm.sh/chart: myhelm1-0.1.0

This is the template function :

{{- define "myhelm1.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

printf "%s-%s" .Chart.Name .Chart.Version concatenates .Chart.Name and .Chart.Version - plus it places a hyphen between the two.

replace "+" "_" replaces plus characters with underscores.

Now that you can understand those two one-liner functions you should be able to understand the 10-liner define "myhelm1.fullname" with ease.

If you have any programming experience you will see the if/else works as expected:

if condition
 do something
else
 do something else
end

The only difference is the {{ and }} template syntax.

learn Helm template syntax fast

The official Helm documentation contains detailed reference information about charts and templates.

The Chart Developer's Guide : https://helm.sh/docs/topics/charts/

The Chart Template Developer's Guide : https://docs.helm.sh/chart_template_guide/

It may take a day to read each page. The best way to learn is via interactive use.

This part of the tutorial explains how to learn Helm interactively. It is an ugly but fast hack.

The hack involves:

  • edit as few files as possible
  • only show as few rendered template lines as possible
  • do no live installs, only debug dry-runs

Let's convert our current chart files to this as quickly as possible - remember ugly and hack is FAST.

Edit your values.yaml file to look like below:

replicaCount: 1

terminationGracePeriodSeconds: 30

image:
  repository: radial/busyboxplus
  tag: base
  pullPolicy: IfNotPresent

Ensure ./myhelm1/.helmignore contains these lines at bottom:

NOTES.txt
test-connection.yaml
service.yaml
ingress.yaml

Make deployment.yaml content as below:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: {{ include "myhelm1.name" . }}
    helm.sh/chart: {{ include "myhelm1.chart" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          
          terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}

ALL we need is some ( even INVALID ) yaml to play with.

Do a dry run:

helm install .\myhelm1\  --name test5 --dry-run --debug

Output too long as shown below:

PS C:\k8> helm install .\myhelm1\  --name test5 --dry-run --debug
[debug] Created tunnel using local port: '50327'

[debug] SERVER: "127.0.0.1:50327"

[debug] Original chart version: ""
[debug] CHART PATH: C:\k8\myhelm1

NAME:   test5
REVISION: 1
RELEASED: Fri Feb 15 13:47:49 2019
CHART: myhelm1-0.1.0
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
image:
  pullPolicy: IfNotPresent
  repository: radial/busyboxplus
  tag: base
replicaCount: 1
terminationGracePeriodSeconds: 30

HOOKS:
MANIFEST:

---
# Source: myhelm1/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: myhelm1
    helm.sh/chart: myhelm1-0.1.0
    app.kubernetes.io/instance: test5
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: myhelm1
          image: "radial/busyboxplus:base"
          imagePullPolicy: IfNotPresent

          terminationGracePeriodSeconds: 30

Get rid of the first few 'useless' lines via grep.

helm install .\myhelm1\  --name test5 --dry-run --debug | grep -vE 'debug]|NAME|REVIS|RELEA|ART:|OKS:|FEST:'

See below. This is all we need: some values to play with and some yaml template content to play with template syntax.

USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
image:
  pullPolicy: IfNotPresent
  repository: radial/busyboxplus
  tag: base
replicaCount: 1
terminationGracePeriodSeconds: 30


---
# Source: myhelm1/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: myhelm1
    helm.sh/chart: myhelm1-0.1.0
    app.kubernetes.io/instance: test5
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: myhelm1
          image: "radial/busyboxplus:base"
          imagePullPolicy: IfNotPresent

          terminationGracePeriodSeconds: 30

Now go wild and learn some syntax:

See below deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: {{ include "myhelm1.name" . }}
    helm.sh/chart: {{ include "myhelm1.chart" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
spec: #-------------------->> learn spacing << ------------------------
  replicas1: {{ .Values.replicaCount }}
  replicas2:   {{ .Values.replicaCount }}
  replicas3:    {{ .Values.replicaCount }}
  replicas4: '{{ .Values.replicaCount }}'
  replicas5: "{{ .Values.replicaCount }}"
  replicas6: "{{    .Values.replicaCount }}"
  replicas7: "{{    .Values.replicaCount       }}"
  replicas: "{{    .Values.replicaCount       }}'
  replicas: '{{    .Values.replicaCount       }}"
  replicas: {{    .Values.replicaCount       }}"
  replicas: "{{    .Values.replicaCount       }}

  template:
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image1: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          image2: "{{ .Values.image.repository }} {{ .Values.image.tag }}"
          image3: "{{ .Values.image.repository }}{{ .Values.image.tag }}"
          image4: {{ .Values.image.repository }}{{ .Values.image.tag }}
          
          imagePullPolicy1: {{ .Values.image.pullPolicy }}
          imagePullPolicy2: {{ .Values.image.pullPolicyzzz }}
          imagePullPolicy3: {{ .Values.image.pullPolicyeeeeeeeeeee }}
          
          terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}

Output:

spec: #-------------------->> learn spacing << ------------------------
  replicas1: 1
  replicas2:   1
  replicas3:    1
  replicas4: '1'
  replicas5: "1"
  replicas6: "1"
  replicas7: "1"
  template:
    spec:
      containers:
        - name: myhelm1
          image1: "radial/busyboxplus:base"
          image2: "radial/busyboxplus base"
          image3: "radial/busyboxplusbase"
          image4: radial/busyboxplusbase

          imagePullPolicy1: IfNotPresent
          imagePullPolicy2:
          imagePullPolicy3:

          terminationGracePeriodSeconds: 30

See how much syntax you learned in seconds.

Make mistakes so you can learn what errors really mean. You also learn when error message helps and when it misleads.

Edit deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: {{ include "myhelm1.name" . }}
    helm.sh/chart: {{ include "myhelm1.chart" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
spec: #
  replicas1: {{ .Values.replicaCount }}

  template:
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image1: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          
          imagePullPolicy-correct: {{ .Values.image.pullPolicy }}

          imagePullPolicy1: {{ Values.image.pullPolicy }}
          imagePullPolicy2: {{ .Valu.image.pullPolicyzzz }}
          imagePullPolicy3: {{ ..Values.image.pullPolicyeeeeeeeeeee }}

Dry run:

helm install .\myhelm1\  --name test5 --dry-run --debug | grep -vE 'debug]|NAME|REVIS|RELEA|ART:|OKS:|FEST:'
Error: parse error in "myhelm1/templates/deployment.yaml": template: myhelm1/templates/deployment.yaml:19: function "Values" not defined

READ, understand and fix error, resubmit.

Error: parse error in "myhelm1/templates/deployment.yaml": template: myhelm1/templates/deployment.yaml:21: unexpected . after term "."

READ, understand and fix error, resubmit.

Error: render error in "myhelm1/templates/deployment.yaml": template: myhelm1/templates/deployment.yaml:20:36: executing "myhelm1/templates/deployment.yaml" at 
<.Valu.image.pullPoli...>: can't evaluate field image in type interface {}
helm install .\myhelm1\  --name test5 --dry-run --debug | grep -vE 'debug]|NAME|REVIS|RELEA|ART:|OKS:|FEST:'

Some different syntax experiments below:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: {{ include "myhelm1.name" . }}
    helm.sh/chart: {{ include "myhelm1.chart" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
spec: #
  replicas1: {{ .Values.replicaCount }}

  template:
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image1: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          
          imagePullPolicy1: {{ quote .Values.image.pullPolicy }}

          imagePullPolicy2: {{ .Values.image.pullPolicy | quote }}

          imagePullPolicy3: "{{ .Values.image.pullPolicy }}"

          imagePullPolicy4: {{ .Values.image.pullPolicy | upper }}

          imagePullPolicy5: {{ .Values.image.pullPolicy | lower }}

{{ $variable := 123 }}

          variable: $variable           
          variable: {{ $variable }}

See the extra 3 lines at bottom - use those - characters to remove it. Remove all 3 lines.

Helm is not as interactive as Python but this way you can nearly make it so.

Gets rendered as:

      containers:
        - name: myhelm1
          image1: "radial/busyboxplus:base"

          imagePullPolicy1: "IfNotPresent"

          imagePullPolicy2: "IfNotPresent"

          imagePullPolicy3: "IfNotPresent"

          imagePullPolicy4: IFNOTPRESENT

          imagePullPolicy5: ifnotpresent



          variable: $variable
          variable: 123          

Another trick. See imagePullPolicy 1 to 3 looks the same. What did we do? You can ugly hack titles like this:

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: {{ include "myhelm1.name" . }}
    helm.sh/chart: {{ include "myhelm1.chart" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
spec: #
  replicas1: {{ .Values.replicaCount }}

  template:
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image1: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          
#          imagePullPolicy1: {{ quote .Values.image.pullPolicy }}
          imagePullPolicy1: {{ quote .Values.image.pullPolicy }}

#          imagePullPolicy2: {{ .Values.image.pullPolicy | quote }}
          imagePullPolicy2: {{ .Values.image.pullPolicy | quote }}

          imagePullPolicy3: " .Values.image.pullPolicy "
          imagePullPolicy3: "{{ .Values.image.pullPolicy }}"

          imagePullPolicy4:  .Values.image.pullPolicy | upper 
          imagePullPolicy4: {{ .Values.image.pullPolicy | upper }}

          imagePullPolicy5:  .Values.image.pullPolicy | lower 
          imagePullPolicy5: {{ .Values.image.pullPolicy | lower }}

{{ $variable := 123 }}

          variable: $variable           
          variable: {{ $variable }}
helm install .\myhelm1\  --name test5 --dry-run --debug | grep -vE 'debug]|NAME|REVIS|RELEA|ART:|OKS:|FEST:'

Output:


        - name: myhelm1
          image1: "radial/busyboxplus:base"

#          imagePullPolicy1: "IfNotPresent"
          imagePullPolicy1: "IfNotPresent"

#          imagePullPolicy2: "IfNotPresent"
          imagePullPolicy2: "IfNotPresent"

          imagePullPolicy3: " .Values.image.pullPolicy "
          imagePullPolicy3: "IfNotPresent"

          imagePullPolicy4:  .Values.image.pullPolicy | upper
          imagePullPolicy4: IFNOTPRESENT

          imagePullPolicy5:  .Values.image.pullPolicy | lower
          imagePullPolicy5: ifnotpresent

Note comments does not help. Template syntax inside comments gets interpreted.

Remove the {{ and }} always works. Then you can look at your source template code and the result on the following line in the output.

Best way to show titles of what is been tested seem to be to use { { and { } instead of {{ and }} .. policy 1 below.

{ and } also works in titles and look very similar to read syntax of {{ and }}

          imagePullPolicy1: { { quote .Values.image.pullPolicy } }
          imagePullPolicy1: {{ quote .Values.image.pullPolicy }}

          imagePullPolicy2: { .Values.image.pullPolicy | quote }
          imagePullPolicy2: {{ .Values.image.pullPolicy | quote }}

this gets rendered as :

          imagePullPolicy1: { { quote .Values.image.pullPolicy } }
          imagePullPolicy1: "IfNotPresent"

          imagePullPolicy2: { .Values.image.pullPolicy | quote }
          imagePullPolicy2: "IfNotPresent"
helm install .\myhelm1\ --set replicaCount={1,2,3}  --name test5 --dry-run --debug | grep -vE 'debug]|NAME|REVIS|RELEA|ART:|OKS:|FEST:'

learn from other templates

There are nearly 300 superb Helm chart and template examples at the official Helm repository at https://github.com/helm/charts

You want to learn from the best: these people.

You will see that after just these 2 tutorials you are already able to understand more than 80% of all the template coding. ( But these 2 tutorials covered maybe 10 percent of the syntax ).

You now have 4 independent, different ways of learning charts and templates:

  • the official Helm reference docs
  • these 2 practical tutorials
  • 300 superb Helm chart examples
  • the fast hack method that you can use to cut-paste and speed learn those 3 sources via quick interactive exercises

Helm reference docs are low-level focussed on detail.

Look for structural chart design insights while looking at the Helm chart repository.

From https://github.com/helm/charts/blob/master/stable/lamp/templates/NOTES.txt

See how the lamp chart only displays certain notes help text when .Values.ingress.enabled

{{- if .Values.ingress.enabled }}

INGRESS:
      Please make sure that you have an ingress controller instance {{ if .Values.ingress.ssl }}and a lego instance
      {{- end -}} running
      and that you have configured the A Records of {{ template "lamp.domain" . }} and its
      subdomains to point to your ingress controllers ip address.
{{- else }}

Most other charts use this idea since charts are infinitely flexible: many features to enable or disable.

Another example use of displaying NOTES.txt based on what the user enabled:

From https://github.com/helm/charts/blob/master/stable/lamp/templates/NOTES.txt

1. You can now connect to the following services:

      {{- if not .Values.ingress.enabled }}
      export CHARTIP=$(kubectl get svc {{ template "lamp.fullname" . }} --output=jsonpath={.status.loadBalancer.ingress..ip})
      {{- end }}

      Main Site:
        {{- if .Values.ingress.enabled }}
        http{{ if .Values.ingress.ssl }}s{{ end }}://{{ template "lamp.domain" . }}
        {{- else }}
        http://$CHARTIP
        {{- end }}
      {{- if .Values.phpmyadmin.enabled }}

      PHPMyAdmin:
      {{- if .Values.ingress.enabled }}
        http{{ if .Values.ingress.ssl }}s{{ end }}://{{ .Values.phpmyadmin.subdomain }}.{{ template "lamp.domain" . }}
      {{- else }}
        http://$CHARTIP:{{ .Values.phpmyadmin.port }}
      {{- end }}
      {{- end }}

Another frequently used method is to warn users if a chart is set up incorrectly or insecurely.

From https://github.com/helm/charts/blob/master/stable/mongodb/templates/NOTES.txt

{{- if contains .Values.service.type "LoadBalancer" }}
{{- if not .Values.mongodbRootPassword }}
-------------------------------------------------------------------------------
 WARNING

    By specifying "service.type=LoadBalancer" and not specifying "mongodbRootPassword"
    you have most  likely exposed the MongoDB service externally without any
    authentication mechanism.

    For security reasons, we strongly suggest that you switch to "ClusterIP" or
    "NodePort". As alternative, you can also specify a valid password on the
    "mongodbRootPassword" parameter.

-------------------------------------------------------------------------------
{{- end }}
{{- end }}

Perfect example of how to handle .Values.service.type "NodePort" or "LoadBalancer" or "ClusterIP"

From https://github.com/helm/charts/blob/master/stable/mongodb/templates/NOTES.txt

To connect to your database from outside the cluster execute the following commands:

{{- if contains "NodePort" .Values.service.type }}

    export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
    export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "mongodb.fullname" . }})
    mongo --host $NODE_IP --port $NODE_PORT {{- if .Values.usePassword }} --authenticationDatabase admin -p $MONGODB_ROOT_PASSWORD{{- end }}

{{- else if contains "LoadBalancer" .Values.service.type }}

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "mongodb.fullname" . }}'

    export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "mongodb.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
    mongo --host $SERVICE_IP --port {{ .Values.service.nodePort }} {{- if .Values.usePassword }} --authenticationDatabase admin -p $MONGODB_ROOT_PASSWORD{{- end }}

{{- else if contains "ClusterIP" .Values.service.type }}

    kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "mongodb.fullname" . }} 27017:27017 &
    mongo --host 127.0.0.1 {{- if .Values.usePassword }} --authenticationDatabase admin -p $MONGODB_ROOT_PASSWORD{{- end }}

{{- end }}

These examples are from spending less than 3 minutes looking at some chart examples. You can easily spend a day there ( and it will be worth it ... if you make notes ).

how to use .Files.Get

At https://docs.helm.sh/chart_template_guide/ ... Accessing Files Inside Templates ... ( cannot link to that paragraph directly ) there are several examples of how to include files inside templates.

The Helm repo has 80 examples of how to use .Files.Get

https://github.com/helm/charts/search?utf8=%E2%9C%93&q=.Files.Get&type=

In the first 10 results I found 5 different uses of .Files.Get.

To learn more about Helm, visit https://github.com/helm/charts/tree/master/stable

More Resources

Running Microsoft Exchange Server with Alibaba Cloud ECS

This article covers setting up Exchange Server 2019 on Windows Server 2019 Datacenter edition image using an Alibaba Cloud ECS Instance.

0 0 0
Share on

Alibaba Clouder

2,599 posts | 763 followers

You may also like

Comments