What do the three values of Helm's helm.sh/hook-delete-policy do, and which applies when it is omitted?
answer
- Three moments in one hook's life
- Before creation, after success, after failure
- The value is a comma-separated list
- An empty list is what triggers the default
- Writing one value replaces before-hook-creation
basics
~20 sbefore-hook-creation deletes an object of the same kind and name just before the hook is created; hook-succeeded deletes it once the hook succeeds; hook-failed deletes it when the hook fails. With the annotation absent, Helm applies before-hook-creation.
solid answer
~40 sThe annotation is read only on manifests that also carry `helm.sh/hook`, and its value is a comma-separated list, so policies combine. `before-hook-creation` deletes an existing object of the hook's kind and name immediately before Helm creates the hook, waiting for the delete to finish; `hook-succeeded` deletes the object once Helm judges the hook successful; `hook-failed` deletes it when the hook fails. Omit the annotation and Helm applies `before-hook-creation`. The trap is that the default applies only when the list is empty — writing `hook-succeeded` alone *replaces* it rather than adding to it, so a leftover from a failed run is no longer cleared before the next attempt. `before-hook-creation,hook-succeeded` is the common pairing: re-runnable, no accumulation, failures kept for inspection.
code
yaml · 15 linesapiVersion: batch/v1
kind: Job
metadata:
name: order-checkout-migrate
annotations:
"helm.sh/hook": pre-upgrade
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: registry.example.com/order-checkout:1.9.3
args: ["migrate", "--to=latest"]go deeper
Memorise the three values and the default. Being able to say that an unannotated hook behaves as before-hook-creation, and that the value is a comma-separated list, already puts you ahead of most answers.
Explain each policy's firing moment rather than listing names, and state the replacement rule: any value you write takes the place of the default. Say which combination you would put on a migration Job and why.
Demonstrate the tradeoff between a tidy namespace and readable failures, and that you verify the rendered annotation on a live release rather than trusting the chart source you happen to have open.
Frame it as a chart-authoring standard: which hooks must be re-runnable from any state, what evidence a failed hook is required to leave, and how you keep those rules consistent across a library of charts other teams install.
### The annotation and its grammar `helm.sh/hook-delete-policy` is read only on a manifest that also carries `helm.sh/hook`; on an ordinary chart resource it is inert metadata that Helm ignores. Its value is a comma-separated list, so several policies can be in force at once: ```yaml annotations: "helm.sh/hook": pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded ``` Three values are defined, and each names a different moment in the hook's life. **`before-hook-creation`** fires just before Helm creates that hook resource. Helm deletes an existing object of the kind and name the hook manifest declares, waits for it to actually be gone, and then creates the new one. Nothing exists to delete on a first install, and that is not an error — the run simply proceeds. This is the policy that makes a hook with a stable, deterministic name re-runnable across upgrades. **`hook-succeeded`** fires after the hook has completed and Helm has judged it successful. The object is deleted before Helm moves on to the rest of the release. **`hook-failed`** fires after the hook has completed and Helm has judged it failed. The object is deleted even though the release is about to abort. ### The default, and the trap inside it If the annotation is absent, Helm applies `before-hook-creation`. That is the single most useful fact about the annotation, and its consequence is the trap: the default applies only when the policy list is *empty*. The moment you write any value, you have replaced the default rather than added to it. A chart that sets `helm.sh/hook-delete-policy: hook-succeeded` — a very natural thing to write, meaning "tidy up after a good run" — has silently switched off the pre-creation delete. Successful runs clean themselves; the first failed or interrupted run leaves an object sitting on the hook's name, and there is no longer anything to clear it before the next attempt. If you want both behaviours, both must be listed. ### What the policy does not do It does not govern the release's ordinary resources; those are managed through the release manifest and are upgraded and deleted with it. It does not roll anything back: `hook-failed` deletes the hook object, it does not undo work the hook already did, and it has no bearing on whether the release aborts. It does not extend to objects the hook's own process creates at runtime, which Helm never sees. And it does not protect anything — there is no "keep" value in this annotation's vocabulary; keeping is what happens when no policy matches the outcome. ### Choosing the combination Three combinations cover almost every real chart. `before-hook-creation,hook-succeeded` is the workhorse: a clean rerun every time, no accumulation of completed objects, and the failed object left in place so its Pods and logs can be read. Bare default (`before-hook-creation`) suits a hook whose artefact you want to inspect after every run, at the price of one lingering object per hook. Adding `hook-failed` on top gives the tidiest namespace and is right for a hook that already ships its own diagnostics elsewhere, but it is the choice that removes the evidence in an incident, so make it deliberately rather than by copying a template. ### A detail worth carrying The deletion is targeted by what the hook manifest names — its kind and its name — not by a search for objects Helm previously created. That is another argument for release-scoped hook names built from `.Release.Name`: a hook called `db-migrate` in a shared namespace tells Helm to delete whatever `db-migrate` is currently there, which in a multi-tenant namespace may not be the object you had in mind. It is also why `before-hook-creation` is so effective for run-to-completion work: the object it deletes is by definition the previous incarnation of the same hook. ### Reading it back from a live release The annotations that matter are the ones on the *rendered* hook, not the ones in the chart source you happen to be looking at, and values or conditionals may differ between the two. `helm get hooks <release>` prints the hook manifests exactly as they were recorded for that release, annotations included, which is the fastest way to settle an argument about which policy a given deployment actually has in force.
- What does the annotation do on a chart resource that is not a hook?Nothing. Helm reads `helm.sh/hook-delete-policy` only for manifests that also carry `helm.sh/hook`. On an ordinary Deployment or ConfigMap it is inert metadata that travels onto the live object and is ignored — the resource stays in the release manifest and is upgraded and deleted with the release like any other.
- When exactly does before-hook-creation fire, and what if there is nothing to delete?Immediately before Helm creates that hook resource for that event, on every run. Helm issues the delete against the kind and name the hook manifest declares and waits for the object to be gone before creating the new one. If nothing exists — a first install, or a previous run that already cleaned up — there is simply nothing to remove and the hook proceeds normally; it is not an error.
- Does hook-failed change what happens to the release when the hook fails?No. It governs only the hook object. The release still aborts on a failed hook, work the hook already performed is not undone, and resources the release had already applied are unaffected. All `hook-failed` decides is whether the failed object — and with it the Pod logs explaining the failure — is deleted or left in the namespace.
saying these in an interview costs you the question
- Saying an unannotated hook is never deleted by Helm
- Believing hook-succeeded implies before-hook-creation as well
- Thinking the policy also governs the release's ordinary resources
- Claiming hook-failed rolls back or retries the release
- Assuming only one value may be given
- Confusing it with helm.sh/resource-policy on chart resources