Helm Release Management

Helm treats every deployment as a versioned, tracked, and reversible release. Unlike raw kubectl apply, Helm maintains a full revision history of what was deployed, enabling atomic upgrades, instant rollbacks, and auditable change tracking. Synthesized from Helm Zero to Hero by @AbhishekVeeramalla.

The Release Lifecycle

A Helm release moves through four states: Install → Upgrade → Rollback → Uninstall. Every transition creates a revision snapshot, stored as a Secret (default in Helm v3) in the release’s Namespace.

Install (rev 1) → Upgrade (rev 2) → Upgrade (rev 3) → Rollback (rev 4 = copy of rev 2)

Revision numbers only increase. A rollback does not delete the bad revision — it creates a new revision that re-applies the manifest state of an earlier one. This preserves a complete, immutable audit trail.

Installing a Release

# Basic install from a repository
helm install my-nginx bitnami/nginx
 
# Install into a specific Namespace (creates the Namespace if needed)
helm install my-nginx bitnami/nginx -n web --create-namespace
 
# Install with custom values
helm install my-nginx bitnami/nginx --set service.type=NodePort
helm install my-nginx bitnami/nginx -f prod-values.yaml
 
# Install with a generated name
helm install bitnami/nginx --generate-name
 
# Dry-run to validate without deploying
helm install my-nginx bitnami/nginx --dry-run

Key behaviors:

  • Release names must be unique per Namespace. You can have my-nginx in both dev and prod Namespaces.
  • helm install is atomic by default: if the deployment fails (e.g., Pods never become ready), Helm automatically rolls back to the pre-install state.
  • The --wait flag blocks until all resources reach a ready state (respecting readiness probes).

Upgrading a Release

# Upgrade to a new chart version
helm upgrade my-nginx bitnami/nginx --version 14.0.0
 
# Upgrade with new values
helm upgrade my-nginx bitnami/nginx --set replicaCount=5
 
# Upgrade or install if not present (CI/CD standard)
helm upgrade --install my-nginx bitnami/nginx
 
# Force resource recreation (e.g., immutable field changes)
helm upgrade my-nginx bitnami/nginx --force
 
# Atomic upgrade: rollback automatically on failure
helm upgrade my-nginx bitnami/nginx --atomic

Upgrade mechanics:

  • Helm computes a three-way strategic merge between the previous release manifest, the live cluster state, and the new manifest. This handles out-of-band edits (e.g., someone kubectl edit a Deployment) gracefully.
  • Every upgrade creates a new revision. Previous revisions remain in history.
  • The --atomic flag is recommended in CI/CD: if the upgrade fails, Helm rolls back automatically rather than leaving the cluster in a broken intermediate state.

Rollback

Rollback is Helm’s safety net — the feature that distinguishes it from plain kubectl apply:

# View revision history
helm history my-nginx
 
# Rollback to revision 2
helm rollback my-nginx 2
 
# Rollback with a timeout
helm rollback my-nginx 2 --wait --timeout 5m

What happens during rollback:

  1. Helm reads the manifest stored for the target revision
  2. It re-applies that manifest to the cluster
  3. A new revision is created (e.g., rev 5 = copy of rev 2)
  4. The live cluster state is restored to the target revision’s configuration

Important: Rollback restores Kubernetes resource state, not application data. If a database schema migration ran during an upgrade, rolling back the Deployment does not reverse the migration. Data rollbacks require application-level strategies.

Uninstalling a Release

# Remove all resources created by the release
helm uninstall my-nginx
 
# Remove but preserve release history
helm uninstall my-nginx --keep-history
 
# Uninstall from a specific Namespace
helm uninstall my-nginx -n web

By default, helm uninstall deletes all tracked resources and removes the release history. With --keep-history, the release is marked as uninstalled but revision Secrets are retained for audit purposes.

Release History and Audit

# List all revisions of a release
helm history my-nginx
 
# Output format: revision, updated, status, chart, app version, description
# REVISION UPDATED                  STATUS      CHART         APP VERSION DESCRIPTION
# 1        Mon Jul 14 10:00:00     deployed    nginx-13.0.0  1.27.0      Install complete
# 2        Mon Jul 14 11:30:00     deployed    nginx-13.1.0  1.28.0      Upgrade complete
# 3        Mon Jul 14 12:00:00     failed      nginx-13.1.0  1.28.0      Upgrade "my-nginx" failed
# 4        Mon Jul 14 12:05:00     deployed    nginx-13.0.0  1.27.0      Rollback to 1

Revision statuses:

StatusMeaning
deployedSuccessfully applied and healthy
supersededReplaced by a newer revision
failedDeployment failed (may have auto-rolled back)
uninstalledRelease was removed
pending-installInstallation in progress
pending-upgradeUpgrade in progress
pending-rollbackRollback in progress

Release Storage: Secrets vs ConfigMaps

Helm v3 stores release metadata in the target Namespace. The default storage backend is Secrets (helm.sh/release.v1 type). This is more secure than the Helm v2 ConfigMap default because:

  • Secrets are base64-encoded at rest (minimal obfuscation, but better than plaintext)
  • RBAC can restrict read access to release history
  • etcd encryption at rest (if enabled) applies to Secrets

To use ConfigMaps instead (legacy behavior):

helm install my-nginx bitnami/nginx --storage-driver configmap

Release Scoping and Namespaces

Helm releases are Namespace-scoped — a release name only needs to be unique within its Namespace. This enables clean multi-environment patterns:

# Same chart, three environments, three Namespaces
helm install frontend ./webapp -n dev
helm install frontend ./webapp -n staging
helm install frontend ./webapp -n prod -f values-prod.yaml

Best practices:

  • Include the environment in release names for cluster-wide uniqueness: myapp-prod, myapp-dev
  • Use separate kubeconfig contexts or --namespace flags in CI/CD to prevent accidental prod deployments
  • Namespace-scoped RBAC can prevent dev engineers from installing into prod Namespaces

Helm in CI/CD Pipelines

The standard CI/CD pattern uses helm upgrade --install for idempotent deployment:

# Build stage
helm package ./myapp
 
# Test stage
helm lint ./myapp
helm template myapp ./myapp | kubeconform -strict
helm test myapp -n staging
 
# Deploy stage
helm upgrade --install myapp ./myapp \
  --namespace prod \
  --values values-prod.yaml \
  --atomic \
  --wait \
  --timeout 10m \
  --create-namespace

Flags explained:

FlagPurpose
--installCreate the release if it does not exist
--atomicRollback automatically if the upgrade fails
--waitBlock until all resources are ready
--timeoutFail if deployment takes longer than N minutes
--create-namespaceCreate the target Namespace if missing

Troubleshooting Releases

SymptomDiagnosticFix
Release stuck in pending-installPod scheduling or image pull failurekubectl get pods -n <ns>; check Events
helm upgrade fails with “another operation in progress”Previous upgrade was interruptedhelm rollback to last known good revision
Live state diverged from Helm historyOut-of-band kubectl edithelm diff upgrade to see drift; re-apply chart
Release exists but helm list is emptyWrong Namespace or contexthelm list -A; kubectl config current-context
Cannot rollbackRelease history purgedAvoid --keep-history 0; set reasonable retention

Tags: helm release-management kubernetes gitops rollback upgrade devops cicd