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.yaml
Contains information about the Helm chart, like version, name & description. -
values.yaml
Defines 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. -
templates
This directory contains all the Kubernetes manifests used for the application. -
templates/NOTES.txt
Text 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: application
The chart type can be eitherapplication
orlibrary
. 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/