In this article, we'll guide you through the step-by-step process of creating your own Helm Chart for Kubernetes
You can find source code in our Github repo
Prerequisites:
AWS EKS Cluster
: Ensure that you have an AWS Elastic Kubernetes Service (EKS) cluster up and running. If you haven't created one yet, you can refer to this article for step-by-step instructions.kubectl
: Install and configure kubectl, the command-line tool for interacting with your EKS cluster. You can follow the official Kubernetes documentation on Installing kubectl for installation instructions.Helm
: Install Helm, the package manager for Kubernetes. Helm simplifies deploying and managing applications on Kubernetes. You can find installation instructions for Helm on the official Helm websiteAWS CLI
: Ensure that you have the AWS Command Line Interface (CLI) installed and configured with the necessary IAM permissions. This is required for managing AWS resources related to your EKS cluster. Install the AWS CLI by following the official AWS documentation
Create Helm Chart
Create a Helm Chart:
When all our prerequisites are met, we can go to our project folder and run:
helm create mychart
This command will create a directory with the following content:
Charts
directory – is where you can place sub-charts that your main Helm chart depends on. Sub-charts are essentially reusable Helm charts that can be included and managed within your primary Helm chart. Empty by default.
Templates
directory – is a crucial part of a Helm chart, containing Kubernetes YAML template files. These templates define how Kubernetes resources (such as pods, services, config maps, and more) should be created within the cluster when the Helm chart is installed or upgraded
Chart.yaml
file – serves as the metadata and configuration file for the Helm chart. It provides essential information about the chart, such as its name, version, description, and maintainers.
values.yaml
file – contains default configuration values for your Helm chart. These values can be overridden by users during installation or upgrade, allowing for customization without modifying the Helm chart itself
Apply our chart
We can install our chart from scratch, run:
helm install mychart ./mychart
You will see similar output:
NAME: mychart
LAST DEPLOYED: Wed Oct 11 13:06:49 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=mychart,app.kubernetes.io/instance=mychart" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT
To check if it is deployed to cluster run:
helm status mychart
You see same output as before, meaning that your chart is installed
Editing default Helm Chart:
Now we would create a new chart which we would configure for our needs:
helm create mywebapp
Edit the mywebapp/Chart.yaml
file to define metadata for your chart:
apiVersion: v2
appVersion: 0.1.0
description: A Helm chart installing Demo App onto Kubernetes cluster
name: apps
type: application
version: 0.1.0
Create Kubernetes Resources
Edit the mywebapp/templates directory to define the Kubernetes resources for your web application. For simplicity, we'll create a Deployment and a Service.
Navite to mywebapp/templates/deployment.yaml
and replace default data with your own:
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: {{ .Values.service.namespace }}
name: {{ .Values.service.name }}
labels:
app: {{ .Values.service.name }}
spec:
replicas: 2
selector:
matchLabels:
app: {{ .Values.service.name }}
template:
metadata:
labels:
app: {{ .Values.service.name }}
spec:
containers:
- name: nginx
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
imagePullPolicy: {{.Values.image.imagePullPolicy}}
ports:
- containerPort: {{ .Values.service.targetPort}}
resources:
requests:
memory: {{ .Values.service.resources.memoryMiB }}Mi
cpu: {{ .Values.service.resources.cpuMilli }}m
limits:
memory: {{ .Values.service.resources.memoryMiB }}Mi
cpu: {{ .Values.service.resources.cpuMilli }}m
In mywebapp/templates/service.yaml
do the same:
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.service.name }}
namespace: {{ .Values.service.namespace }}
labels:
app: {{ .Values.service.name }}
service: {{ .Values.service.name }}
spec:
selector:
app: {{ .Values.service.name }}
ports:
- name: http
port: {{ .Values.service.svcPort}}
targetPort: {{ .Values.service.targetPort}}
type: ClusterIP
These templates define a Deployment with two replicas and a Service for your web application using an NGINX image. As you can see we didn't hardcode some values. For example expression {{ .Values.service.name }}
is used to access a specific value from the values.yaml file. In this case, it's accessing a value nested under the service section of the values.yaml
file
Customize Values
Now let's define our values in the mywebapp/values.yaml
file. Leave defaults, just replace image and service section with this:
image:
repository: nginx
tag: latest
imagePullPolicy : Always
service:
name: my-app
namespace: default
svcPort: 80
targetPort: 80
resources:
memoryMiB: 100
cpuMilli: 200
Customizing Notes.txt
You may noticed while installing default Helm Chart that we had some otputs.
The NOTES.txt file in a Helm chart serves as a post-installation message or guide that is displayed after a Helm release has been successfully installed or upgraded. It typically contains helpful information and instructions for users and administrators regarding the release that was just deployed.
Let's customize it. Open mywebapp/templates/NOTES.txt
and paste following content:
Thank you for installing {{ .Values.service.name }}.
Your release is named {{ .Release.Name }}.
To learn more about the release, try:
$ helm status {{ .Release.Name }}
$ helm get all {{ .Release.Name }}
Port forward the service to localhost port :
kubectl port-forward service/{{ .Values.service.name }} 20043:{{ .Values.service.svcPort}} -n {{ .Values.service.namespace }}
We are using kubectl port-forward service/{{ .Values.service.name }} 20043:{{ .Values.service.svcPort}} -n {{ .Values.service.namespace }}
to create a network proxy that listens on our local port 20043 and forwards any incoming traffic to the specified Kubernetes service. The service name, port, and namespace are determined by the values in the Helm chart's values.yaml
file. This allows us to access a service running in a Kubernetes cluster as if it were running locally on your machine. We would use it to access our app later.
Install the Chart
Now we can install it to our connected cluster:
helm install mywebapp ./
Now let's check other command, which is very usefull as it not only installing chart but also upgrade it if any changes made, so you would not need to uninstall it every time you do some updates:
helm upgrade mywebapp ./
You should see the following output:
Release "mywebapp" has been upgraded. Happy Helming!
NAME: mywebapp
LAST DEPLOYED: Thu Oct 12 13:47:59 2023
NAMESPACE: default
STATUS: deployed
REVISION: 10
NOTES:
Thank you for installing my-app.
Your release is named mywebapp.
To learn more about the release, try:
$ helm status mywebapp
$ helm get all mywebapp
Port forward the service to localhost port :
kubectl port-forward service/my-app 20043:80 -n default
Verification
Now we can check if everything is working as expected. Run:
kubectl get services -A
Also you can check if you release is up and running, as it mentioned in the output when installed or upgraded, with this cammands:
helm get all mywebapp -A
You should see your service is up and running.
Now copy generated command from the output of and run it in your terminal:
helm status mywebapp
kubectl port-forward service/my-app 20043:80 -n default
Open your browser and navigate to localhost:20043
, you should see Nginx Welcome page from your cluster
You can find source code in our Github repo
ADDD RESOURCES CPU AND MEMORY