# Cheat sheet — Helm

Dense revision sheet. `helm` commands + interview one-liners at the bottom. (Helm **v3.14.4**.)

---

## The triad
- **Chart** = the package (templates + default values + `Chart.yaml`).
- **Release** = one installed instance of a chart (named, with revision history).
- **Values** = the config fed to templates (`.Values`), layered from defaults → `-f` → `--set`.

## Chart layout
```
mychart/
  Chart.yaml          # apiVersion v2, name, version, appVersion, type, dependencies?
  values.yaml         # default values
  templates/          # rendered through the Go template engine
    _helpers.tpl      # partials (underscore = not a manifest)   ← repo: split _name/_label/_env
    deployment.yaml
    NOTES.txt         # printed after install (repo: platform charts only)
  charts/             # fetched subchart dependencies
  .helmignore
```

## Template engine essentials
| Piece | Example |
|---|---|
| Value | `{{ .Values.grpcPort }}` |
| Built-in objects | `.Release.Name/.Namespace`, `.Chart.Name`, `.Capabilities`, `.Files` |
| Pipeline | `{{ .Values.x | default "y" | quote }}` |
| Whitespace trim | `{{- ... -}}` |
| Indent a block | `{{ toYaml .Values.resources | nindent 4 }}` |
| Named template | `{{ define "util.labels" }}…{{ end }}` → `{{ include "util.labels" . | nindent 4 }}` |
| Render a string as template | `{{ tpl (.Files.Get "x.tpl") . }}` |
| Validate | `{{ required "msg" .Values.x }}` (repo uses `fail` instead) |
| Capability switch | `{{ if .Capabilities.APIVersions.Has "keda.sh/v1alpha1" }}` |

**`include` vs `template`:** `include` returns a string you can pipe (`| nindent`); `template`
can't be piped. Prefer `include`.

## Values precedence (low → high)
subchart `values.yaml` → parent `values.yaml` → `-f file1 -f file2` (last wins) → `--set` (wins all).
- **Global values:** `.Values.global.*` — the only values shared into subcharts.

## Hooks (lifecycle)
`helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade,pre-delete,…`
- Ordered by `helm.sh/hook-weight` (low → high). Cleaned by `helm.sh/hook-delete-policy`
  (`before-hook-creation`, `hook-succeeded`, `hook-failed`).

## helm command kit
```
helm template NAME CHART -f vals.yaml        # render locally, no cluster  (= skaffold render)
helm install  NAME CHART -n NS               # create a release
helm upgrade  NAME CHART --install -n NS      # upgrade or install (idempotent) (= skaffold run)
helm upgrade  ... --atomic --wait            # auto-rollback on failure
helm list -n NS                              # releases
helm history NAME -n NS                       # revisions of a release
helm rollback NAME REV -n NS                  # revert to a revision
helm get manifest / values NAME -n NS         # what's actually deployed
helm lint CHART                               # static checks
helm dependency update CHART                  # fetch subcharts to charts/
```

---

## This repo (anchors)
| Thing | Where |
|---|---|
| Library chart (`type: library`) | `deployments/helm/libs/util/` |
| Service chart (`type: application`, no deps) | `backend/bob/Chart.yaml` |
| Entry macro (emits all objects) | `libs/util/templates/_app.tpl:7` (`util.app`) |
| fullname / labels helpers | `_name.tpl:14` / `_label.tpl:5` (no `_helpers.tpl`) |
| Shared global values | `backend/values.yaml` (all `global:`) |
| Per-cell values | `backend/<svc>/{env}-{org}-values.yaml` |
| Copy-not-dependency | `deployments/helm/update_deps.sh:5-19` |
| Real dep (exception) | `backend/zeus/Chart.yaml:26-30` (sftpgo) |
| Migration hook (local-only!) | `libs/util/templates/_hook_migration.tpl:1-14` |
| Skaffold releases + valuesFiles | `skaffold.backend.yaml:5-76`, `backend/bob/skaffold.yaml:8-38` |
| SOPS → Secret (`.AsSecrets`, no deploy-time decrypt) | `libs/util/templates/_secret.tpl:31-38` |
| Helm version | `deployments/versions/helm` (`v3.14.4`) |

## Interview one-liners
- **Chart vs release?** *"A chart is the package; a release is one installed instance of it,
  with a name and revision history. Same chart, two releases = two independent installs."*
- **How do values combine?** *"Defaults in values.yaml, overridden by `-f` files (last wins),
  overridden by `--set`. Only `global` reaches subcharts."*
- **`include` vs `template`?** *"`include` returns a string you can pipe to `nindent`;
  `template` can't be piped. Use `include`."*
- **What's a library chart?** *"`type: library` — it only defines named templates, renders
  nothing itself. We keep all workload templates in one (`libs/util`)."*
- **Subchart vs our copy model?** *"Normally shared templates are a subchart dependency; this
  repo instead *copies* `libs/util` into each chart via `update_deps.sh`."*
- **What's a hook?** *"A resource annotated to run at a lifecycle phase — our DB-migration Job
  is a `pre-install/pre-upgrade` hook, weight -47, and it's gated to local."*
- **`helm template` vs `install`?** *"`template` renders manifests locally (that's
  `skaffold render`); `upgrade --install` actually applies them (that's `skaffold run`)."*
- **How are secrets handled?** *"SOPS-encrypted values are packed into a Secret via
  `.AsSecrets` and decrypted **in-app** at runtime — we don't decrypt at deploy time."*
