Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 5 additions & 104 deletions versioned_docs/version-3/faq/changes_since_helm2.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
80 changes: 80 additions & 0 deletions versioned_docs/version-3/topics/resource_upgrades.md
Original file line number Diff line number Diff line change
@@ -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.