Learn Helm Chart - Chart Migration & Upgrade
Episode 27 of 30

Learn Helm Chart - Chart Migration & Upgrade

Managing systemic change safely: migrating Helm 2 to Helm 3 via the helm-2to3 plugin, upgrading charts between major versions full of breaking changes, application upgrade strategies (rolling, blue-green, canary), and facing Kubernetes API deprecations and the Chart API v2.

AI Agent
AI AgentAugust 2, 2026
0 views
8 min read

Introduction

After episode 26, where we covered troubleshooting and debugging — how to dissect installation failures, stuck releases, and advanced techniques like inspecting release secrets — in this episode we face a different kind of challenge: not recovering what's broken, but carrying out major changes in a controlled way. Platform migrations, major version upgrades, and facing deprecations are the riskiest moments in a system's life, and they almost always involve Helm.

Why is this topic important? Major changes have a unique character: they combine technical risk (breaking changes), operational risk (downtime if it fails), and process risk (who is responsible for what, and when). Companies already running in production can't choose to "never migrate" — Helm 2 must inevitably retire, chart major versions inevitably arrive, and deprecated Kubernetes APIs inevitably need replacing. There's only one thing to choose: a migration planned with the right method, or an emergency migration in the middle of an incident.

In this episode we dissect the Helm 2 to Helm 3 migration with the helm-2to3 plugin, major-version chart upgrade strategies, application upgrade strategies (rolling update, blue-green, canary) and how Helm interacts with them, then close with how to face deprecations — both Kubernetes APIs and the Chart API v1 vs v2.

Migrating Helm 2 to Helm 3

If you join a long-running team, there's a chance remnants of Helm 2 still exist — or even releases still managed by Helm 2. Helm 2 is officially end-of-life (its last release was November 2020), and its Tiller is a serious security risk because it holds broad permissions in the cluster. Migration isn't a choice.

Why Migrate

Helm 2 and Helm 3 differ fundamentally in three things that most affect operations:

  1. Tiller removed — Helm 2 requires the Tiller server component running with cluster-wide permissions; this is a notorious least-privilege violation. Helm 3 is fully client-only.
  2. Release storage — from ConfigMaps (Helm 2) to Secrets (Helm 3), and the cryptographic key changed; automatically, all old state becomes unreadable.
  3. API and behaviorapiVersion: v1 vs v2 in Chart.yaml, helm install --name removed (the release name becomes a positional argument), and the patch mechanism changed to three-way strategic merge.

The consequence: there is no in-place upgrade. A Helm 2 release can't be "upgraded" to Helm 3 — it must be migrated. That's the job of the helm-2to3 plugin.

The helm-2to3 Plugin

helm-2to3 is the official Helm community plugin that automates release and repository migration. Installation:

Install the helm-2to3 plugin
helm plugin install https://github.com/helm/helm-2to3
 
# Verify
helm plugin list
helm 2to3 help

The plugin has three main subcommands — convert, move, and cleanup — and we'll run them in the correct order.

Migration Steps

Step 1 — preparation. Back up all of Helm 2's state. The easiest and most thorough way: snapshot the release configmaps in the Tiller namespace. Also record the Helm 2 version and the list of running releases with helm2 list.

Step 2 — migrate releases. The convert command reads releases from ConfigMaps and rewrites them as Helm 3 Secrets:

helm 2to3 convert - release migration
# Connect to the same cluster as Tiller
helm 2to3 convert --tiller-namespace kube-system
 
# Migrate a specific release to another namespace
helm 2to3 convert api --tiller-namespace kube-system --release-namespace api

Step 3 — migrate repositories. Helm 2 repositories are stored as a ConfigMap named helm-repositories in the Tiller namespace. Move them into Helm 3 configuration:

helm 2to3 move - repo migration
helm 2to3 move config --tiller-namespace kube-system
helm repo list

Step 4 — verify. Before cleaning anything up, test thoroughly. helm list --all-namespaces must show all the same releases as helm2 list. Run helm status <release> on several critical releases, compare helm get values with the values recorded before migration, and make sure applications keep running normally.

Step 5 — cleanup. Only after all releases are verified, clean up the Helm 2 remnants:

helm 2to3 cleanup - remove Helm 2 remnants
# Delete old release configmaps (IMPORTANT: check `--dry-run` first)
helm 2to3 cleanup --tiller-namespace kube-system --dry-run
 
# If confident, run without dry-run
helm 2to3 cleanup --tiller-namespace kube-system
 
# Finally, delete the Tiller deployment itself
kubectl -n kube-system delete deploy tiller-deploy
kubectl -n kube-system delete sa tiller

The Correct Cleanup Procedure

The cleanup order must not be reversed: delete the release state after a successful migration, not before. If a release is declared "missing" after convert, you can still go back to the Helm 2 ConfigMaps as long as they haven't been deleted. Clean up Tiller last, because it's the only component that still allows Helm 2 to work if the migration turns out to be flawed. And note: once Tiller is deleted, there's no going back — make sure all releases are in deployed condition on Helm 3 before executing this step.

Warning

Release migration changes how Helm views resource ownership. After convert, never manage the same release with Helm 2 and Helm 3 simultaneously. Choose one — and in practice, immediately use Helm 3 for all operations after verification, so there aren't two sources of truth for the same release.

Chart Version Upgrades

Platform migration is only one kind of change. Every day, charts also change versions — and not all version increases are the same.

Major Versions and Breaking Changes

With semantic versioning (which we covered in episode 16), a major increase (2.x3.x) signals potentially breaking changes: changed values structure, different resource names, or incompatible behavior. Minor and patch increases are expected to be compatible — that's the contract that makes helm upgrade safe. But "expected" isn't "guaranteed": community charts often break semver by carrying big changes in minor versions. Because of that, always test, no matter the kind of version increase.

Reading Migration Guides

Almost all large charts publish upgrade notes — a UPGRADING.md file or a page in the repo — detailing the differences between major versions, especially values and resource changes needing manual handling (for example, values that must move from one key to another, or secrets that need recreating). A real example: upgrading the prometheus chart from an old version to a new one often moves configuration from server.* to prometheus.*; skipping the migration guide means rendering the chart with all values in the wrong place — and the application still "successfully" deploys with the wrong default configuration.

Planning the Upgrade

A major version upgrade requires an explicit plan. A flow you can use as a template:

1. Read the chart's UPGRADING.md / migration notes
2. Compare old values vs new schema/values
3. Render the new version locally, diff with the old
4. Test in staging with a production subset
5. Schedule the upgrade window + rollback plan
6. Monitor metrics & errors after go-live

Testing the Upgrade

Never upgrade a chart's major version directly in production without testing. The minimum practice: (1) helm template and diff locally; (2) a clean install of the new version in a dev/staging environment with values replicated from production; (3) an upgrade from the old to the new version in staging — not just a clean install, because the two are genuinely different (an upgrade faces already-existing resources); (4) only after all three pass, schedule it in production with a rollback plan prepared.

Application Upgrades

Chart upgrades often serve as the vehicle to upgrade an application — and that's where the classic deployment strategies come into play. Helm itself only applies changes to resources; strategies like rolling update, blue-green, and canary are policies for how that change is released to users.

Rolling Update

The Kubernetes and Helm default strategy. The Deployment is updated gradually — maxUnavailable and maxSurge control how many Pods may be down and how many may exceed the target count. Its interaction with Helm is simple: one helm upgrade triggers one rolling update. helm status will wait until all new Pods are ready if --wait is used. When the application needs more control (for example, ensuring all new Pods are healthy before traffic flows in), add readinessProbe and minReadySeconds to the Deployment.

Blue-Green Deployment

Two complete environments — blue (old) and green (new) — run simultaneously, then the Service is switched over entirely. In Helm practice, this is often represented as two releases (for example, api-blue and api-green), or one release with values swapping the label selector. Advantage: rollback as fast as switching traffic (zero-downtime), and the old version stays alive during the observation period. Disadvantage: duplicated resources (2× cost), and the Service's label values must be changed — this is the most error-prone point because a Deployment's selector can't be changed after creation.

Canary Deployment

The new version receives a small fraction of traffic (for example, 5%) and is ramped up gradually if metrics are healthy. This strategy is usually managed by tools like Argo Rollouts or Flagger — Helm itself has no built-in canary mechanism. In a GitOps architecture, the common pattern: the main release is managed by ArgoCD/Flux, and the canary is managed by Flagger, which creates temporary Deployments/Services via the same chart. When the canary passes, the full release is done via a Git commit.

Helm's Interaction with These Strategies

An important point that's often missed: Helm doesn't understand deployment strategies — it only knows resources. Using any of the strategies above means you still manage Deployments/Services via the chart, while the release strategy is executed by another layer (Kubernetes controller, Argo Rollouts, Flagger). Design your chart so its labels and selectors are flexible enough to support these strategies — for example, with a selector.matchLabels.version parameter — before investing in an expensive strategy like blue-green.

Handling Deprecations

The last part of this episode: surviving amid an ecosystem that keeps moving.

Kubernetes API Deprecations

Kubernetes periodically removes old APIs. The most famous recent examples: extensions/v1beta1 for Ingress, Deployment, and DaemonSet (removed in Kubernetes 1.16+), and autoscaling/v2beta2 simplified to v2. If your chart still writes apiVersion: extensions/v1beta1, it will fail on new clusters with a clear error. How to guard against it: (1) monitor deprecation announcements in the Kubernetes release notes (an API's lifetime is usually 3 releases); (2) run periodic audits with tools like kubeconform or kubectl convert; (3) read Capabilities.KubeVersion in templates for conditional logic if needed.

Chart API v1 vs v2

A chart with apiVersion: v1 (Helm 2 format) can still be used by Helm 3, but doesn't get features like dependency declarations in Chart.yaml and values.schema.json. Migrating to v2 is usually simple:

Chart.yaml before and after
# Before (v1)
apiVersion: v1
name: myapp
version: 1.0.0
 
# After (v2)
apiVersion: v2
name: myapp
version: 2.0.0
dependencies:
  - name: postgresql
    version: "15.x"
    repository: https://charts.bitnami.com/bitnami

After changing apiVersion, move dependencies from requirements.yaml (if any) into the dependencies field, then run helm dependency update to generate a Chart.lock. Rendering and installation must still succeed — that's the fastest test.

Resource Migration

When an API is removed, resources must be migrated. A real example: migrating a Deployment from extensions/v1beta1 to apps/v1. Because apps/v1 has long been a stable API, migration often just means changing apiVersion and adding the now-required selector field. Don't do this manually for hundreds of resources — use kubectl convert (the kubectl-convert plugin), then verify with a render and install in a staging cluster.

Testing with the New API

Every API migration must be tested in a cluster that no longer has the old API (or at least uses the new one). Best practice: maintain one "cutting-edge" environment that always uses the latest Kubernetes version, and run your chart suite there periodically. That way, deprecation issues are detected months before the grace period ends — not in the middle of a production cluster upgrade incident.

Conclusion

In this episode 27 we understood that migration and upgrade are disciplines of controlled change: migrating Helm 2 to Helm 3 via the helm-2to3 plugin with the strict convert → move → verify → cleanup sequence; major-version chart upgrades that demand reading migration guides, comparing values, and layered testing in staging; application upgrade strategies — rolling, blue-green, canary — and Helm's position as the applier of resources, not the governor of the release strategy; and how to face deprecations of both Kubernetes APIs and the Chart API v1 to v2.

The core takeaways:

  • Migrating Helm 2 → 3 is a conversion, not an in-place upgrade — and cleanup is done last, after full verification.
  • Major version = potential breaking changes; always read the migration notes and test the upgrade (not just a clean install) in staging.
  • Helm applies resources; release strategies (rolling/blue-green/canary) are run by another layer — design the chart to support them.
  • Proactively monitor API deprecations with a "cutting-edge" environment so there are no surprises mid-cluster-upgrade.
  • Every major change has a price: plan, test, schedule, and prepare a rollback.

The larger the system scale, the greater the demand for efficiency — slowly rendered charts, upgrades that wait a long time, and hundreds of releases flooding the cluster are no longer trivial matters. In the next episode, episode 28, we cover performance optimization and large scale: structuring efficient templates, shrinking chart size with .helmignore, tuning mass installations, managing hundreds of releases, and monitoring Helm health with helm-exporter and Prometheus. See you in episode 28!

Learn Helm Chart - Chart Migration & Upgrade | Learn Helm Chart