skip to content

In a Helm chart, which built-in objects supply the app.kubernetes.io/instance, managed-by and version label values?

level: juniorimportance: should knowfreq 55%

answer

  1. Two objects carry all four values
  2. One label names the install, not the chart
  3. One renders a fixed word every time
  4. App version, not chart version, and quoted
  5. Chart label rewrites an illegal character

basics

~10 s

app.kubernetes.io/instance comes from .Release.Name, managed-by from .Release.Service (which always renders Helm), and version from .Chart.AppVersion. The separate helm.sh/chart label is built from .Chart.Name and .Chart.Version.

solid answer

~40 s

The chart, not Helm, emits these values, and each one has a specific built-in behind it. `app.kubernetes.io/instance: {{ .Release.Name }}` distinguishes two installs of the same chart. `app.kubernetes.io/managed-by: {{ .Release.Service }}` renders the literal string `Helm`. `app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}` carries the *application's* version and is normally wrapped in an `if`, because `appVersion` is optional in `Chart.yaml`; the `quote` matters because an unquoted `appVersion: 1.20` is read as a number and would render as `1.2`. `app.kubernetes.io/name` comes from the chart name, overridable by a values key such as `nameOverride`. Separately, `helm.sh/chart` is `printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-"` - SemVer build metadata uses `+`, which is not legal in a label value.

code

yaml · 9 lines
yaml
metadata:
  labels:
    helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
    app.kubernetes.io/name: {{ .Chart.Name }}
    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
    {{- if .Chart.AppVersion }}
    app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
    {{- end }}

go deeper

for a junior

Memorise the mapping: instance is the release name, managed-by is the render service, version is the app version, and the chart label is name plus chart version. Be ready to write the block from memory in an editor.

for a middle

Be ready to explain why each pipe stage in the helm.sh/chart value exists, why the version label is guarded and quoted, and what breaks when two releases of one chart share an instance label.

for a senior

An interviewer expects you to connect labels to operations: which label answers 'which release owns this object', which one answers 'what version is running', and how you audit a namespace where charts emitted them inconsistently.

for a principal

Own the standard. Decide which metadata every chart in the estate must emit, whether that is enforced by a shared helper or a merge check, and what your dashboards and query tooling depend on before you let a team drop a label.

## Who emits what There are two sources of metadata on a Helm-managed object and candidates routinely conflate them. Helm itself stamps ownership metadata on every resource it manages, which includes a `managed-by` label naming Helm. Everything else - the `app.kubernetes.io/name`, `/instance`, `/version` set and the `helm.sh/chart` label - is emitted by the chart's own templates. If the author does not write them, they do not appear. So the interview question is really: for each label a chart is expected to emit, which built-in object holds the value? ## The four values **`app.kubernetes.io/instance` <- `.Release.Name`.** This is the one that makes the label set per-install rather than per-chart. Install the same chart twice into a namespace as `fraud-a` and `fraud-b` and the two sets of objects differ by exactly this label. Using `.Chart.Name` here instead is the classic beginner error: both releases then carry identical labels, and any selector built on them matches the other release's Pods. **`app.kubernetes.io/managed-by` <- `.Release.Service`.** `.Release.Service` is documented as "the service that is rendering the present template", and in practice it always renders the literal string `Helm`. The word *service* here has nothing to do with a Kubernetes Service object - it means the tool doing the render. **`app.kubernetes.io/version` <- `.Chart.AppVersion`.** Note *App*: this is the `appVersion` field of `Chart.yaml`, the version of the software being shipped, not the chart's own `version`. Two details matter. First, `appVersion` is optional, so the emitted block is normally guarded: ```yaml {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} ``` Without the guard you emit a key with an empty value. Second, the `quote` is not decoration. `Chart.yaml` is YAML, so `appVersion: 1.20` unquoted is parsed as the number 1.2 and renders as `1.2`. Quote it in `Chart.yaml` and pipe it through `quote` in the template. **`app.kubernetes.io/name` <- the chart name**, normally through a small named template that lets a values key such as `nameOverride` replace it and truncates the result. This is the label most often carried into a selector, which is why it must stay stable for the life of a release. ## `helm.sh/chart` is different `helm.sh/chart` is Helm's own namespaced label and it identifies the chart *artefact*, not the app: ``` {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} ``` Every pipe stage earns its place. `.Chart.Version` is a SemVer string and SemVer allows build metadata after a `+` (`2.14.3+build.17`), but a label *value* may not contain `+`, so it is rewritten to `_`. A label value is capped at 63 characters, hence `trunc 63`; truncation can leave a trailing `-`, which is also illegal at the end of a label value, hence `trimSuffix "-"`. Skipping those pipes gives you a chart that installs fine for months and then fails validation the first time someone publishes a build-metadata version or a long chart name. ## Where the values land The full set normally goes on every rendered object's `metadata.labels` and on the Pod template's labels. A Deployment's `spec.selector.matchLabels`, however, takes only the stable subset - `name` and `instance` - because `helm.sh/chart` and `app.kubernetes.io/version` change whenever a version is bumped, and a selector cannot change after install. ## What good looks like A good answer names the built-in for each label without hesitating, distinguishes `.Release.Name` from `.Chart.Name`, distinguishes `.Chart.Version` from `.Chart.AppVersion`, and knows that `.Release.Service` is a fixed string rather than something the caller sets. A very good answer adds that these are chart-authored: rendering the chart with `helm template` shows them, and a chart that omits them produces objects nobody can query by application or by release.

  • Why does the helm.sh/chart label pipe the chart version through replace "+" "_" and trunc 63?
    Because a Kubernetes label value has a stricter alphabet than a SemVer string. SemVer allows build metadata after a plus sign, but `+` is not legal in a label value, so it is rewritten to an underscore. Values are also capped at 63 characters, so the result is truncated, and `trimSuffix "-"` removes a trailing dash truncation may leave behind, which would also be rejected.
  • What happens if Chart.yaml has no appVersion and the template emits the version label unconditionally?
    `.Chart.AppVersion` renders as an empty string, so you emit `app.kubernetes.io/version: ""`. An empty label value is legal but useless - every object claims an empty version and queries filtering on it match nothing meaningful. That is why the emitted block is wrapped in `{{- if .Chart.AppVersion }}`, and why an unquoted numeric `appVersion` in `Chart.yaml` is a separate trap: YAML reads `1.20` as a number and the label renders `1.2`.
  • Does Helm add any of these labels by itself if the chart omits them?
    Helm writes its own ownership metadata onto resources it manages, which includes a managed-by label naming Helm, but it does not synthesise the `app.kubernetes.io/name`, `/instance` or `/version` labels or the `helm.sh/chart` label. Those come from the chart's templates. Render the chart with `helm template` and whatever you do not see there will not exist in the cluster.

saying these in an interview costs you the question

  • Uses .Chart.Name for the instance label
  • Thinks .Release.Service names a Kubernetes Service
  • Puts the chart version in app.kubernetes.io/version
  • Emits appVersion unquoted so 1.20 becomes 1.2
  • Assumes Helm emits the whole app.kubernetes.io set
  • Ignores the 63-character label value limit

context