# Helm

:bulb:[Getting started](https://helm.sh/docs/chart_template_guide/getting_started/)

## Structure

```
mychart/
  Chart.yaml    
  values.yaml
  charts/
  templates/
  ...
```

## Useful commands

* helm **install** full-coral ./mychart
  * helm install RELEASE\_NAME PATH\_TO\_CHART
* helm **get manifest** full-coral
* helm **uninstall** full-coral
* helm **install --debug --dry-run** full-coral ./mychart
* helm **dependencies build**; helm **template** ./ -f values.yaml
  * you can not create template of particular yaml file, only all

## Built-in objects

* Release
  * {{ .Release.Name }}
* Values
* Chart
* Files
* Capabilities
* Template

## Values files

* 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`)

## Function

`functionName arg1 arg2...`

For example

```
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ quote .Values.favorite.drink }}
  food: {{ quote .Values.favorite.food }}
```

## Pipeline

Passing a value through 1..N functions (.Values.favorite.food | upper | quote)

```
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
```

### Useful function `default`&#x20;

* `drink: {{ .Values.favorite.drink | default "tea" | quote }}`
* the `default` command is perfect for computed values, which cannot be declared inside `values.yaml`
  * ```yaml
    drink: {{ .Values.favorite.drink | default (printf "%s-tea" (include "fullname" .)) }}
    ```

### Useful function lookup

The `lookup` function can be used to *look up* resources in a running cluster. The synopsis of the lookup function is `lookup apiVersion, kind, namespace, name -> resource or resource list`.

| Behavior                               | Lookup function                            |
| -------------------------------------- | ------------------------------------------ |
| `kubectl get pod mypod -n mynamespace` | `lookup "v1" "Pod" "mynamespace" "mypod"`  |
| `kubectl get pods -n mynamespace`      | `lookup "v1" "Pod" "mynamespace" ""`       |
| `kubectl get pods --all-namespaces`    | `lookup "v1" "Pod" "" ""`                  |
| `kubectl get namespace mynamespace`    | `lookup "v1" "Namespace" "" "mynamespace"` |
| `kubectl get namespaces`               | `lookup "v1" "Namespace" "" ""`            |

## Flow control

Helm's template language provides the following control structures:

### `if`/`else` for creating conditional blocks

```
{{ if PIPELINE }}
  # Do something
{{ else if OTHER PIPELINE }}
  # Do something else
{{ else }}
  # Default case
{{ end }}
```

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`)

Whitespaces may be tricky while rendering a temple

```
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 }}
```

you may sometimes find it useful to use the `indent` function (`{{ indent 2 "mug:true" }}`)

### `with` to specify a scope

```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 }}
```

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 using `.`. This, for example, will fail:

```yaml
  {{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  release: {{ .Release.Name }}
  {{- end }}
```

* `range`, which provides a "for each"-style loop

## Named templates

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*.

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.

* `define` declares a new named template inside of your template
* `template` imports a named template

```yaml
{{- define "mychart.labels" }}     // declare using "define"
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  {{- template "mychart.labels" }}    // use with a "template"
data:
  myvalue: "Hello World"
```

```
result looks like
apiVersion: v1
kind: ConfigMap
metadata:
  name: running-panda-configmap
  labels:
    generator: helm
    date: 2016-11-02
data:
  myvalue: "Hello World"
```

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 }}
```

* `block` declares a special kind of fillable template area

## Variables

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {{- $relname := .Release.Name -}}
  release: {{ $relname }}
```

## 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 template --debug` will test rendering chart templates locally.
* `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: v2
# some: problem section
# {{ .Values.foo | quote }}
```

The above will be rendered and returned with the comments intact:

```yaml
apiVersion: v2
# some: problem section
#  "bar"
```

This provides a quick way of viewing the generated content without YAML parse errors blocking.

[<br>](https://helm.sh/docs/chart_template_guide/helm_ignore_file/)
