Introduction to Helm - The Kubernetes Package Manager

Helm streamlines the deployment and management of Kubernetes applications by packaging all necessary resources into reusable charts. Rather than managing dozens of YAML files manually, Helm enables teams to define, install, and upgrade complex applications with simple commands. This approach transforms Kubernetes deployments from error-prone manual processes into reproducible, version-controlled operations.

What Is Helm?

Helm serves as a package manager for Kubernetes, similar to apt for Ubuntu, yum for Red Hat, or npm for Node.js. It bundles Kubernetes manifests into charts - versioned packages that can be installed, upgraded, and shared across teams and organizations.

graph TB A[Helm] --> B[Package Management] A --> C[Templating] A --> D[Release Management] B --> B1[Charts
Reusable packages] B --> B2[Repositories
Chart distribution] B --> B3[Dependencies
Chart relationships] C --> C1[Values
Configuration] C --> C2[Templates
Dynamic manifests] C --> C3[Functions
Logic & helpers] D --> D1[Versions
Track releases] D --> D2[Upgrades
Update deployments] D --> D3[Rollbacks
Revert changes]

Core Capabilities:

Helm Architecture

Helm 3 (the current major version) uses a client-only architecture that communicates directly with the Kubernetes API:

sequenceDiagram participant User participant Helm as Helm Client participant K8s as Kubernetes API participant Storage as K8s Secret Storage User->>Helm: helm install myapp ./chart Helm->>Helm: Render templates with values Helm->>K8s: Create resources K8s-->>Helm: Resources created Helm->>Storage: Store release info Storage-->>Helm: Release saved Helm-->>User: Installation complete

Key Components:

Helm Client: Command-line tool that developers and operators use to:

Charts: Directories containing files that describe Kubernetes resources:

Releases: Instances of charts running in a cluster with specific configurations. Each installation creates a new release with its own version history.

Repositories: HTTP servers that host chart packages, enabling distribution and discovery.

Installing Helm

Installation is straightforward across platforms:

Linux:

curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash # Verify installation helm version

macOS:

brew install helm # Verify installation helm version

Windows (PowerShell):

choco install kubernetes-helm # Verify installation helm version

From Binary:

# Download the desired version from https://github.com/helm/helm/releases wget https://get.helm.sh/helm-v3.12.0-linux-amd64.tar.gz tar -zxvf helm-v3.12.0-linux-amd64.tar.gz sudo mv linux-amd64/helm /usr/local/bin/helm # Verify installation helm version

Basic Helm Commands

The Helm CLI provides intuitive commands for common operations:

Installing a Chart:

# Install from a local chart directory helm install myapp ./my-chart # Install from a repository helm install myapp bitnami/nginx # Install with custom values helm install myapp ./my-chart -f custom-values.yaml # Install with inline value overrides helm install myapp ./my-chart --set image.tag=v2.0.0

Listing Releases:

# List all releases in current namespace helm list # List releases in all namespaces helm list --all-namespaces # List releases matching a filter helm list --filter '^myapp'

Getting Release Information:

# Show release status helm status myapp # Show values used in a release helm get values myapp # Show all computed values (including defaults) helm get values myapp --all # Show generated manifest helm get manifest myapp

Upgrading a Release:

# Upgrade with new chart version helm upgrade myapp ./my-chart # Upgrade with new values helm upgrade myapp ./my-chart -f production-values.yaml # Force resource updates helm upgrade myapp ./my-chart --force # Perform dry-run to preview changes helm upgrade myapp ./my-chart --dry-run --debug

Rolling Back:

# List release history helm history myapp # Rollback to previous version helm rollback myapp # Rollback to specific revision helm rollback myapp 3

Uninstalling:

# Uninstall a release helm uninstall myapp # Uninstall but keep release history helm uninstall myapp --keep-history

Chart Structure

A Helm chart follows a standard directory structure:

my-chart/ ├── Chart.yaml # Chart metadata ├── values.yaml # Default configuration values ├── charts/ # Dependent charts ├── templates/ # Kubernetes manifest templates │ ├── deployment.yaml │ ├── service.yaml │ ├── ingress.yaml │ ├── _helpers.tpl # Template helpers │ └── NOTES.txt # Post-install notes └── README.md # Chart documentation

Chart.yaml - Chart Metadata:

apiVersion: v2 name: my-application description: A Helm chart for my application type: application version: 1.0.0 # Chart version appVersion: "2.1.3" # Application version keywords: - web - api maintainers: - name: Platform Team email: platform@company.com dependencies: - name: postgresql version: 12.x.x repository: https://charts.bitnami.com/bitnami

values.yaml - Configuration:

replicaCount: 3 image: repository: myapp/api tag: v2.1.3 pullPolicy: IfNotPresent service: type: ClusterIP port: 80 targetPort: 8080 ingress: enabled: true className: nginx hosts: - host: api.example.com paths: - path: / pathType: Prefix resources: limits: cpu: 1000m memory: 512Mi requests: cpu: 250m memory: 256Mi autoscaling: enabled: true minReplicas: 3 maxReplicas: 10 targetCPUUtilizationPercentage: 80

templates/deployment.yaml - Templated Manifest:

apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "my-chart.fullname" . }} labels: {{- include "my-chart.labels" . | nindent 4 }} spec: {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: matchLabels: {{- include "my-chart.selectorLabels" . | nindent 6 }} template: metadata: labels: {{- include "my-chart.selectorLabels" . | nindent 8 }} spec: containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: http containerPort: {{ .Values.service.targetPort }} protocol: TCP resources: {{- toYaml .Values.resources | nindent 10 }}

This template demonstrates several Helm features:

Working with Helm Repositories

Helm repositories enable chart sharing and distribution:

Adding Repositories:

# Add the Bitnami repository helm repo add bitnami https://charts.bitnami.com/bitnami # Add the Prometheus community repository helm repo add prometheus-community https://prometheus-community.github.io/helm-charts # Add a private repository with authentication helm repo add mycompany https://charts.company.com \ --username admin \ --password secretpass

Managing Repositories:

# List configured repositories helm repo list # Update repository indexes helm repo update # Remove a repository helm repo remove bitnami

Searching for Charts:

# Search all configured repositories helm search repo nginx # Search the Artifact Hub helm search hub nginx # Show chart information helm show chart bitnami/nginx # Show chart values helm show values bitnami/nginx # Show all chart information helm show all bitnami/nginx

Practical Example - Deploying a Web Application

Deploy a complete web application with database dependency:

Step 1: Create Chart Structure

helm create webapp cd webapp

Step 2: Configure values.yaml

replicaCount: 2 image: repository: company/webapp tag: "1.0.0" pullPolicy: IfNotPresent service: type: LoadBalancer port: 80 targetPort: 3000 env: - name: NODE_ENV value: production - name: DATABASE_HOST value: webapp-postgresql - name: DATABASE_PORT value: "5432" postgresql: enabled: true auth: database: webappdb username: webappuser password: secretpassword primary: persistence: enabled: true size: 10Gi

Step 3: Add Database Dependency in Chart.yaml

apiVersion: v2 name: webapp description: Complete web application with database type: application version: 1.0.0 appVersion: "1.0.0" dependencies: - name: postgresql version: 12.x.x repository: https://charts.bitnami.com/bitnami condition: postgresql.enabled

Step 4: Update Dependencies

helm dependency update

Step 5: Install the Application

# Install with default values helm install webapp ./webapp # Install with custom values helm install webapp ./webapp -f production-values.yaml # Install in specific namespace helm install webapp ./webapp -n production --create-namespace

Step 6: Verify Deployment

# Check release status helm status webapp # Watch pods starting kubectl get pods -w # Get service endpoint kubectl get svc webapp

Step 7: Upgrade with New Configuration

# Update values.yaml with new replica count # replicaCount: 5 # Apply upgrade helm upgrade webapp ./webapp # Verify upgrade helm history webapp

Step 8: Rollback If Needed

# Check what changed helm diff revision webapp 1 2 # Rollback to previous version helm rollback webapp # Verify rollback helm status webapp

Release Management

Helm provides powerful release lifecycle management:

stateDiagram-v2 [*] --> Deployed: helm install Deployed --> Upgraded: helm upgrade Upgraded --> Upgraded: helm upgrade Upgraded --> RolledBack: helm rollback RolledBack --> Deployed Deployed --> Uninstalled: helm uninstall Upgraded --> Uninstalled: helm uninstall RolledBack --> Uninstalled: helm uninstall Uninstalled --> [*]

Viewing Release History:

# Show all revisions helm history webapp # Output: # REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION # 1 Mon Oct 23 10:00:00 2023 superseded webapp-1.0.0 1.0.0 Install complete # 2 Mon Oct 23 14:30:00 2023 deployed webapp-1.1.0 1.1.0 Upgrade complete

Release Testing:

# Run chart tests helm test webapp # Tests are defined in templates/tests/ directory # Example: templates/tests/test-connection.yaml

Helm Hooks

Hooks allow executing actions at specific points in the release lifecycle:

apiVersion: batch/v1 kind: Job metadata: name: {{ include "my-chart.fullname" . }}-migration annotations: "helm.sh/hook": pre-upgrade "helm.sh/hook-weight": "1" "helm.sh/hook-delete-policy": hook-succeeded spec: template: spec: containers: - name: migration image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" command: ["npm", "run", "migrate"] restartPolicy: Never

Available Hooks:

Benefits of Using Helm

Consistency: Deploy applications the same way across environments using different value files.

Reusability: Package once, deploy anywhere with environment-specific configuration.

Versioning: Track what was deployed when, and easily rollback if issues arise.

Dependency Management: Handle complex multi-tier applications with automatic dependency resolution.

Template Power: Generate complex manifests dynamically based on simple configuration.

Community Ecosystem: Leverage thousands of pre-built charts for common applications.

When to Use Helm

Ideal For:

Consider Alternatives When:

Common Pitfalls

Over-Templating: Creating overly complex templates with excessive logic makes charts hard to understand and maintain. Keep templates simple and readable.

Ignoring Dependencies: Forgetting to run helm dependency update after modifying Chart.yaml leads to outdated or missing dependency charts.

Not Using Dry-Run: Deploying without --dry-run testing can result in unexpected changes. Always preview changes before applying.

Poor Value Structure: Flat, disorganized values files become unwieldy. Use nested structures that mirror the application architecture.

Skipping Documentation: Charts without README files or comments force users to reverse-engineer behavior. Document values and expected usage.

Version Confusion: Mixing up chart versions and application versions causes deployment issues. Maintain clear versioning for both.

Key Takeaways