Overview #
- 
A Helm chart is a combination of Kubernetes YAML manifest templates and helm-specific files 
- 
A values file is used to modify the deployment parameters 
- 
Helm takes care of applying the values to the templates 
Helm Chart Overview:
├── charts
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── _helpers.tpl
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── NOTES.txt
│   ├── serviceaccount.yaml
│   ├── service.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml
- 
Chart.yamlContains information about the Helm chart, like version, name & description.
- 
values.yamlDefines the values for the YAML templates, like image name, replica count, etc.
- 
charts (directory)Used to add another charts structure inside this directory if the main charts have some dependency on others. By default this directory is empty.
- 
templatesThis directory contains all the Kubernetes manifests used for the application.
- 
templates/NOTES.txtText file that gets printed out after the chart is successfully deployed.
- 
templates/tests/Used for tests for the chart, that can be defined to validate that the chart works as expected when it is installed.
Create a Helm Chart #
Create an example Helm chart for an Nginx deployment.
Create Helm Chart Blueprint #
Create a new Helm chart with the default files and folders:
# Create a Helm chart blueprint with the name "nginx-helm-chart"
helm create nginx-helm-chart
# Shell output:
Creating nginx-helm-chart
# CD into the chart directory
cd nginx-helm-chart
The file and folder structure looks like this:
├── charts
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── _helpers.tpl
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── NOTES.txt
│   ├── serviceaccount.yaml
│   ├── service.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml
Adopt Helm Chart #
Chart.yaml #
Replace the default contents of Chart.yaml:
# Open Chart.yaml
vi Chart.yaml
apiVersion: v2
name: nginx-helm-chart
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: "1.16.0"
maintainers:
- email: juergen@jklug.work
  name: juergen
#icon: https://example.com/path/to/icon.png
- 
type: applicationThe chart type can be eitherapplicationorlibrary. Application charts are deployed on Kubernetes. Library charts are re-usable charts that can be used with other charts.
- 
version:Defines the chart version.
- 
appVersion:Defines the version number of the application, in this example Nginx.
- 
maintainers:Information about the chart owner.
templates #
# Remove all default files from the template directory
rm -rf templates/*
deployment.yaml #
# Create "deployment.yaml" manifest
vi templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-nginx
  labels:
    app: nginx
    app.kubernetes.io/instance: {{ .Release.Name }}-nginx
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: nginx
      app.kubernetes.io/instance: {{ .Release.Name }}-nginx
  template:
    metadata:
      labels:
        app: nginx
        app.kubernetes.io/instance: {{ .Release.Name }}-nginx
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          volumeMounts:
            - name: nginx-index-file
              mountPath: /usr/share/nginx/html/
      volumes:
        - name: nginx-index-file
          configMap:
            name: {{ .Release.Name }}-index-html-configmap
service.yaml #
# Create "service.yaml" manifest
vi templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name }}-service
spec:
  selector:
    app.kubernetes.io/instance: {{ .Release.Name }}-nginx
  type: {{ .Values.service.type }}
  ports:
    - protocol: {{ .Values.service.protocol | default "TCP" }}
      port: {{ .Values.service.port }}
      targetPort: {{ .Values.service.targetPort }}
configmap.yaml #
# Create "configmap.yaml" manifest
vi templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-index-html-configmap
data:
  index.html: |
    <html>
    <h1>Helm Chart Example</h1>
    </br>
    <h1>Deployed in {{ .Values.env.name }} Environment</h1>
    </html    
values.yaml #
# Create "values.yaml" manifest
vi values.yaml
replicaCount: 2
image:
  repository: nginx
  tag: "1.26.0"
  pullPolicy: IfNotPresent
service:
  name: nginx-service
  type: ClusterIP
  port: 8080
  targetPort: 80
env:
  name: dev
Files And Folder Structure #
The file and folder structure should now look like this:
├── charts
├── Chart.yaml
├── templates
│   ├── configmap.yaml
│   ├── deployment.yaml
│   └── service.yaml
└── values.yaml
Validate the Helm Chart #
Validate the Helm chart syntax and the YML indentations are correct:
# Verify the chart is valid
helm lint .
# Shell output:
==> Linting .
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failed
Validate the template values are getting substituted correctly via the values fined in the values.yaml manifest:
# Render the templated YML manifests
helm template .
Shell output:
---
# Source: nginx-helm-chart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-index-html-configmap
data:
  index.html: |
    <html>
    <h1>Helm Chart Example</h1>
    </br>
    <h1>Deployed in dev Environment</h1>
    </html
---
# Source: nginx-helm-chart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: release-name-service
spec:
  selector:
    app.kubernetes.io/instance: release-name-nginx
  type: ClusterIP
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 80
---
# Source: nginx-helm-chart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: release-name-nginx
  labels:
    app: nginx
    app.kubernetes.io/instance: release-name-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
      app.kubernetes.io/instance: release-name-nginx
  template:
    metadata:
      labels:
        app: nginx
        app.kubernetes.io/instance: release-name-nginx
    spec:
      containers:
        - name: nginx-helm-chart
          image: "nginx:1.26.0"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          volumeMounts:
            - name: nginx-index-file
              mountPath: /usr/share/nginx/html/
      volumes:
        - name: nginx-index-file
          configMap:
            name: release-name-index-html-configmap
Install the Helm Chart #
Dry Run #
# CD out of the Helm chart directory
cd ..
# Start a dry run for the Helm installation of the nginx 
helm install --dry-run development nginx-helm-chart
Shell output:
NAME: development
LAST DEPLOYED: Wed Aug 28 12:44:42 2024
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: nginx-helm-chart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: development-index-html-configmap
data:
  index.html: |
    <html>
    <h1>Helm Chart Example</h1>
    </br>
    <h1>Deployed in dev Environment</h1>
    </html
---
# Source: nginx-helm-chart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: development-service
spec:
  selector:
    app.kubernetes.io/instance: development-nginx
  type: ClusterIP
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 80
---
# Source: nginx-helm-chart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: development-nginx
  labels:
    app: nginx
    app.kubernetes.io/instance: development-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
      app.kubernetes.io/instance: development-nginx
  template:
    metadata:
      labels:
        app: nginx
        app.kubernetes.io/instance: development-nginx
    spec:
      containers:
        - name: nginx-helm-chart
          image: "nginx:1.26.0"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          volumeMounts:
            - name: nginx-index-file
              mountPath: /usr/share/nginx/html/
      volumes:
        - name: nginx-index-file
          configMap:
            name: development-index-html-configmap
Install Helm Chart #
# Install the Helm chart
helm install development nginx-helm-chart \
  --namespace development \
  --create-namespace
# Shell output:
NAME: development
LAST DEPLOYED: Wed Aug 28 12:45:08 2024
NAMESPACE: development
STATUS: deployed
REVISION: 1
TEST SUITE: None
Verify Installation #
# List resources in "development" namespace
kubectl get all -n development
# Shell output:
NAME                                     READY   STATUS    RESTARTS   AGE
pod/development-nginx-75c84bb89d-75h99   1/1     Running   0          60s
pod/development-nginx-75c84bb89d-c4kbf   1/1     Running   0          60s
NAME                          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/development-service   ClusterIP   10.110.120.89   <none>        8080/TCP   60s
NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/development-nginx   2/2     2            2           60s
NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/development-nginx-75c84bb89d   2         2         2       60s
# List ConfigMap
kubectl get configmap -n development
# Shell output:
NAME                               DATA   AGE
development-index-html-configmap   1      65s
Create a portforwarding for the Nginx service and curl the Nginx container:
# Create portforwarding
kubectl port-forward service/development-service 8080:8080 --namespace development
# Curl for the Nginx container (use a new shell)
curl http://localhost:8080
# Shell output:
<html>
<h1>Helm Chart Example</h1>
</br>
<h1>Deployed in dev Environment</h1>
</html
Upgrade Helm Installation #
Create a custom values:
# Create a custom values manifest
vi custom-values.yaml
replicaCount: 3 # Adopt the pod count
image:
  repository: nginx
  tag: "1.26.0"
  pullPolicy: IfNotPresent
service:
  name: nginx-service
  type: ClusterIP
  port: 8080
  targetPort: 80
env:
  name: dev
Upgrade the Helm installation:
# Upgrade the Helm installation
helm upgrade  development nginx-helm-chart \
  --values custom-values.yaml \
  --namespace development
# Shell output:
Release "development" has been upgraded. Happy Helming!
NAME: development
LAST DEPLOYED: Wed Aug 28 12:56:16 2024
NAMESPACE: development
STATUS: deployed
REVISION: 2
TEST SUITE: None
Note that the REVISION number changes to 2.
Verify the Upgraded Installation #
Verify the upgraded pod number in the “development” namespace:
# List pods in "development" namespace
kubectl get pods -n development
# Shell output:
NAME                                 READY   STATUS    RESTARTS   AGE
development-nginx-75c84bb89d-52gt4   1/1     Running   0          105s
development-nginx-75c84bb89d-75h99   1/1     Running   0          12m
development-nginx-75c84bb89d-c4kbf   1/1     Running   0          12m
Rollback the Helm Installation #
# Rollback the Helm chart installation: Define revision number
helm rollback development -n development 1
# Shell output:
Rollback was a success! Happy Helming!
Verify the upgraded pod number in the “development” namespace:
# List pods in "development" namespace
kubectl get pods -n development
# Shell output:
NAME                                 READY   STATUS    RESTARTS   AGE
development-nginx-75c84bb89d-75h99   1/1     Running   0          17m
development-nginx-75c84bb89d-c4kbf   1/1     Running   0          17m
Verify the Rollback #
# List Helm releases / installations
helm list -n development
# Shell output
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
development     development     3               2024-08-28 12:59:43.671536115 +0000 UTC deployed        nginx-helm-chart-0.1.0  1.16.0
Uninstall Helm Chart #
# Uninstall the Helm chart
helm uninstall development -n development
Package Helm Chart #
# Package Helm chart: Define path the Helm chart
helm package nginx-helm-chart/
# Shell output:
Successfully packaged chart and saved it to: /home/ubuntu/Helm/nginx-helm-chart-0.1.0.tgz
# Verify packaged chart
ls -la
# Shell output:
-rw-rw-r-- 1 ubuntu ubuntu  207 Aug 28 12:54 custom-values.yaml
drwxr-xr-x 4 ubuntu ubuntu 4096 Aug 28 12:44 nginx-helm-chart
-rw-rw-r-- 1 ubuntu ubuntu 1210 Aug 28 13:05 nginx-helm-chart-0.1.0.tgz
 
Links #
# Helm Documentation
https://helm.sh/docs/chart_template_guide/builtin_objects/