In a Helm chart, which built-in objects supply the app.kubernetes.io/instance, managed-by and version label values?
answer
- Two objects carry all four values
- One label names the install, not the chart
- One renders a fixed word every time
- App version, not chart version, and quoted
- Chart label rewrites an illegal character
basics
~10 sapp.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 sThe 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 linesmetadata:
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
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.
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.
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.
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