TT Lab
Get started
Learn Learning paths Courses

Helm Deployment and Rollback Scenarios

Confirm the Order Values Merge In by Rendering

Continue in TT Lab

Goal

You build the habit of rendering to check the order in which values are merged instead of memorizing it. You attach a local subchart as a dependency, layer two value files and --set to see who wins, and go as far as blocking wrong values before deployment with a schema.

Why it matters

A production deployment usually has two or three layers of values files. The chart defaults, per-environment values, and the image tag that CI injects. If you get confused about which wins, staging values leak into production. There are two more traps here. Maps are merged, but lists are replaced wholesale, and values you give to a subchart are passed along only if you wrap them with the subchart name as the key.

Dependencies cause the same kind of problem. The version you write in Chart.yaml is a range, and what was actually picked is written in Chart.lock. If you do not commit this file, each person gets different dependencies, and from then on "it works on my machine" begins.

Environment

There is no internet, so you cannot fetch a chart repository. Instead, you create the subchart in a neighboring directory and point to it with file://. helm dependency update works normally this way. The working directory is /root/hs-val and the outputs go under /root/hs-val/out. Grading does not look at files as text but runs helm template itself and reads the result.

Steps

  1. Create the subchart cache and the parent platform, attach a file:// dependency, and lock it.
  2. In platform/values.yaml, send values down to the subchart under the cache key.
  3. Put in global.env and confirm that both charts read it together.
  4. Layer values/base.yaml and values/prod.yaml, render, and save to /root/hs-val/out/render.yaml.
  5. Confirm that lists are replaced and write it in /root/hs-val/out/list-note.txt.
  6. Turn off the subchart entirely with cache.enabled: false.
  7. Block an out-of-range value with values.schema.json and save the rejection output.
  8. Install into val-lab and save the result of helm get values.

Notes

Attach a local subchart as a dependency and lock it

Create two charts in /root/hs-val. The subchart is cache and the parent is platform. In platform/Chart.yaml, write the cache dependency with the file://../cache repository, add condition: cache.enabled, and then run helm dependency update.

There is no internet, so use file:// as the repository address. If you run helm dependency update <부모차트> (parent chart in the placeholder), the subchart is bundled as a package and comes in as platform/charts/cache-0.1.0.tgz, and the version that was picked is written in platform/Chart.lock. You have to commit this lock file to the repository for other people and CI to get the same thing. In CI, use helm dependency build, and use update, which re-resolves the range, only when you intend to.

Send values down to the subchart

At the end of platform/values.yaml, create a cache key and put enabled: true and replicaCount: 3 under it. Leave the parent's own replicaCount at the default of 1.

To give values to a subchart, you must wrap them with the subchart name as the key in the parent values. If you just write them at the top level, they merely become the parent chart's values. After editing, run helm template plat ./platform and check that the replicas of the two Deployments split into 3 and 1 respectively.

Only values under global are seen by all charts

Put global.env in platform/values.yaml, and create ConfigMap templates holding that value in both the parent and the subchart. The names are {{ .Release.Name }}-platform-env and {{ .Release.Name }}-cache-env respectively, and you put .Values.global.env in data.env.

A subchart cannot see the parent's top-level values, but it does see the values under global. There is one trap. Even if you edit the subchart templates, the package inside platform/charts/ is the old one, so you must run helm dependency update again for it to be reflected in the render. If data.env of the two ConfigMaps has the same value in the render result, it is a success.

Layer two value files and --set to see who wins

Create /root/hs-val/values/base.yaml and prod.yaml and write tier and image.tag differently in them. Create a {{ .Release.Name }}-settings ConfigMap template in the parent chart holding tier, tag, and envNames, and save the result rendered with -f base.yaml -f prod.yaml --set image.tag=ci-42 to /root/hs-val/out/render.yaml.

The precedence, from lowest, is the chart's values.yaml, the files given with -f (the one that came first → the later one), and then --set. Put tier, replicaCount, image.tag, and extraEnv in base.yaml, and tier, image.tag, and extraEnv in prod.yaml. Do not write replicaCount in prod. You will use what happens to a key that is absent from the later file again in step 8. The grader runs the same command again and compares it with your file.

Lists are not merged but replaced wholesale

Leave the extraEnv of the two value files from step 4 as they are, and check which side's list the envNames in the render result comes from. Write the rule you confirmed in the first line of /root/hs-val/out/list-note.txt as LIST_MERGE=replace, and add one or two sentences below it on why.

Maps are merged key by key, but for lists the later one overrides the earlier one wholesale. If you render with -f base.yaml -f prod.yaml, not one item from base remains. The accident where an extraEnv split per environment leaves only one comes from here. If you want to merge, you have to design it as a map, not a list.

If the condition is false, the subchart is not rendered

Put cache.enabled: false in prod.yaml, and compare the render with that value given against the render without it. The side that is turned off must have no subchart resources at all.

If the value that the condition in Chart.yaml points to is false, that subchart is not rendered at all. So even if that subchart's values are wrong, the deployment passes, and it shows up for the first time the moment you turn it on. You can tell whether a resource came from the subchart by the # Source: platform/charts/cache/ comment in the render result.

Block wrong values before deployment with a schema

Create /root/hs-val/platform/values.schema.json and restrict replicaCount to an integer from 1 to 5 inclusive. Then try to render with a value above the upper limit and save the rejected output to /root/hs-val/out/schema-reject.txt.

Helm checks the merged values with values.schema.json at the chart root. The purpose is to catch misspelled keys before deployment. There is one thing to be careful about. If you put a key that exists only in the environment file into required, it also blocks rendering without a values file, and the earlier steps break. The rejection output goes to standard error, so you must capture it with 2>&1 for it to remain in the file.

Check the values actually put into the deployed release

Install platform into the val-lab namespace under the name plat, giving -f base.yaml -f prod.yaml --set image.tag=ci-42 exactly as before. Then save helm get values as JSON to /root/hs-val/out/user-values.json.

helm get values shows only the values the user gave, and --all shows everything merged with the chart defaults. What you look at first in an incident investigation is the former. After saving, check three things. Whether image.tag is the --set value, whether tier is the value from the file given later, and whether replicaCount, which prod does not have, remains as the base value. The last one is the evidence of map merging.