Helm / Intermediate: authoring and lifecycle contracts / Lesson 7
Helpers, names and stable selectors
Design named helper interfaces that reuse descriptive metadata without accidentally changing immutable workload identity or cross-release routing.
On this page
Lesson goals
- Namespace helper names and pass their contexts explicitly.
- Separate descriptive labels from selector identity.
- Review naming changes as lifecycle changes.
Make a helper an interface
Named templates are compiled in a shared naming space, including dependency templates. A generic helper called labels can collide with another chart. Prefix names with the chart and, when compatibility requires it, a helper interface version. A helper is more than a deduplication trick: document which context it expects and which text it returns. A helper receiving the entire root can use Release and Chart; a helper receiving a small dictionary can use only that dictionary. Explicit inputs make reuse easier to reason about and prevent hidden dependence on the caller’s current dot.
Return text for composition
The include function returns rendered helper text, allowing a pipeline to indent it at the destination. By contrast, the template action inserts output directly and is less convenient for contextual indentation. The first fragment defines two stable selector labels and includes them under a selector. It assumes an application chart named catalog and an explicit release name. The helper deliberately excludes package version and application version. Those fields describe a deployment but should not redefine which existing Pods belong to a Deployment when a package version changes.
{{- define "catalog.v1.selectorLabels" -}}
app.kubernetes.io/name: catalog
app.kubernetes.io/instance: {{ .Release.Name | quote }}
{{- end -}}
selector:
matchLabels:
{{- include "catalog.v1.selectorLabels" . | nindent 4 }}
The definition would normally live in _helpers.tpl and the call in a workload template. This combined teaching fragment is not a complete manifest.
Distinguish descriptive labels
Descriptive metadata can include chart version, application version, team and component. Selector labels serve a narrower identity contract and must match Pod template labels. For an apps/v1 Deployment, the selector is immutable after creation, so changing a version-bearing selector can make a normal-looking upgrade fail. Service selectors have their own mutable routing consequences and can accidentally include another release if instance identity is omitted. Keep one small selector helper and a separate broader labels helper. User-provided extra labels should not silently override protected identity keys in either location.
Review names as object identity
Changing a fullname helper can create a new object rather than rename an existing object in place. References from Services, mounts, roles and hooks must change coherently, and persistent storage may have additional implications. Truncating long names is not sufficient by itself: two distinct inputs can truncate to the same prefix. Respect the receiving resource’s naming limits and design collision resistance for the intended namespace. The second example compares planned identities as tuples. It illustrates why a change in name or namespace must be reviewed as ownership and lifecycle work, not just visual consistency.
before = ("v1/ConfigMap", "lab", "preview-catalog-settings")
after = ("v1/ConfigMap", "lab", "catalog-settings")
print(before == after)
print("identity changed" if before != after else "same identity")
False
identity changed
A different identity is established; the program does not determine what a real release operation would delete or retain.
Review helper contracts across versions
A helper review should cover a short and long release name, two release instances, custom descriptive labels and a chart version change. Assert that selectors remain stable for the same release and that all required Pod labels remain present. For a library chart, treat helper behavior as a public interface used by several consumers, so a formatting or context change can be breaking even without a rendered resource of its own. Keep expected output small and explain why each field exists. Reusing a helper is valuable only when it preserves the intended resource semantics.
Common errors and fixes
An upgrade changes an immutable Deployment selector
- Why it happens
- The selector helper included a changing chart version.
- How to fix it
- Plan a supported migration and separate stable selector keys from descriptive version labels.
- Prevent it next time
- Compare selectors across package versions before release.
A dependency changes another chart’s labels helper
- Why it happens
- Both charts defined the same global helper name.
- How to fix it
- Use chart-qualified helper names and review included dependency definitions.
- Prevent it next time
- Treat named template names as a shared namespace.
A Service selects two releases
- Why it happens
- The selector omitted release-instance identity.
- How to fix it
- Include stable instance labels consistently on selector and Pod template.
- Prevent it next time
- Review two-release fixtures rather than one isolated instance.
Check your understanding
1. Should helm.sh/chart be part of the Deployment selector? Explain the lifecycle consequence.
Show worked solution
Usually it belongs in descriptive labels because it changes when the chart version changes. A Deployment selector must remain stable across in-place upgrades, and apps/v1 treats it as immutable. Keep application and release identity in the selector, repeat those labels on the Pod template and carry chart version separately for querying and review.
2. A helper is called with dict "name" "catalog". Can it safely read .Release.Name?
Show worked solution
No: its context contains the supplied dictionary, not automatically the original root. Pass the required release name explicitly or include a root key in a documented helper interface. Inside that helper, $ starts from the supplied context as well. A clear small input contract is preferable to a helper that accidentally depends on whichever caller happened to pass the full root.
Key takeaways
- Helpers need unique names, explicit contexts and stable output contracts.
- Resource identity and selectors deserve lifecycle review whenever helper behavior changes.