What does the helm.sh/resource-policy: keep annotation do to a rendered resource?
answer
- An annotation Helm reads, not Kubernetes
- Two moments it intervenes, not one
- Survivor keeps metadata it no longer deserves
- Trades data loss for a redeploy collision
- Only for what cannot be re-rendered
basics
~20 shelm.sh/resource-policy: keep tells Helm to skip deleting that object when an operation would otherwise remove it — uninstall, or an upgrade that drops it from the chart. The object survives as an orphan Helm no longer manages.
solid answer
~50 s`helm.sh/resource-policy: keep` is an annotation a chart puts on a rendered object. When a Helm operation would delete that object — `helm uninstall`, or an upgrade or rollback in which the object is no longer part of the rendered chart — Helm skips the deletion and leaves it in the cluster. `keep` is the only value with meaning. The cost is that the survivor becomes an orphan: it is no longer part of any release, nothing tracks it, and a later install of the same chart hits an object that already exists but carries the wrong release ownership metadata, which Helm refuses to adopt by default. Charts use it for the handful of objects whose loss is unrecoverable — a PersistentVolumeClaim rendered by the chart, or a CRD rendered under `templates/` — not as a blanket safety setting.
code
yaml · 12 linesapiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "platform.fullname" . }}-model-cache
annotations:
helm.sh/resource-policy: keep
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 340Gigo deeper
Recall the exact annotation and its one meaningful value, and that Helm honours it by not deleting the object. Know that it is written by the chart author into the template, not passed as a flag at the command line.
Explain both moments Helm consults it: uninstall, and an upgrade or rollback where the object has dropped out of the rendered chart. Describe what the survivor becomes — an untracked orphan still wearing release metadata.
Show the tradeoff you actually manage: keep converts a data-loss risk into a redeploy collision plus an untracked object nobody bills or patches. Be ready to say how you find the survivors before an uninstall rather than after.
Own where the decision belongs. Which resource classes may carry keep is a chart-authoring standard for your platform, not a per-release judgement call, and the standard has to name who reclaims the orphans and when.
### The annotation ```yaml metadata: annotations: helm.sh/resource-policy: keep ``` It is read by Helm, not by Kubernetes — nothing in the cluster changes behaviour because of it. It is a marker on a rendered object that Helm consults whenever it is about to issue a delete for that object. ### When Helm would otherwise delete There are two distinct situations, and candidates usually name only the first: 1. **Uninstall.** Helm walks the stored manifest of the current revision and deletes each object in it. An object annotated `keep` is skipped. 2. **An upgrade (or rollback) that drops the object.** When the newly rendered manifest no longer contains an object that the previous revision's manifest did — the template was deleted, or a conditional turned it off — Helm deletes it as part of reconciling to the new state. `keep` skips that deletion too. The second case is the one people are surprised by, in both directions: surprised that a template they removed took a live object with it, and surprised that annotating it `keep` means that object now hangs around forever after they thought they had removed the feature. ### What the survivor becomes The kept object is not transferred to some other manager; it is simply not deleted. It keeps whatever labels and annotations it was rendered with, including `app.kubernetes.io/managed-by: Helm` and the release metadata — which is now a lie, because the release that put them there may no longer exist. Nothing tracks it, nothing will update it, and no future `helm upgrade` will touch it, because it is not in any release's manifest any more. That produces the second-order problem. Install the same chart again into the same namespace and Helm renders the same object, finds one already present, and sees ownership metadata pointing at a release that is not this one. Helm refuses to adopt objects it does not own, so the install fails on an existing resource rather than quietly taking it over. The candidate who has actually operated this will say so unprompted: `keep` converts a data-loss risk into a redeploy-collision risk, and someone has to own the resulting cleanup. ### What to annotate, and what not to The rule of thumb is that `keep` belongs on objects whose deletion is unrecoverable, and nowhere else: - a PersistentVolumeClaim the chart renders directly, holding data the chart cannot regenerate; - a CRD rendered under `templates/` (as opposed to shipped in `crds/`), because deleting a CRD takes every custom resource of that kind with it, cluster-wide; - occasionally a Secret whose value was generated once at install time and is not reproducible. It does not belong on Deployments, Services, ConfigMaps, ServiceAccounts or anything else the chart can simply re-render. Annotating those makes uninstall a lie: the release disappears from `helm list` while most of the workload is still running, and the next engineer has to reconstruct by hand what the release used to consist of. ### Making the survivors visible Because `keep` is invisible at operation time unless you go looking, treat it as a chart-review concern. Grep the rendered output rather than the templates, since the annotation may be conditional: ```bash helm get manifest platform-core -n platform | grep -B8 'helm.sh/resource-policy: keep' ``` That tells you, before you run an uninstall, exactly which objects will still be in the namespace afterwards — and it is the difference between a teardown you can verify and one you merely hope worked. ### The boundary worth stating `keep` is a chart-author decision expressed in the chart, and it applies to objects Helm renders. It has nothing to say about objects Helm never rendered in the first place: claims a controller created from a StatefulSet's volume claim templates, or CRDs installed from `crds/`, survive uninstall regardless of any annotation, because Helm was never going to delete them. Confusing the two is the most common way this topic goes wrong in an interview: `keep` is the reason a *tracked* object survives, not the explanation for every leftover in the namespace.
- Does helm.sh/resource-policy: keep also apply when an upgrade removes the object from the chart?Yes, and that is the half people forget. When the newly rendered manifest no longer contains an object the previous revision had, Helm deletes it during the upgrade; the annotation skips that deletion as well. So removing a template from a chart does not remove a kept object from the cluster.
- What goes wrong when you reinstall a chart whose objects were kept from a previous release?The render produces objects that already exist and carry release ownership metadata from the old release. Helm will not adopt objects it does not own, so the install fails on the existing resource. Someone has to decide deliberately whether to delete the survivor or adopt it, which is exactly the review the annotation deferred.
- Are there other values for helm.sh/resource-policy besides keep?keep is the value to rely on; it is what the annotation exists for. Anything else in that annotation should be treated as having no effect, so do not build chart behaviour on a value you cannot demonstrate. If you want an object gone on uninstall, the correct move is to leave the annotation off entirely.
saying these in an interview costs you the question
- Thinks Kubernetes enforces the annotation, not Helm
- Says it only matters at uninstall time
- Puts keep on every object as a safety measure
- Believes a kept object is still managed by Helm
- Expects a reinstall to silently adopt the survivor
- Uses keep to explain leftover StatefulSet claims