Authoring and Shipping Helm Charts
Put Standard Labels in One Place with a Library Chart
Goal
You create a type: library chart so that two application charts share the same Deployment template and label rules, and check by rendering what wins when the parent redefines the same name.
Why it matters
When charts multiply, the first thing that scatters is the standard labels. Among charts from the same company, some attach app.kubernetes.io/instance and others attach release. Monitoring dashboards and network policies pick targets by labels, so this inconsistency later comes back as "why are metrics not being picked up for just this Pod?" A library chart is a device that nails this rule down in one place. It cannot be installed or rendered on its own and holds only define blocks, so the very name of the type shows that it exists only for others to use. There are two more things you learn here — how to re-run a string inside values as a template with tpl, and the fact that template names are a single name space across the whole chart, so if names overlap they are silently overwritten.
Steps
- Create a chart with
type: library(nameplatform-lib, version0.1.0) in/root/hc-library/platform-lib. In/root/hc-library/platform-lib/templates/_helpers.tpl, define two withdefine:platform-lib.fullnameandplatform-lib.labels. The labels output four lines:app.kubernetes.io/name,app.kubernetes.io/instance,app.kubernetes.io/managed-by, andplatform.labhub.io/tier. Under templates, put only files that start with an underscore. - Run
helm install liblab /root/hc-library/platform-lib --dry-runandhelm template liblab /root/hc-library/platform-libin turn and capture both outputs (including errors) in/root/hc-library/out/library-error.txt. The answer to this step is in what words Helm uses to refuse. - Define
platform-lib.deploymentin/root/hc-library/platform-lib/templates/_deployment.tpl. This template emits a Deployment whose name isplatform-lib.fullname, and whosemetadata.labelsare made by plugging inplatform-lib.labelswithnindent 4.spec.replicasis.Values.replicas(default 1), the container name is.Chart.Name, and the image is.Values.imagewrapped in quotes. The selector and Pod labels use only the two lines name and instance. - Create a
/root/hc-library/billingapplication chart (version0.1.0, appVersion"1.4.2"), declareplatform-lib0.1.0as a dependency from thefile://../platform-librepository, and resolve it.values.yamlholds four values:replicas: 1,image: "registry.local/billing:1.4.2",tier: core, andnote: "{{ .Release.Name }} in {{ .Release.Namespace }}", andtemplates/deployment.yamlholds only a single line that includesplatform-lib.deployment. Save the result ofhelm template shop /root/hc-library/billingto/root/hc-library/out/billing.yaml. - Create a
/root/hc-library/reportingchart (version0.1.0, appVersion"0.9.0") in the same way, but setreplicas: 3,image: "registry.local/reporting:0.9.0",tier: batch, andnote: "{{ .Chart.Name }} {{ .Chart.Version }}", and resolve the dependency. Save the result ofhelm template insight /root/hc-library/reportingto/root/hc-library/out/reporting.yaml. Check that the list of label keys is the same in the two rendered results and only the values differ. - Add
platform-lib.configmapto the library (/root/hc-library/platform-lib/templates/_configmap.tpl). The name is<fullname>-note, anddata.noterenders.Values.noteonce more withtpland wraps it in quotes. Addtemplates/configmap.yaml(a single include line) to both charts. Thenotevalues were already put into values.yaml in steps 4 and 5 — leave them as they are, braces included. Since you changed the library, both charts must fetch the dependency again. Save the two rendered files again. - In
/root/hc-library/billing/templates/_override.tpl, redefineplatform-lib.deploymentwith the same name. The content is the same as the library's, but add one line,platform.labhub.io/overridden-by: billing, tometadata.annotations. Render the two charts again and save them, and check that only billing gets that annotation. - Organize the results of this lab in
/root/hc-library/out/report.json. There are eight keys:library(the library chart's name),type(the chart type),installable(a boolean),consumers(an array of consuming chart names),billing_replicasandreporting_replicas(the actual replicas numbers of each render),shared_label_keys(the number of label keys the library helper produces), andoverride_winner(the name of the chart that won by redefining the same name).
Notes
- In the templates of a
type: librarychart, put only files that start with an underscore - The dependency
repository: "file://../<디렉터리>"(with the directory in the placeholder) works in this Pod (it is a different place fromfile://in repository registration) helm dependency updatetakes the library at that moment as a tgz — if you changed the library, fetch it again- Common mistake: running
helm installon a library and thinking the chart is broken - Common mistake: not prefixing define names with the chart name, so they silently collide with another chart's definitions
- Official documentation: https://helm.sh/docs/topics/library_charts/ · https://helm.sh/docs/chart_template_guide/named_templates/
Create a chart that renders nothing
Create a chart with type: library (name platform-lib, version 0.1.0) in /root/hc-library/platform-lib. In /root/hc-library/platform-lib/templates/_helpers.tpl, define two with define: platform-lib.fullname and platform-lib.labels. The labels output four lines: app.kubernetes.io/name, app.kubernetes.io/instance, app.kubernetes.io/managed-by, and platform.labhub.io/tier. Under templates, put only files that start with an underscore.
A library chart has no templates that get rendered. Helm treats files that start with _ as "pieces that produce no output," so all the content goes into define blocks inside _*.tpl. The tier may have no value, so apply default and wrap it with quote.
Try installing the library chart
Run helm install liblab /root/hc-library/platform-lib --dry-run and helm template liblab /root/hc-library/platform-lib in turn and capture both outputs (including errors) in /root/hc-library/out/library-error.txt. The answer to this step is in what words Helm uses to refuse.
Both commands fail. Errors go to standard error, so you have to capture them with 2>&1 for them to land in the file. Write the second command with appending (>>) so it does not erase the first output. Think about why the installation is blocked — there is nothing in this chart to render.
Put a whole Deployment into the library
Define platform-lib.deployment in /root/hc-library/platform-lib/templates/_deployment.tpl. This template emits a Deployment whose name is platform-lib.fullname, and whose metadata.labels are made by plugging in platform-lib.labels with nindent 4. spec.replicas is .Values.replicas (default 1), the container name is .Chart.Name, and the image is .Values.image wrapped in quotes. The selector and Pod labels use only the two lines name and instance.
include brings in the result of another define as a string, so you can apply indentation with a pipe. nindent 4 puts a newline first and then indents by four spaces — it suits use on the line right under labels:. The grader puts this definition into a temporary chart and renders it directly.
An application chart takes the library as a dependency
Create a /root/hc-library/billing application chart (version 0.1.0, appVersion "1.4.2"), declare platform-lib 0.1.0 as a dependency from the file://../platform-lib repository, and resolve it. values.yaml holds four values: replicas: 1, image: "registry.local/billing:1.4.2", tier: core, and note: "{{ .Release.Name }} in {{ .Release.Namespace }}", and templates/deployment.yaml holds only a single line that includes platform-lib.deployment. Save the result of helm template shop /root/hc-library/billing to /root/hc-library/out/billing.yaml.
A library cannot be installed but can be attached as a dependency. file:// does not work for repository registration, but it works as a dependency repository. When you resolve it, Chart.lock and charts/platform-lib-0.1.0.tgz are created. If you give the release name shop, the object name becomes shop-billing.
A second chart uses the same template with different values
Create a /root/hc-library/reporting chart (version 0.1.0, appVersion "0.9.0") in the same way, but set replicas: 3, image: "registry.local/reporting:0.9.0", tier: batch, and note: "{{ .Chart.Name }} {{ .Chart.Version }}", and resolve the dependency. Save the result of helm template insight /root/hc-library/reporting to /root/hc-library/out/reporting.yaml. Check that the list of label keys is the same in the two rendered results and only the values differ.
This is exactly where the library earns its value — the rule for attaching labels is in only one place, and the only thing that differs per chart is values. To extract and compare just the label keys, run yq '.metadata.labels | keys' on the two files.
Re-render a template string held in values
Add platform-lib.configmap to the library (/root/hc-library/platform-lib/templates/_configmap.tpl). The name is <fullname>-note, and data.note renders .Values.note once more with tpl and wraps it in quotes. Add templates/configmap.yaml (a single include line) to both charts. The note values were already put into values.yaml in steps 4 and 5 — leave them as they are, braces included. Since you changed the library, both charts must fetch the dependency again. Save the two rendered files again.
tpl <문자열> <컨텍스트> (string and context in the placeholders) interprets the string as a template on the spot. The braces written in values are just characters, so if they do not go through this function, they are printed as they are. helm dependency update takes the library at that moment as a tgz and puts it in charts/ — if you do not fetch it again after changing the library, the old copy keeps being used.
What wins when the parent redefines the same name
In /root/hc-library/billing/templates/_override.tpl, redefine platform-lib.deployment with the same name. The content is the same as the library's, but add one line, platform.labhub.io/overridden-by: billing, to metadata.annotations. Render the two charts again and save them, and check that only billing gets that annotation.
Helm's template names use a single name space across the whole chart. If there are two with the same name, the one read later wins, and the parent chart's templates are read later than the subchart's. That is why the convention of prefixing names with the chart name came about — it is to prevent accidental collisions.
Write down in numbers what the library removed
Organize the results of this lab in /root/hc-library/out/report.json. There are eight keys: library (the library chart's name), type (the chart type), installable (a boolean), consumers (an array of consuming chart names), billing_replicas and reporting_replicas (the actual replicas numbers of each render), shared_label_keys (the number of label keys the library helper produces), and override_winner (the name of the chart that won by redefining the same name).
Do not make up the numbers; read them from the render results — you can extract them like yq '. | select(.kind=="Deployment") | .spec.replicas' out/billing.yaml. installable must be a boolean without quotes.