Deploy a Local Helm Chart

KubernetesBeginner
Practice Now

Introduction

The previous deployment labs used raw Kubernetes manifests directly. Helm adds a packaging layer around those manifests. A Helm chart stores related Kubernetes templates together, exposes reusable settings in values.yaml, and installs the rendered objects as a named release.

In this lab, you will build a small local chart instead of downloading one from a repository. You will write the chart metadata, values, Deployment template, and Service template, render the chart before installing it, then upgrade the release by changing values. This keeps the focus on the CKAD skill: understanding how a local chart turns into ordinary Kubernetes objects.

Prepare a Helm Workspace

In this step, you will prepare a namespace and confirm the tools needed for a local Helm chart workflow.

Start in /home/labex/project. This lab keeps the chart directory, generated manifests, and all commands in this workspace.

mkdir -p /home/labex/project
cd /home/labex/project

Check that the Kubernetes API server is reachable. If the VM has just started and the node is not ready yet, wait a few seconds and run the command again.

kubectl get nodes --request-timeout=5s

Expected output includes:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

Wait until the cluster networking Pod is Ready. The chart will create a Service, so application Pods need cluster networking before traffic tests are meaningful.

kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s

Expected output:

pod/calico-node-... condition met

Create a namespace named ckad-prep-helm and set it as the current namespace:

kubectl create namespace ckad-prep-helm
kubectl config set-context --current --namespace=ckad-prep-helm

Confirm both the current namespace and the Helm client. Helm 3 works directly with Kubernetes using your current kubeconfig; there is no separate server-side Tiller component.

kubectl config view --minify --output 'jsonpath={..namespace}'; echo
helm version --short

Expected output includes:

ckad-prep-helm
v...

Create and Render a Local Chart

In this step, you will create a minimal local Helm chart and render it before installing anything.

A chart directory has a few important parts. Chart.yaml describes the chart itself. values.yaml contains default settings. Files under templates/ are Kubernetes manifests with template expressions such as {{ .Values.replicaCount }}. Helm replaces those expressions with concrete values when it renders or installs the chart.

Create the chart directory:

mkdir -p local-web-chart/templates

Write Chart.yaml. The chart name is not the same thing as the release name; the release name is chosen later when you install the chart.

cat > local-web-chart/Chart.yaml <<'EOF'
apiVersion: v2
name: local-web
description: A small local chart for CKAD deployment practice
type: application
version: 0.1.0
appVersion: "1.0"
EOF

Write values.yaml. These defaults control the number of Pods, the container image, the Service ports, and the message served by the application.

cat > local-web-chart/values.yaml <<'EOF'
replicaCount: 2
image:
  repository: busybox
  tag: "1.36"
service:
  port: 80
  targetPort: 8080
message: helm-v1
EOF

Create the Deployment template. The template uses the release name in object names and labels, so the same chart can be installed under different release names.

cat > local-web-chart/templates/deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-web
  labels:
    app.kubernetes.io/name: {{ .Chart.Name }}
    app.kubernetes.io/instance: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ .Chart.Name }}
      app.kubernetes.io/instance: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ .Chart.Name }}
        app.kubernetes.io/instance: {{ .Release.Name }}
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: web
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: IfNotPresent
        command:
        - /bin/sh
        - -c
        - |
          mkdir -p /www
          echo {{ .Values.message | quote }} > /www/index.html
          httpd -f -p {{ .Values.service.targetPort }} -h /www
        ports:
        - containerPort: {{ .Values.service.targetPort }}
        readinessProbe:
          httpGet:
            path: /
            port: {{ .Values.service.targetPort }}
          initialDelaySeconds: 1
          periodSeconds: 2
EOF

Create the Service template. Notice that the Service selector uses the same labels as the Pod template.

cat > local-web-chart/templates/service.yaml <<'EOF'
apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name }}
  labels:
    app.kubernetes.io/name: {{ .Chart.Name }}
    app.kubernetes.io/instance: {{ .Release.Name }}
spec:
  selector:
    app.kubernetes.io/name: {{ .Chart.Name }}
    app.kubernetes.io/instance: {{ .Release.Name }}
  ports:
  - port: {{ .Values.service.port }}
    targetPort: {{ .Values.service.targetPort }}
EOF

Run helm lint to catch chart structure and template problems:

helm lint ./local-web-chart

Expected output includes:

1 chart(s) linted, 0 chart(s) failed

Render the chart locally. helm template prints the Kubernetes YAML that Helm would send to the API server, but it does not create any objects.

helm template local-web ./local-web-chart | sed -n '1,120p'

Expected output includes a Service named local-web and a Deployment named local-web-web.

Install the Chart as a Release

In this step, you will install the local chart into the ckad-prep-helm namespace.

Installing a chart creates a Helm release. The release name is local-web in this lab. Helm records release metadata, and Kubernetes receives ordinary objects such as a Deployment and Service.

Install the chart:

helm install local-web ./local-web-chart

Expected output includes:

NAME: local-web
STATUS: deployed

Wait for the Deployment created by the chart:

kubectl rollout status deployment/local-web-web --timeout=120s

Expected output:

deployment "local-web-web" successfully rolled out

Inspect the release and the Kubernetes objects it created:

helm list
kubectl get deployment,service -l app.kubernetes.io/instance=local-web

Expected output includes:

local-web
deployment.apps/local-web-web
service/local-web

Create a client Pod and send a request to the Service. This confirms that the chart did not only create objects; the installed application is actually reachable.

kubectl run chart-client --image=busybox:1.36 --restart=Never --command -- sleep 3600
kubectl wait --for=condition=Ready pod/chart-client --timeout=120s
kubectl exec chart-client -- wget -qO- http://local-web

Expected output:

helm-v1

Upgrade the Release with New Values

In this step, you will upgrade the existing release by overriding chart values.

The chart already contains reusable templates. You do not need to edit the template files to change the message or replica count. helm upgrade renders the same chart again with new values, updates the Kubernetes objects, and records a new release revision.

Upgrade the release so it serves helm-v2 from three replicas:

helm upgrade local-web ./local-web-chart --set message=helm-v2 --set replicaCount=3

Expected output includes:

Release "local-web" has been upgraded.
STATUS: deployed

Wait for the upgraded Deployment:

kubectl rollout status deployment/local-web-web --timeout=120s

Expected output:

deployment "local-web-web" successfully rolled out

Inspect the release history and the values currently stored with the release:

helm history local-web
helm get values local-web

Expected output includes two revisions and the overridden values:

REVISION
1
2
message: helm-v2
replicaCount: 3

Check the running Deployment and application response:

kubectl get deployment local-web-web
kubectl exec chart-client -- wget -qO- http://local-web

Expected output includes:

3/3
helm-v2

Summary

You created a local Helm chart from chart metadata, default values, and Kubernetes templates. You rendered the chart before installing it, installed it as a release, tested the Service, and upgraded the release by overriding values. The key idea is that Helm packages repeatable application deployment work while still producing ordinary Kubernetes objects you can inspect with kubectl.