AdBlock Detected

It looks like you're using an ad-blocker!

Our team work realy hard to produce quality content on this website and we noticed you have ad-blocking enabled. Advertisements and advertising enable us to continue working and provide high-quality content.

How-to-create-Helm-Chart-for-Kubernetes.jpeg

A significant part of my day used to be spent creating different Kubernetes objects like deployments, config maps, secrets, services, etc. This is a somewhat tedious and sometimes repetitive task where mistakes can easily occur. It is in situations like these that we should make use of and create a Helm Chart for Kubernetes. Helm Charts help us coordinate the download, installation, and deployment of our applications. In the following points, we will go through the necessary steps to understand how to create a Helm Chart for Kubernetes.

Why should one use Helm?

About why we should use Helm, the answer is quite simple: for simplicity and because it will make our work much easier. Helm manages deployments in Kubernetes through templates. It provides a flexible structure so that we can run any type of application in our Kubernetes cluster. It even allows versioning of our templates, enabling us to have different deployments in a simple and effective manner.

In the world of development and infrastructure, the goal is to avoid manual tasks whenever possible, as they can lead to errors. That’s why, by applying Helm charts, we can eliminate errors and deploy in a simple and secure way.

Hands on

In this example, we will create a Helm example with Minikube. Click here to install Minikube and here to configure and install Helm.

If everything is installed and configured, let’s start by launching our Minikube.

minikube start
How to Create a Helm Chart for Kubernetes
Minikube start

And next, we are going to initialize the creation of a new Helm chart named chartexample:

helm create chartexample

Once created, we can verify the files and folders:

$ ls chartexample
charts  Chart.yaml  templates  values.yaml

Helm Chart Structure

Once we have created our Helm chart with the previous command, we will see two files and two folders. Let’s go through each one.

If we open Chart.yaml, we will see the following:

apiVersion: v2
name: chartexample
description: A Helm chart for Kubernetes

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"

In the file, we see a series of attributes, starting with the API version, the chart name, and a description. Next, we see the type of chart, which is application by default, and the chart and application versions.

Now, let’s move to the /templates folder, which could be said to be where all the logic resides to deploy our application. It contains files for Kubernetes objects; if you take a look, you’ll find a deployment, ingress, a service, a service account, a horizontal pod autoscaler, and a tests folder.

If we continue exploring, we will find an empty folder named charts. This folder will be useful for adding charts that are necessary or that our application depends on.

Next, let’s analyze where the logic and configuration reside to generate a template—the values.yaml file.

Analyze values.yaml File in Helm Chart

The values.yaml file provides a template format where we can configure our Kubernetes objects.

# Default values for chartexample.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

image:
  repository: nginx
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  tag: ""

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: ""

podAnnotations: {}

podSecurityContext: {}
  # fsGroup: 2000

securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
  className: ""
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  hosts:
    - host: chart-example.local
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

resources: {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #   cpu: 100m
  #   memory: 128Mi
  # requests:
  #   cpu: 100m
  #   memory: 128Mi

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  # targetMemoryUtilizationPercentage: 80

nodeSelector: {}

tolerations: []

affinity: {}

In the above configuration file, we can see that it is structured to add a service, an ingress, autoscaling, affinity, etc. Let’s analyze and define each part of our values.yaml file.

Pod configuration

The first part of our values file contains information related to Pod configuration.

The first parameter we encounter is replicaCount, which indicates the number of replicas for the pod; by default, it sets it to 1.

Next, we have the image definition, where it defaults to the nginx image and the pullPolicy is set to IfNotPresent, which we will change to always for our example.

Secrets

Next, we have imagePullSecrets; in this section, any password or tokens can be defined.

Names

The next section we encounter is related to nameOverride and fullnameOverride. In this section, we can change the name of the chart that we created with the helm create command.

Service Account

By default, it will generate a service account based on the full name we have defined. The best and most recommended practice is to generate your own and define the desired permissions.

Security

In the securityContext and podSecurityContext section, limits on users or which file groups can be used or not will be defined.

Network

The next part we will look at is service and ingress. Regarding the service, we can define ClusterIP or NodePort. We will use NodePort in our example, as it will expose the service on each Kubernetes node’s IP address with a fixed port.

As for the ingress, we will leave it as false by default.

Resource


In the resources section, we will define the resource limits to be used. By default, it is empty, but it is advisable to fill it in. In our example, we will define 100m of CPU and 128Mi of memory.

Autoscaling

The next parameter we encounter is autoscaling, which is disabled by default and, once enabled, will work based on certain parameters.

Tolerations, node selectors, and affinities

Next, we will see the last three sections, which are empty by default.

As we explained in a previous article, nodeSelector is used when assigning our application or pods to specific nodes in our Kubernetes cluster.

Tolerations and affinities will ensure that our pods are running on different nodes.

In our example, for simplicity, we will leave it with the default configuration.

Deploying with Helm

Next, we are going to deploy an nginx with the modifications we have indicated earlier:

# Default values for chartexample.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

image:
  repository: nginx
  pullPolicy: Always
  # Overrides the image tag whose default is the chart appVersion.
  tag: ""

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: ""

podAnnotations: {}

podSecurityContext: {}
  # fsGroup: 2000

securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000

service:
  type: NodePort
  port: 80

ingress:
  enabled: false
  className: ""
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  hosts:
    - host: chart-example.local
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

resources: 
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  limits:
    cpu: 100m
    memory: 128Mi
  requests:
    cpu: 100m
    memory: 128Mi

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  # targetMemoryUtilizationPercentage: 80

nodeSelector: {}

tolerations: []

affinity: {}

To perform an installation with Helm, we will use the following command:

helm install helm-example chartexample/ --values chartexample/values.yaml

and if everything goes well, it should display the following output:

NAME: helm-example
LAST DEPLOYED: Fri Jun 11 13:17:17 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services helm-example-chartexample)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT

Once the above commands are executed, we should obtain the IP and the running port to view the nginx page:

Nginx with Helm | How to Create a Helm Chart for Kubernetes
Nginx with Helm

Conclusion

Throughout this article on how to create a Helm Chart for Kubernetes, we have seen how we can deploy an application using Helm and its templates. This will assist us in repetitive tasks or when we need to deploy applications with similar characteristics.

Another example where we have used Helm is in autoscaling with Spring Boot and Prometheus.

Leave a Reply

Your email address will not be published. Required fields are marked *