978 words
5 minutes

Inside Helm - How Charts, Releases, and State Work in Kubernetes

By · Developer Advocate · Docker Captain · IBM Champion
Open MacBook Pro on a tiger-stripe wood desk showing a CSS code editor, with a green cactus in a green pot and a travel mug beside it in warm daylight

Hey my DevOps queens (and kings, too)! 👑

Ever deployed an app to Kubernetes and then sat there thinking, “Wait… what actually happens after I type helm install?” Yeah. This one’s for you, sis.

Helm makes Kubernetes deployments look easy. Too easy, honestly. Because behind the scenes it’s doing way more than rendering a few YAML files. It’s a stateful release manager. It tracks every change you make, stores versioned state inside your cluster, and handles upgrades like it actually knows what it’s doing — and there’s no external database anywhere in sight.

So let’s peek behind the curtain. How are charts put together? Where does your release data actually live? And how does Helm keep the whole thing consistent and versioned without breaking a sweat? Grab your coffee. 💅

What’s Inside a Helm Chart#

A Helm chart is a package. It describes how your app should land on Kubernetes, and it’s structured and predictable. Do it right and it becomes gorgeously reusable, too.

my-chart/
Chart.yaml # metadata (name, version, dependencies, etc.)
values.yaml # default configuration values
templates/ # Go templates for Kubernetes manifests
_helpers.tpl # reusable named templates and functions
charts/ # subcharts (dependencies)
files/ # arbitrary files used in templates
crds/ # CustomResourceDefinitions (installed first)
.helmignore # like .gitignore for packaging

Picture it as the blueprint for your app. You flex it through values.yaml, and you can override the defaults at deploy time whenever you like.

Pro tip: CRDs in the crds/ directory are:

  • installed first,
  • not templated,
  • and never upgraded or deleted — this protects existing Custom Resources and data.

What Actually Happens When You Run helm install#

There’s a sequence here, and it matters. Run helm install and Helm doesn’t just “apply some YAML.” It walks through clear steps:

  • Loads the chart (local or remote).
  • Merges values from multiple sources:
    • base values.yaml;
    • any additional files: -f base.yaml -f prod.yaml (left-to-right; later overrides earlier);
    • inline flags: --set, --set-string, --set-file, --set-json (these always take precedence).
  • Renders Go templates into complete Kubernetes manifests.
  • Applies them to the cluster.

Clean install? Helm just creates the resources. Easy.

Things get a little more interesting if the resources already exist. When they carry the correct Helm annotations (meta.helm.sh/*, app.kubernetes.io/managed-by=Helm), Helm will happily adopt them. If they don’t, here’s what you get:

Error: invalid ownership metadata

During upgrades or rollbacks, the story changes again. Helm runs a three-way strategic merge, comparing the previous manifest, the new manifest, and the current cluster state. That whole comparison happens client-side, through client-go.

Where Helm Stores Release State#

Every Helm release lives inside your cluster. No external DBs. No magic. Promise.

By default, your release info goes into a Kubernetes Secret. You can swap that out for a ConfigMap or a SQL driver (PostgreSQL) if you’d rather.

Default object structure:

kind: Secret
type: helm.sh/release.v1
metadata:
name: sh.helm.release.v1.<release>.v<revision>
namespace: <release-namespace>

Now, the .data.release field. This is where the good stuff hides: a base64-encoded, gzip-compressed blob holding the chart archive, the rendered manifests, your merged values, hooks, plus release metadata like revision, timestamps, and status.

One quirk worth knowing. Kubernetes already base64-encodes Secret data, and the release payload also includes encoded sections of its own, so you end up with nested encoding. Encoding inside encoding. Cute, in a confusing way.

Heads up: etcd enforces a ~1 MiB limit for Secret data. Bump into this:

Too long: must have at most 1048576 characters

and it’s time to switch to SQL storage:

Terminal window
export HELM_DRIVER=sql
export HELM_DRIVER_SQL_CONNECTION_STRING=postgresql://user:pass@host/db

Labels and Annotations#

Helm labels everything it touches so it can track ownership down to the detail.

Added automatically:

app.kubernetes.io/managed-by=Helm
meta.helm.sh/release-name=<release-name>
meta.helm.sh/release-namespace=<namespace>

Best-practice labels (usually added by chart templates):

app.kubernetes.io/instance=<release-name>
helm.sh/chart=<chart-name>-<version>

When these don’t line up during an upgrade, Helm refuses to take ownership. And that, darling, is exactly where the classic invalid ownership metadata error comes from.

What Is a Helm Release?#

A release is one installed instance of a chart, with a specific set of values, living in a namespace.

Every change you make becomes a new revision. Install, upgrade, rollback, doesn’t matter. Each one gets stored right there in your cluster. No external database. No API extension. Just plain old Kubernetes objects, quietly doing their job.

The Three-Way Merge Explained#

Here’s what Helm lines up side by side when you upgrade:

  • the previous rendered manifest,
  • the new manifest (after your changes),
  • the current live resources.

From those three, it works out a three-way strategic merge patch and applies only what actually changed. Less disruption that way, and your manual tweaks survive where they can.

NOTE

This logic runs client-side, not via Server-Side Apply. For CRDs or unstructured resources, Kubernetes uses JSON merge-patch, which can behave slightly differently.

Namespaces: Release vs Target#

Helm splits namespaces into two flavors:

  • Release namespace — where Helm stores its Secret or ConfigMap.
  • Target namespaces — where chart resources are deployed (can be multiple).
  • --create-namespace only creates the release namespace (the one you pass with --namespace).

Got a chart that spreads across namespaces? Then create them yourself, or template them inside the chart.

Tip: Try not to hardcode metadata.namespace unless you genuinely need to. Otherwise helm template | kubectl apply might quietly shove your resources into default.

Storage Drivers#

Helm gives you a few backends for storing release state:

Terminal window
export HELM_DRIVER=secret # default (encoded, secure)
export HELM_DRIVER=configmap # readable, not encrypted
export HELM_DRIVER=sql # PostgreSQL – best for large releases
export HELM_DRIVER=memory # ephemeral, for tests only

Managing Release History#

Helm hangs onto all revisions unless you tell it not to. So put a cap on it:

Terminal window
helm upgrade --history-max 10 ...
export HELM_MAX_HISTORY=10

Want to poke through the history? Anytime:

Terminal window
helm history <release>
helm get values <release>
helm get manifest <release>

TL;DR#

Helm isn’t magic. It’s just clean engineering. Every time you fire off helm install, it:

  • loads, merges, and renders templates,
  • stores state inside your cluster,
  • tags resources for ownership tracking,
  • applies three-way strategic merges on upgrade,
  • manages revisions — all with zero external dependencies.

Once the inner workings click for you, Helm stops feeling like a mystery box. It starts feeling like your favorite DevOps assistant. 💖

Quick Debug Tip#

Terminal window
helm ls -A
kubectl get secrets -A -l "owner=helm" -l "status=deployed"

Great for a fast audit, or just snooping on what Helm’s been up to lately.


Tatiana Mikhaleva

Docker Captain  ·  IBM Champion  ·  AWS Community Builder

DevOps.Pink — cloud-native education for the agentic-AI era.

Related Posts

Same category
  1. 1
    How to Secure AI Agents in Production: IBM's Six-Phase Framework
    DevOps & Cloud · Teams secure AI agents like normal software, and production breaks. Here's IBM and Anthropic's six-phase framework for securing them, phase by phase.
  2. 2
    Your AI Agent Doesn't Need a Better Prompt. It Needs a Ceiling
    DevOps & Cloud · A prompt is not a security control. It's a wish. The Vault → Sentinel → MCP → ADLC → watsonx Orchestrate stack that gives AI agents a hard ceiling — and why IBM consolidating HashiCorp made the whole thing boring, in the best possible way.
  3. 3
    CNCF Q1 2026 Report — Why Feature Flagging Is the Hidden Gateway to Cloud Native Maturity
    DevOps & Cloud · CNCF Q1 2026 cloud native report analysis. Why feature flagging is the bridge from mainstream to advanced engineering practice, with exclusive commentary from the report's author.
  4. 4
    AI SRE Joined My On-Call — A Beginner-Friendly Walkthrough of Rootly
    DevOps & Cloud · What an AI SRE actually does on call. A hands-on walkthrough of Rootly — how it observes, advises, and (when you let it) acts. With a real look at the four-level trust model.

Random Posts

Random
  1. 1
    Helm in Kubernetes - What It Is and Why You Need It
    DevOps & Cloud · Helm simplifies Kubernetes deployments. Learn what it is, how it works, and why it's essential for managing scalable apps and infrastructure.
  2. 2
    How Generative AI Actually Understands You
    AI & MLOps · Discover how generative AI understands text, images, video, and sound — explained simply with real examples of tokens, chunks, and embeddings.
  3. 3
    DevSecOps Explained - Security for DevOps in 2025
    DevOps & Cloud · A no-fluff DevSecOps guide for DevOps engineers. Learn how to build secure pipelines, protect secrets, and integrate security from day one.
  4. 4
    How to Secure AI Agents in Production: IBM's Six-Phase Framework
    DevOps & Cloud · Teams secure AI agents like normal software, and production breaks. Here's IBM and Anthropic's six-phase framework for securing them, phase by phase.
Inside Helm - How Charts, Releases, and State Work in Kubernetes
https://devops.pink/inside-helm-how-charts-releases-and-state-work-in-kubernetes/
Author
Tatiana Mikhaleva
Published
2025-11-09
License
CC BY-NC-SA 4.0