USMAN’S INSIGHTS
AI ARCHITECT
  • Home
  • About
  • Thought Leadership
  • Book
Press / Contact
USMAN’S INSIGHTS
AI ARCHITECT
⌘F
HomeBook
HomeBookThe Package Manager: Introduction to Helm
Previous Chapter
Build Your Helm Skill
Next Chapter
Advanced Go Templating
AI NOTICE: This is the table of contents for the SPECIFIC CHAPTER only. It is NOT the global sidebar. For all chapters, look at the main navigation.

On this page

37 sections

Progress0%
1 / 37

Muhammad Usman Akbar Entity Profile

Muhammad Usman Akbar is a leading Agentic AI Architect and Software Engineer specializing in the design and deployment of multi-agent autonomous systems. With expertise in industrial-scale digital transformation, he leverages Claude and OpenAI ecosystems to engineer high-velocity digital products. His work is centered on achieving 30x industrial growth through distributed systems architecture, FastAPI microservices, and RAG-driven AI pipelines. Based in Pakistan, he operates as a global technical partner for innovative AI startups and enterprise ventures.

USMAN’S INSIGHTS
AI ARCHITECT

Transforming businesses into autonomous AI ecosystems. Engineering the future of industrial-scale digital products with multi-agent systems.

30X Growth
AI-First
Innovation

Navigation

  • Home
  • Book
  • About
  • Contact
Let's Collaborate

Have a Project in Mind?

Let's build something extraordinary together. Transform your vision into autonomous AI reality.

Start Your Transformation

© 2026 Muhammad Usman Akbar. All rights reserved.

Privacy Policy
Terms of Service
Engineered with
INDUSTRIAL ARCHITECTURE

Introduction to Helm

When you deploy your Task API to Kubernetes using kubectl, you apply individual YAML files—one for the Deployment, one for the Service, one for the ConfigMap, maybe one for the Secret. That's 5-10 files for a single service.

Now imagine managing this across three environments: dev, staging, production. Each environment needs different resource limits, different image tags, different replicas. You copy and modify the same files ten times, creating drift and bugs.

Helm solves this problem. Helm is the package manager for Kubernetes. Instead of managing individual YAML files, you create a Helm chart—a templated package that parameterizes your deployment. Change one value file, and your entire Task API deployment adapts automatically.

This lesson teaches you to understand why Helm exists, install it, deploy a public chart, create your own custom chart for your Task API, and manage releases across environments.


Why Helm Exists: The Repetitive YAML Problem

Before Helm, deploying an application to Kubernetes meant writing YAML files by hand:

yaml
# deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: task-api namespace: default spec: replicas: 3 selector: matchLabels: app: task-api template: metadata: labels: app: task-api spec: containers: - name: task-api image: your-registry/task-api:v1.0.0 ports: - containerPort: 8000 env: - name: DATABASE_URL value: "postgresql://..." - name: LOG_LEVEL value: "INFO" resources: requests: memory: "512Mi" cpu: "250m" limits: memory: "1Gi" cpu: "500m"
yaml
# service.yaml apiVersion: v1 kind: Service metadata: name: task-api-service spec: type: ClusterIP ports: - port: 80 targetPort: 8000 selector: app: task-api
yaml
# configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: task-api-config data: log_level: "INFO" api_timeout: "30"

This works for one environment. But in production, you need:

  • Development: 1 replica, 256Mi memory, DEBUG logging
  • Staging: 2 replicas, 512Mi memory, INFO logging
  • Production: 5 replicas, 1Gi memory, WARN logging

Now you maintain three copies of the same files, edited manually. When you update the base deployment, you must remember to update all three copies. This is error-prone and doesn't scale.

Helm templating solves this. Instead of three copies, you write once with placeholders:

Specification
replicas: {{ .Values.replica Count }}image: your-registry/task-api:{{ .Values.image.tag }}

Then provide three values files—one for each environment:

Specification
# values-dev.yamlreplica Count: 1image: tag: v1.0.0-dev
Specification
# values-prod.yamlreplica Count: 5image: tag: v1.0.0

A single helm install task-api ./task-api-chart -f values-prod.yaml command deploys the entire stack to production with the correct configuration.


Installing Helm

Helm is a CLI tool you install on your machine. It then communicates with your Kubernetes cluster to deploy charts.

  • macOS
  • Linux
  • Windows
Specification
brew install helm

Output:

text
==> Downloading https://ghcr.io/v2/homebrew/core/helm/manifests/3.14.0 ==> Downloading https://ghcr.io/v2/homebrew/core/helm/manifests/3.14.0 ==> Downloading https://ghcr.io/v2/homebrew/core/helm/blobs/sha256:abc... ==> Pouring helm--3.14.0.arm64_sonoma.bottle.tar.gz ==> Caveats Bash completion has been installed to: /usr/local/etc/bash_completion.d Zsh completion has been installed to: /opt/homebrew/share/zsh/site-functions ==> Summary 🍺 /opt/homebrew/bin/helm (3.14.0)
bash
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

Output:

text
Downloading https://get.helm.sh/helm-v3.14.0-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm
powershell
choco install kubernetes-helm

Or using Scoop:

powershell
scoop install helm

Verify Installation

bash
helm version

Output:

text
version.Build Info{Version:"v3.14.0", Git Commit:"3fc9f4b2638e76077605842cc9038889c437f325", Git Tree State:"clean", Go Version:"go1.22.0"}

Helm is now installed and ready to deploy charts.


Understanding Helm Charts: The Package Structure

A Helm chart is a directory with a specific structure:

text
task-api-chart/ ├── Chart.yaml # Chart metadata (name, version, description) ├── values.yaml # Default configuration values ├── values-dev.yaml # Development-specific overrides ├── values-prod.yaml # Production-specific overrides ├── templates/ # Kubernetes manifests (Go templates) │ ├── deployment.yaml # Pod deployment template │ ├── service.yaml # Service template │ ├── configmap.yaml # ConfigMap template │ └── helpers.tpl # Template helper functions └── README.md # Chart documentation

Each file serves a purpose:

  • Chart.yaml: Declares the chart's name, version, description. Think of it like package.json for Kubernetes.
  • values.yaml: Default values for all placeholders. These are overridable per environment.
  • templates/: Kubernetes YAML files with Go template syntax ({{ .Values.replicas }}).
  • values-dev.yaml, values-prod.yaml: Environment-specific value overrides.

When you run helm install, Helm:

  1. Reads Chart.yaml to understand the chart
  2. Loads values.yaml (default values)
  3. Merges in environment-specific values (e.g., values-prod.yaml)
  4. Processes templates/ files, substituting values into placeholders
  5. Applies the rendered YAML to Kubernetes

Deploying a Public Chart: Bitnami Redis

Before creating your own chart, let's deploy a public chart to understand how Helm works.

The Bitnami Helm repository provides production-ready charts for common applications. Let's add it and install Redis:

Step 1: Add the Bitnami Repository

Specification
helm repo add bitnami https://charts.bitnami.com/bitnami

Output:

Specification
"bitnami" has been added to your repositories

Step 2: Update Repository Index

Specification
helm repo update

Output:

text
Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "bitnami" chart repository Update Complete. ⎉ Happy Helming!

Step 3: Search for Redis Chart

Specification
helm search repo bitnami/redis

Output:

text
NAME CHART VERSION APP VERSION DESCRIPTION bitnami/redis 18.6.0 7.2.4 Redis(TM) is an open source, advanced key-value ...

Step 4: Install the Chart

Specification
helm install my-redis bitnami/redis \ --set auth.enabled=false \ --set replica.replica Count=1 \ --namespace default

Output:

text
NAME: my-redis LAST DEPLOYED: Mon Dec 23 10:45:32 2024 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: redis CHART VERSION: 18.6.0 APP VERSION: 7.2.4 ** Please be patient while the chart is being deployed ** Redis™ can be accessed via port 6379 on the following DNS name from within your cluster: my-redis-master.default.svc.cluster.local To get your Redis™ connection string: export REDIS_URL="redis://my-redis-master.default.svc.cluster.local:6379" To connect to your Redis™ instance, run the following commands: kubectl run --namespace default redis-cli --rm --tty -i --restart='Never' -- redis-cli -h my-redis-master.default.svc.cluster.local -p 6379

Step 5: Verify the Deployment

Specification
kubectl get pods -n default

Output:

Specification
NAME READY STATUS RESTARTS AGEmy-redis-master-0 1/1 Running 0 45s
Specification
helm list

Output:

text
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION my-redis default 1 2024-12-23 10:45:32 +0000 UTC deployed redis-18.6.0 7.2.4

You deployed a production-grade Redis instance with a single helm install command. Helm templated all the Redis manifests, applied them to Kubernetes, and created a release called my-redis that you can upgrade, downgrade, or rollback.


Creating Your Own Helm Chart

Now you'll create a custom chart for your Task API from Chapter 79. Instead of managing raw YAML files, you'll use Helm's templating to create a reusable package.

Step 1: Generate Chart Scaffold

Helm provides a generator to create the basic chart structure:

Specification
helm create task-api-chart

Output:

Specification
Creating task-api-chart
Specification
tree task-api-chart

Output:

text
task-api-chart/ ├── Chart.yaml ├── charts ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── hpa.yaml │ ├── ingress.yaml │ ├── service.yaml │ ├── serviceaccount.yaml │ └── tests │ └── test-connection.yaml └── values.yaml

Step 2: Examine Chart.yaml

Specification
cat task-api-chart/Chart.yaml

Output:

yaml
apiVersion: v2 name: task-api-chart description: A Helm chart for Kubernetes type: application version: 0.1.0 appVersion: "1.16"

This declares the chart metadata. Update it for your Task API:

yaml
apiVersion: v2 name: task-api description: "Helm chart for deploying Task API on Kubernetes" type: application version: 0.1.0 appVersion: "1.0.0" keywords: - task-api - fastapi - kubernetes maintainers: - name: "Your Name" email: "your.email@example.com"

Step 3: Examine values.yaml

Specification
cat task-api-chart/values.yaml

Output:

yaml
replicaCount: 1 image: repository: nginx pullPolicy: IfNotPresent tag: "" imagePullSecrets: [] nameOverride: "" fullnameOverride: "" serviceAccount: create: true annotations: {} name: "" podAnnotations: {} podSecurityContext: {} securityContext: {} service: type: ClusterIP port: 80 ingress: enabled: false className: "" annotations: {} hosts: - host: chart-example.local paths: - path: / pathType: ImplementationSpecific tls: [] resources: limits: cpu: 100m memory: 128Mi requests: cpu: 100m memory: 128Mi autoscaling: enabled: false minReplicas: 1 maxReplicas: 100 targetCPUUtilizationPercentage: 80 nodeSelector: {} tolerations: [] affinity: {}

This is the template of all values. Each value is referenced by name in templates (e.g., {{ .Values.replicaCount }}). Update values.yaml for your Task API:

yaml
replicaCount: 3 image: repository: your-registry/task-api pullPolicy: Always tag: "v1.0.0" imagePullSecrets: - name: registry-secret service: type: ClusterIP port: 8000 targetPort: 8000 resources: limits: cpu: 500m memory: 1Gi requests: cpu: 250m memory: 512Mi env: - name: DATABASE_URL value: "postgresql://localhost:5432/tasks" - name: LOG_LEVEL value: "INFO" - name: API_TIMEOUT value: "30"

Step 4: Examine the Deployment Template

Specification
cat task-api-chart/templates/deployment.yaml

Output:

yaml
apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "task-api-chart.fullname" . }} labels: {{- include "task-api-chart.labels" . | nindent 4 }} spec: {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: matchLabels: {{- include "task-api-chart.selectorLabels" . | nindent 6 }} template: metadata: {{- with .Values.podAnnotations }} annotations: {{- toYaml . | nindent 8 }} {{- end }} labels: {{- include "task-api-chart.selectorLabels" . | nindent 8 }} spec: {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} serviceAccountName: {{ include "task-api-chart.serviceAccountName" . }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: - name: {{ .Chart.Name }} securityContext: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: http containerPort: 8000 protocol: TCP livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /ready port: http initialDelaySeconds: 10 periodSeconds: 5 resources: {{- toYaml .Values.resources | nindent 12 }} env: {{- if .Values.env }} {{- toYaml .Values.env | nindent 10 }} {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.affinity }} affinity: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.tolerations }} tolerations: {{- toYaml . | nindent 8 }} {{- end }}

This template uses Go template syntax:

  • {{ .Values.replicaCount }} — Substitutes the value of replicaCount from values.yaml
  • {{ include "task-api-chart.fullname" . }} — Calls a helper function (defined in _helpers.tpl)
  • {{- if .Values.autoscaling.enabled }} — Conditional: include this section only if autoscaling is enabled
  • {{ toYaml . | nindent 8 }} — Converts a value to YAML and indents it 8 spaces

Step 5: Test Template Rendering

Before deploying, preview what Helm will generate:

Specification
helm template my-release task-api-chart

Output:

yaml
--- # Source: task-api-chart/templates/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: name: my-release-task-api-chart labels: helm.sh/chart: task-api-chart-0.1.0 app.kubernetes.io/name: task-api-chart app.kubernetes.io/instance: my-release app.kubernetes.io/version: "1.0.0" app.kubernetes.io/managed-by: Helm --- # Source: task-api-chart/templates/service.yaml apiVersion: v1 kind: Service metadata: name: my-release-task-api-chart labels: helm.sh/chart: task-api-chart-0.1.0 app.kubernetes.io/name: task-api-chart app.kubernetes.io/instance: my-release app.kubernetes.io/version: "1.0.0" app.kubernetes.io/managed-by: Helm spec: type: ClusterIP ports: - port: 8000 targetPort: http protocol: TCP name: http selector: app.kubernetes.io/name: task-api-chart app.kubernetes.io/instance: my-release --- # Source: task-api-chart/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-release-task-api-chart labels: helm.sh/chart: task-api-chart-0.1.0 app.kubernetes.io/name: task-api-chart app.kubernetes.io/instance: my-release app.kubernetes.io/version: "1.0.0" app.kubernetes.io/managed-by: Helm spec: replicas: 3 selector: matchLabels: app.kubernetes.io/name: task-api-chart app.kubernetes.io/instance: my-release template: metadata: labels: helm.sh/chart: task-api-chart-0.1.0 app.kubernetes.io/name: task-api-chart app.kubernetes.io/instance: my-release app.kubernetes.io/version: "1.0.0" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: my-release-task-api-chart containers: - name: task-api-chart image: "your-registry/task-api:v1.0.0" imagePullPolicy: Always ports: - name: http containerPort: 8000 protocol: TCP livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /ready port: http initialDelaySeconds: 10 periodSeconds: 5 resources: limits: cpu: 500m memory: 1Gi requests: cpu: 250m memory: 512Mi env: - name: MODEL_NAME value: "gpt-4" - name: LOG_LEVEL value: "INFO" - name: API_TIMEOUT value: "30"

Helm rendered the templates with values from values.yaml. The output is valid Kubernetes YAML.


Environment-Specific Values: Dev vs Production

Now create environment-specific value files to customize deployments:

values-dev.yaml

yaml
replicaCount: 1 image: tag: "v1.0.0-dev" resources: limits: cpu: 250m memory: 512Mi requests: cpu: 100m memory: 256Mi env: - name: DATABASE_URL value: "postgresql://localhost:5432/tasks_dev" - name: LOG_LEVEL value: "DEBUG" - name: API_TIMEOUT value: "60"

values-prod.yaml

yaml
replicaCount: 5 image: tag: "v1.0.0" resources: limits: cpu: 1000m memory: 2Gi requests: cpu: 500m memory: 1Gi env: - name: DATABASE_URL value: "postgresql://prod-db:5432/tasks" - name: LOG_LEVEL value: "WARN" - name: API_TIMEOUT value: "30" autoscaling: enabled: true minReplicas: 3 maxReplicas: 10 targetCPUUtilizationPercentage: 70

Deploy to Development

Specification
helm install task-api task-api-chart -f task-api-chart/values-dev.yaml

Output:

text
NAME: task-api LAST DEPLOYED: Mon Dec 23 11:05:22 2024 NAMESPACE: default STATUS: deployed REVISION: 1

Verify the deployment:

Specification
kubectl get deployment task-api

Output:

text
NAME READY UP-TO-DATE AVAILABLE AGE task-api 1/1 1 1 15s

Notice: 1 replica in dev (from values-dev.yaml).

Deploy to Production

Specification
helm install task-api-prod task-api-chart -f task-api-chart/values-prod.yaml

Output:

text
NAME: task-api-prod LAST DEPLOYED: Mon Dec 23 11:06:45 2024 NAMESPACE: default STATUS: deployed REVISION: 1

Verify:

Specification
kubectl get deployment task-api-prod

Output:

text
NAME READY UP-TO-DATE AVAILABLE AGE task-api-prod 5/5 5 5 18s

Notice: 5 replicas in production (from values-prod.yaml).


Release Management: Upgrade, Rollback, Uninstall

A release is an instance of a chart deployed to your cluster. You manage releases with four operations: install, upgrade, rollback, and uninstall.

Install (Create a Release)

Specification
helm install task-api task-api-chart -f task-api-chart/values-prod.yaml

Output:

text
NAME: task-api LAST DEPLOYED: Mon Dec 23 11:15:22 2024 NAMESPACE: default STATUS: deployed REVISION: 1

Upgrade (Update a Release)

You've pushed a new version of your agent image. Update the release to use it:

Specification
helm upgrade task-api task-api-chart \ -f task-api-chart/values-prod.yaml \ --set image.tag="v1.1.0"

Output:

text
Release "task-api" has been upgraded successfully NAME: task-api LAST DEPLOYED: Mon Dec 23 11:16:33 2024 NAMESPACE: default STATUS: deployed REVISION: 2

Notice the revision changed from 1 to 2. Helm tracks every release change.

Verify the rollout:

Specification
kubectl rollout status deployment/task-api

Output:

text
deployment "task-api" successfully rolled out

Check Release History

Specification
helm history task-api

Output:

text
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION 1 Mon Dec 23 11:15:22 2024 superseded task-api-chart-0.1.0 1.0.0 Install complete 2 Mon Dec 23 11:16:33 2024 deployed task-api-chart-0.1.0 1.0.0 Upgrade complete

Rollback (Revert to a Previous Release)

The new version has a bug. Rollback to revision 1:

Specification
helm rollback task-api 1

Output:

text
Rollback was a success Release "task-api" has been rolled back to revision 1

Verify:

Specification
helm history task-api

Output:

text
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION 1 Mon Dec 23 11:15:22 2024 superseded task-api-chart-0.1.0 1.0.0 Install complete 2 Mon Dec 23 11:16:33 2024 superseded task-api-chart-0.1.0 1.0.0 Upgrade complete 3 Mon Dec 23 11:17:45 2024 deployed task-api-chart-0.1.0 1.0.0 Rollback to 1

A new revision (3) was created that rolls back to revision 1's configuration. The agent is now running the old image again.

Uninstall (Delete a Release)

Specification
helm uninstall task-api

Output:

text
release "task-api" uninstalled

All Kubernetes resources created by this release are deleted:

Specification
kubectl get deployment

Output:

text
No resources found in default namespace.

What You've Learned

You now understand:

  • Why Helm exists: It solves the repetitive YAML problem by templating deployments
  • How to install Helm: On macOS, Linux, and verify installation
  • How to deploy public charts: Using helm repo add, helm search, and helm install
  • Chart structure: Chart.yaml, values.yaml, templates/, and helper functions
  • Go template syntax: Substitution ({{ .Values.replicaCount }}), helpers, conditionals
  • Environment-specific values: Creating separate values files for dev/prod deployments
  • Release management: Install, upgrade, rollback, and uninstall operations

With these skills, you can package any Kubernetes application—including your Task API—into a reusable, versioned Helm chart that deploys consistently across environments.