diff --git a/versioned_docs/version-3/faq/changes_since_helm2.md b/versioned_docs/version-3/faq/changes_since_helm2.md index bffbfd7ca5..05b522d611 100644 --- a/versioned_docs/version-3/faq/changes_since_helm2.md +++ b/versioned_docs/version-3/faq/changes_since_helm2.md @@ -54,111 +54,12 @@ the last applied chart's manifest as its current state, if there were no changes in the chart's state, the live state was left unchanged. In Helm 3, we now use a three-way strategic merge patch. Helm considers the old -manifest, its live state, and the new manifest when generating a patch. +manifest, its live state, and the new manifest when generating a patch. This +means out-of-band changes (such as `kubectl edit` or injected sidecars) are +preserved when they do not conflict with the new manifest. -#### Examples - -Let's go through a few common examples what this change impacts. - -##### Rolling back where live state has changed - -Your team just deployed their application to production on Kubernetes using -Helm. The chart contains a Deployment object where the number of replicas is set -to three: - -```console -$ helm install myapp ./myapp -``` - -A new developer joins the team. On their first day while observing the -production cluster, a horrible coffee-spilling-on-the-keyboard accident happens -and they `kubectl scale` the production deployment from three replicas down to -zero. - -```console -$ kubectl scale --replicas=0 deployment/myapp -``` - -Another developer on your team notices that the production site is down and -decides to rollback the release to its previous state: - -```console -$ helm rollback myapp -``` - -What happens? - -In Helm 2, it would generate a patch, comparing the old manifest against the new -manifest. Because this is a rollback, it's the same manifest. Helm would -determine that there is nothing to change because there is no difference between -the old manifest and the new manifest. The replica count continues to stay at -zero. Panic ensues. - -In Helm 3, the patch is generated using the old manifest, the live state, and -the new manifest. Helm recognizes that the old state was at three, the live -state is at zero and the new manifest wishes to change it back to three, so it -generates a patch to change the state back to three. - -##### Upgrades where live state has changed - -Many service meshes and other controller-based applications inject data into -Kubernetes objects. This can be something like a sidecar, labels, or other -information. Previously if you had the given manifest rendered from a Chart: - -```yaml -containers: -- name: server - image: nginx:2.0.0 -``` - -And the live state was modified by another application to - -```yaml -containers: -- name: server - image: nginx:2.0.0 -- name: my-injected-sidecar - image: my-cool-mesh:1.0.0 -``` - -Now, you want to upgrade the `nginx` image tag to `2.1.0`. So, you upgrade to a -chart with the given manifest: - -```yaml -containers: -- name: server - image: nginx:2.1.0 -``` - -What happens? - -In Helm 2, Helm generates a patch of the `containers` object between the old -manifest and the new manifest. The cluster's live state is not considered during -the patch generation. - -The cluster's live state is modified to look like the following: - -```yaml -containers: -- name: server - image: nginx:2.1.0 -``` - -The sidecar pod is removed from live state. More panic ensues. - -In Helm 3, Helm generates a patch of the `containers` object between the old -manifest, the live state, and the new manifest. It notices that the new manifest -changes the image tag to `2.1.0`, but live state contains a sidecar container. - -The cluster's live state is modified to look like the following: - -```yaml -containers: -- name: server - image: nginx:2.1.0 -- name: my-injected-sidecar - image: my-cool-mesh:1.0.0 -``` +For detailed examples, CRD limitations, and the `--force` flag behavior, see +[Resource Upgrades](../topics/resource_upgrades.md). ### Release Names are now scoped to the Namespace diff --git a/versioned_docs/version-3/topics/resource_upgrades.md b/versioned_docs/version-3/topics/resource_upgrades.md new file mode 100644 index 0000000000..43f6d5034c --- /dev/null +++ b/versioned_docs/version-3/topics/resource_upgrades.md @@ -0,0 +1,80 @@ +--- +title: Resource Upgrades +description: Describes how Helm updates Kubernetes resources during upgrades and rollbacks. +sidebar_position: 18 +--- + +Helm uses a **three-way strategic merge patch** when upgrading or rolling back +releases. It compares three sources to generate the patch: + +1. The **old manifest** stored in the last release +2. The **live state** of the resource in the cluster +3. The **new manifest** from the chart being applied + +This means out-of-band changes (such as `kubectl edit` or injected sidecars) +are preserved when they do not conflict with the new manifest. + +## Examples + +### Rolling back where live state has changed + +Suppose your chart sets `replicas: 3`, but someone scales the Deployment to +zero with `kubectl scale`: + +```console +$ helm install myapp ./myapp +$ kubectl scale --replicas=0 deployment/myapp +$ helm rollback myapp +``` + +Because Helm compares the old manifest (3 replicas), the live state (0 +replicas), and the new manifest (3 replicas), it generates a patch that +restores the replica count to three. + +### Upgrades that preserve injected sidecars + +A service mesh injects a sidecar container into your pod. When you upgrade the +chart to change the `nginx` image tag: + +```yaml +containers: +- name: server + image: nginx:2.1.0 +``` + +Helm sees that the live state has an additional `my-injected-sidecar` container +not present in either the old or new manifest, so it keeps the sidecar while +applying the image change. + +## CRDs and JSON merge patch + +The strategic merge patch described above only applies to **built-in Kubernetes +types** that have schema metadata defining list merge keys. For **Custom +Resource Definitions (CRDs)** and other unstructured objects, Helm falls back +to a standard **JSON merge patch**. + +JSON merge patch replaces arrays wholesale rather than merging them by key. +This means: + +- List fields in CRDs (such as container lists or rule lists) are **overwritten + entirely** with the values from the new manifest +- Injected items that are not present in the chart manifest will be removed on + upgrade + +If your CRDs have array fields that are modified by controllers or other +processes, consider using `--force` (see below) or managing those resources +outside of Helm. + +## The `--force` flag + +When `helm upgrade --force` is used, Helm skips the merge patch entirely and +performs a full **resource replacement** via the Kubernetes API. This is useful +when a patch cannot be applied (for example, when an immutable field has +changed), but carries risks: + +- The resource is replaced in place, which may cause a brief disruption +- Immutable fields (such as a Service's `clusterIP` or a PVC's storage class) + will cause the replacement to fail if they differ from the live state +- It cannot be combined with `--server-side-apply` + +Use `--force` as a last resort when normal patching fails.