skip to content

How does a checksum/config pod annotation in a Helm chart restart Pods when a ConfigMap changes?

level: middleimportance: must knowfreq 66%

answer

  1. The controller only watches one part of the spec
  2. Put a fingerprint where the controller looks
  3. Render, then hash, then annotate
  4. The key name is convention, not machinery
  5. Object metadata is the wrong home for it

basics

~20 s

The chart hashes its rendered ConfigMap template and writes the hash into the Pod template's annotations. When the config changes the hash changes, the Pod template changes, and the workload controller performs a normal rolling update. Helm itself never reads the annotation.

solid answer

~50 s

Updating a ConfigMap does not by itself restart anything - config injected as environment variables is read once at start-up, so a workload keeps running the old values. The chart fixes that by making the config visible *in the Pod template*: it renders the ConfigMap template, hashes the result, and puts the hash in `spec.template.metadata.annotations` under a conventional key such as `checksum/config`. The canonical form is `{{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}`, where `.Template.BasePath` is the chart's templates path so the argument names that template. Change a value, the render changes, the hash changes, the Pod template changes, and a rolling update follows. Two things matter: the annotation must be on the Pod template rather than the object's own metadata, and the key is a convention - Helm does not interpret it.

code

yaml · 12 lines
yaml
spec:
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
    spec:
      containers:
        - name: scoring
          envFrom:
            - configMapRef:
                name: {{ .Release.Name }}-scoring

go deeper

for a junior

Know that a config change alone does not restart anything, and that the chart adds a hash of the config to the Pod's annotations so a change is visible. Be able to point at the right place in a Deployment.

for a middle

Be ready to write the pipeline from memory and explain each part - why include rather than template, what BasePath gives you, and why the annotation belongs on the Pod template.

for a senior

Expect the failure modes: an annotation on the wrong metadata block, content written by another controller that the hash never sees, and hashing too broadly so unrelated chart edits roll production workloads.

for a principal

Decide the estate-wide convention: which objects get a checksum annotation, whether charts hash rendered files or values subtrees, and where config reload should be the application's job rather than a restart.

## The problem A chart renders a ConfigMap and a Deployment that consumes it. On upgrade the ConfigMap is updated in place and the Deployment's own spec is byte-identical to before, so the workload controller sees no reason to do anything - the running Pods keep serving the values they read when they started. Config delivered as environment variables is read once at process start and never re-read; config delivered as a mounted file may eventually appear on disk but only helps if the application watches the file and reloads. From the chart author's point of view, none of that is something a chart can rely on. ## The mechanism A workload controller rolls Pods when the **Pod template** changes. So the chart makes the config part of the Pod template - not the config itself, which would be enormous and would leak, but a hash of it: ```yaml spec: template: metadata: annotations: checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} ``` Read it inside out. `$.Template.BasePath` is a built-in holding the chart's templates path, for example `scoring-chart/templates`; `print` concatenates it with `/configmap.yaml` to form the *name* of that template. `include` renders that template with the current context and returns its output as a string - this is why `include` is used rather than `template`, which writes directly to the output and cannot be piped. `sha256sum` hashes the string. The result is a stable hex digest that changes if and only if the rendered ConfigMap changes. Now every `helm upgrade` recomputes the hash. Same config, same digest, identical Pod template, no rollout. Different config, different digest, changed Pod template, ordinary rolling update with the workload's existing surge and unavailability settings. The rollout is the controller's normal behaviour, not something Helm does. ## Three details that get people **It must be on the Pod template.** `spec.template.metadata.annotations`, not the Deployment's top-level `metadata.annotations`. An annotation on the object itself is metadata about the Deployment and changing it triggers nothing. This is the single most common implementation bug, and it is invisible until someone changes config and wonders why nothing restarted. **Helm does not read the key.** `checksum/config` is a convention that spread from the Helm documentation, not a reserved name. You could call it `config-hash/scoring` and it would work identically, because the mechanism is "the Pod template changed", not "Helm noticed an annotation". Candidates who claim Helm restarts the Pods have the causality backwards. **Watch where the annotations block is emitted.** Charts commonly wrap the Pod template's `annotations:` key in a conditional over a values key that lets callers add their own annotations. If you nest the checksum inside that conditional, the checksum disappears for every caller who sets no annotations of their own - which is most of them. Emit `annotations:` unconditionally when the chart itself always has one to write. ## Choosing what to hash Hashing the whole rendered template file is the documented default and it is the safest starting point, but it is broad: the file includes the ConfigMap's own metadata, and that metadata carries version-bearing labels, so the digest moves whenever the chart version moves even if no config value changed. The narrower alternative hashes only the values subtree that feeds the config: ```yaml checksum/config: {{ toYaml .Values.scoring.config | sha256sum }} ``` That rolls Pods exactly when the configuration a user set changes. The trade is that it misses config the template computes from something other than that subtree. Pick one deliberately and say which in the chart's documentation. A rendered Secret gets the same treatment under a second annotation. Hash it - never inline the value. The annotation is readable by anyone who can read the Pod, and a hash is one-way while a copied value is not. ## What good looks like A good answer explains that the rollout comes from the Pod template changing, writes the `include`/`sha256sum` pipeline correctly, and puts it in the right place. A strong answer adds that the key name is arbitrary, that hashing the whole rendered file couples the rollout to chart-version bumps, and that a Secret needs the same annotation with the same hash-don't-inline discipline.

  • Does Helm itself do anything with the checksum/config annotation?
    No. The key is a convention from the Helm documentation and nothing in Helm inspects it. Helm renders the annotation like any other field and applies the manifest; the restart happens because the Pod template now differs from the stored one, so the workload controller performs a rolling update. Rename the key and the behaviour is unchanged - which is the clearest way to prove where the causality lies.
  • Why use include rather than template for the hashed content?
    `template` writes its output straight into the rendered document and returns nothing, so it cannot be piped into `sha256sum`. `include` renders a named template and returns the result as a string, which is exactly what a pipeline needs. That is why the checksum idiom always uses `include`, and why `include` is the general-purpose choice whenever rendered output has to be transformed.
  • The chart hashes a ConfigMap whose values are later filled in by another controller in the cluster. Does the annotation still work?
    No. The hash covers only what the chart renders. If an external secret operator or another controller writes the real content into the object after apply, the chart's render is identical on every upgrade and the Pods never roll on a content change. Reloading then has to come from elsewhere - the application watching its mounted file, or the controller that owns the data triggering the restart.

saying these in an interview costs you the question

  • Puts the checksum on the Deployment's own metadata
  • Says Helm reads the annotation and restarts Pods
  • Believes editing a ConfigMap restarts Pods by itself
  • Uses a timestamp or random value to force rollouts
  • Inlines the config value instead of a hash
  • Nests the checksum inside an optional annotations block

context