TT Lab
Get started
Learn Learning paths Courses

Authoring and Shipping Helm Charts

Attaching Subcharts and Creating Order With Hooks

Continue in TT Lab

Goal

You assemble two independent charts as a parent and a subchart, and build by hand all four axes of dependency management: passing values, conditional activation, global values, and hooks.

Why it matters

When you build a platform chart, you inevitably meet the question "should this component go in the same chart or be split out?" Dependencies are the answer in between. The child remains an independent chart that can be installed on its own, and the parent pulls it in by declaration while overriding its values. There is only one rule here — what you write in the parent values under a key with the same name as the subchart becomes the top level of the child's .Values. Only values that must reach both the parent and the child go under global. And since this environment has no internet, the repository must be a file:// local path. This is not a limitation but a configuration that is common in practice too — it is exactly the method used when you keep several charts in one repository and reference them from each other. Finally, hooks are the only means of creating order inside a deployment, but hook resources are not owned by the release, so if you do not write a deletion policy they pile up on every deployment.

Steps

  1. Create a chart named cache in /root/helm/deps/cache and a chart to be the parent in /root/helm/deps/platform. Both charts must have Chart.yaml, values.yaml, and templates/. Set replicaCount in /root/helm/deps/cache/values.yaml to 1. Also create the output directory /root/helm/deps/out in advance.
  2. In the first entry of dependencies in /root/helm/deps/platform/Chart.yaml, write name: cache, repository: "file://../cache", a version equal to the version of the cache chart (for example 0.1.0), and condition: cache.enabled. There is no internet, so a remote repository URL does not work.
  3. Run helm dependency update /root/helm/deps/platform. /root/helm/deps/platform/Chart.lock must be created, the name of the first dependency in it must be cache, its digest must start with sha256:, and the cache package must be placed in /root/helm/deps/platform/charts/.
  4. Write cache.enabled: true and cache.replicaCount: 3 in /root/helm/deps/platform/values.yaml and render with helm template platform /root/helm/deps/platform > /root/helm/deps/out/rendered.yaml. The spec.replicas of the Deployment whose name contains cache must be 3. Be sure to leave replicaCount in /root/helm/deps/cache/values.yaml at 1 as it is — this step is for confirming that the parent overrides it.
  5. Save helm template platform /root/helm/deps/platform --set cache.enabled=false > /root/helm/deps/out/disabled.yaml. This file must not contain the string cache anywhere, and the parent chart's objects must remain (at least 1 object). Do not use the word cache in the parent chart's own resource names or content.
  6. Put global.environment: stage in /root/helm/deps/platform/values.yaml, and attach labhub.io/environment: {{ .Values.global.environment }} to the metadata.labels in the templates of both the parent and the subchart. In the re-rendered /root/helm/deps/out/rendered.yaml, there must be 2 or more labhub.io/environment: stage lines, and the object whose name contains cache must also have that label.
  7. Add one hook Job to /root/helm/deps/platform/templates/. Name it like {{ .Release.Name }}-db-migrate (do not put cache in the name), and attach the annotations helm.sh/hook: pre-install,pre-upgrade, helm.sh/hook-weight: "-5", and helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded. Save the rendering that includes the hook to /root/helm/deps/out/hooks.yaml (helm template also outputs hooks by default).
  8. Create /root/helm/deps/out/deps-report.json. It has four keys. object_count is the number of lines starting with kind: in /root/helm/deps/out/rendered.yaml, subcharts is ["cache"], lock_digest is the digest value of /root/helm/deps/platform/Chart.lock exactly as it is, and hooks is an array holding the names of the hook resources (at least 1). Also, one of the rendered Deployment names must contain the release name platform.

Notes

Prepare a subchart and a parent chart

Create a chart named cache in /root/helm/deps/cache and a chart to be the parent in /root/helm/deps/platform. Both charts must have Chart.yaml, values.yaml, and templates/. Set replicaCount in /root/helm/deps/cache/values.yaml to 1. Also create the output directory /root/helm/deps/out in advance.

You need two independent charts. The child chart must also have a self-contained structure (metadata, defaults, templates) to be packaged later.

Declare the dependency in the parent Chart.yaml

In the first entry of dependencies in /root/helm/deps/platform/Chart.yaml, write name: cache, repository: "file://../cache", a version equal to the version of the cache chart (for example 0.1.0), and condition: cache.enabled. There is no internet, so a remote repository URL does not work.

This environment has no internet. Instead of a remote repository URL, look for a way to use a path relative to the parent chart. You also need to write the field that makes it possible to turn it on and off.

Resolve the dependency and fill charts/

Run helm dependency update /root/helm/deps/platform. /root/helm/deps/platform/Chart.lock must be created, the name of the first dependency in it must be cache, its digest must start with sha256:, and the cache package must be placed in /root/helm/deps/platform/charts/.

When you resolve the dependency, a lock file is created and the package is placed in charts/. If the version you declared differs from the child chart's version, it fails here.

Override the subchart's values from the parent

Write cache.enabled: true and cache.replicaCount: 3 in /root/helm/deps/platform/values.yaml and render with helm template platform /root/helm/deps/platform > /root/helm/deps/out/rendered.yaml. The spec.replicas of the Deployment whose name contains cache must be 3. Be sure to leave replicaCount in /root/helm/deps/cache/values.yaml at 1 as it is — this step is for confirming that the parent overrides it.

Do not touch the child chart's defaults file. If you write a value in the parent values under a key with the same name as the subchart, it becomes the child's top-level value.

Turn off the subchart with condition

Save helm template platform /root/helm/deps/platform --set cache.enabled=false > /root/helm/deps/out/disabled.yaml. This file must not contain the string cache anywhere, and the parent chart's objects must remain (at least 1 object). Do not use the word cache in the parent chart's own resource names or content.

A condition turns off only the child chart. If the child's name still appears in the result after you turned it off, the parent template is creating that resource directly.

Pass a global value down to the subchart

Put global.environment: stage in /root/helm/deps/platform/values.yaml, and attach labhub.io/environment: {{ .Values.global.environment }} to the metadata.labels in the templates of both the parent and the subchart. In the re-rendered /root/helm/deps/out/rendered.yaml, there must be 2 or more labhub.io/environment: stage lines, and the object whose name contains cache must also have that label.

There is a separate place to put values that must reach both the parent and the child. Attach the same label in both templates and check with your own eyes that it is really passed.

Attach an install hook

Add one hook Job to /root/helm/deps/platform/templates/. Name it like {{ .Release.Name }}-db-migrate (do not put cache in the name), and attach the annotations helm.sh/hook: pre-install,pre-upgrade, helm.sh/hook-weight: "-5", and helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded. Save the rendering that includes the hook to /root/helm/deps/out/hooks.yaml (helm template also outputs hooks by default).

A hook is defined with three annotations. You must write when it runs, how the order works when there are several, and who cleans it up afterward.

Produce an umbrella rendering report

Create /root/helm/deps/out/deps-report.json. It has four keys. object_count is the number of lines starting with kind: in /root/helm/deps/out/rendered.yaml, subcharts is ["cache"], lock_digest is the digest value of /root/helm/deps/platform/Chart.lock exactly as it is, and hooks is an array holding the names of the hook resources (at least 1). Also, one of the rendered Deployment names must contain the release name platform.

Extract the numbers directly from the rendering result and the lock file and organize them as JSON. Do not write the object count and the digest by hand; read them from the files and put them in.