Helm-101

Helm-101

Helm is a package manager for Kubernetes, simplifying the deployment and management of applications on Kubernetes clusters. It allows users to define, install, and upgrade even the most complex Kubernetes applications using customizable packages called charts.

Helm charts include all the necessary Kubernetes resources, making it easier to share and reproduce applications across different environments. Helm helps streamline the Kubernetes deployment process and enhances the scalability and maintainability of containerized applications.

Pre-requisites

  1. Kubernetes Cluster:

    • Have a functional Kubernetes cluster for deploying applications.
  2. Helm Installation:

    • Install Helm on your local workstation to manage Kubernetes applications effectively.
  3. Kubernetes Knowledge:

    • Understand basic Kubernetes concepts for effective chart customization.
  4. YAML Proficiency:

    • Be familiar with YAML syntax, crucial for defining Kubernetes resources and Helm charts.

n the context of deploying a basic website frontend using Nginx on Kubernetes, consider the following scenario:

  1. Project Environments:

    • Dev, QA, Staging, and Prod represent distinct environments within the project.
  2. Environment-Specific Parameters:

    • Each environment requires different parameters for Nginx deployment:

      • Dev and QA need only one replica.

      • Staging and Prod involve more replicas with pod autoscaling.

      • Ingress routing rules vary for each environment.

      • Configurations and secrets differ across environments.

  3. Deployment File Management:

    • Managing different Nginx deployment files for each environment can become cumbersome.

    • Writing custom scripts to replace values in a single deployment file based on the environment is not a scalable approach.

  4. Introduction of Helm Chart:

    • Helm charts provide a solution by offering a templated and parameterized structure.

    • With Helm, a single chart can be customized for different environments, reducing the need for separate deployment files.

    • Parameters in Helm charts allow dynamic configuration based on environment, enhancing scalability and maintainability.

Helm charts are packaged combinations of Kubernetes YAML manifest templates and Helm-specific files, simplifying application deployment on Kubernetes clusters. The templating functionality, powered by the Go templating engine, enables dynamic and reusable charts. Rather than maintaining separate charts for each environment, a single Helm chart can be customized using a values file, reducing redundancy and simplifying deployment parameter adjustments. This approach significantly streamlines the deployment process, enhancing efficiency and manageability across different Kubernetes environments. Practical examples in subsequent sections will provide hands-on experience with Helm Charts.

Helm Chart Structure

1. Purpose:

  • Helm charts streamline Kubernetes deployments. For Nginx deployment, traditional YAML files are organized into a structured Helm chart.

nginx-deployment:

nginx-deployment
    ├── configmap.yaml
    ├── deployment.yaml
    ├── ingress.yaml
    └── service.yaml

Helm Structure would look like:

nginx-chart/
|-- Chart.yaml
|-- charts
|-- templates
|   |-- NOTES.txt
|   |-- _helpers.tpl
|   |-- deployment.yaml
|   |-- configmap.yaml
|   |-- ingress.yaml
|   |-- service.yaml
|   `-- tests
|       `-- test-connection.yaml
`-- values.yaml

2. Directory Structure:

  • nginx-deployment:

    • Contains separate YAML files for Nginx deployment.
  • nginx-chart:

    • Helm chart directory structure containing essential files and folders.

3. Files and Directories:

  • .helmignore:

    • Lists files excluded from the Helm chart, functioning like .gitignore.
  • Chart.yaml:

    • Holds chart metadata such as version and description.
  • values.yaml:

    • Defines values for YAML templates, facilitating customization for different environments.
  • charts:

    • Directory for potential dependencies, typically left empty in this example.
  • templates:

    • Contains Kubernetes manifest files templated to access values from values.yaml.

    • NOTES.txt:

      • A plaintext file printed post-deployment, offering additional information.
    • _helpers.tpl:

      • Contains methods and sub-templates available for use in other chart templates.
    • tests/:

      • Allows defining tests to validate chart functionality during installation.

4. Customization:

  • Values.yaml changes for environment-specific configurations.

  • Override values dynamically or during installation using --values or --set commands.

Helm Chart Tutorial GitHub Repo

  • The Helm Chart Tutorial provides an example Helm chart and manifests.
git clone https://github.com/Gatete-Bruno/helm-101.git

Helm Chart From Scratch

  • To create a Helm chart from scratch for Nginx deployment, use the following command
helm create nginx-chart

Output:

nginx-chart
│   ├── Chart.yaml
│   ├── charts
│   ├── templates
│   │   ├── NOTES.txt
│   │   ├── _helpers.tpl
│   │   ├── deployment.yaml
│   │   ├── hpa.yaml
│   │   ├── ingress.yaml
│   │   ├── service.yaml
│   │   ├── serviceaccount.yaml
│   │   └── tests
│   │       └── test-connection.yaml
│   └── values.yaml

I have customized the directory to look like:

kato@master1:~/helm-101/nginx-chart$ tree
.
├── Chart.yaml
├── templates
│   ├── configmap.yaml
│   ├── deployment.yaml
│   ├── helpers.tpl
│   └── service.yaml
└── values.yaml

1 directory, 6 files

Let us breakdown what we have:

  1. Chart.yaml
apiVersion: v2
name: nginx-chart
description: A Helm chart for deploying Nginx on Kubernetes
type: application 
version: 0.1.0
appVersion: "1.0"

This YAML snippet represents the metadata configuration for a Helm chart.

  • apiVersion: v2:

    • Specifies the Helm chart API version in use (version 2).
  • name: nginx-chart:

    • Defines the name of the Helm chart as "nginx-chart."
  • description: A Helm chart for deploying Nginx on Kubernetes:

    • Provides a brief description of the purpose of the Helm chart.
  • type: application:

    • Specifies the type of the Helm chart, indicating that it's designed for deploying applications.
  • version: 0.1.0:

    • Assigns a version number (0.1.0) to the Helm chart.
  • appVersion: "1.0":

    • Specifies the application version (1.0) associated with the Helm chart.

Now let us look at what we have in the templates dir

├── templates
│   ├── configmap.yaml
│   ├── deployment.yaml
│   ├── helpers.tpl
│   └── service.yaml
└── values.yaml

for the configmap.yaml file

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "nginx-chart.fullname" . }}-configmap
  namespace: {{ .Release.Namespace }}
data:
  index.html: |
    <html>
    <h1>Welcome</h1>
    </br>
    <h1>Hi! I got deployed in dev Environment using Helm Chart </h1>
    </html>
  • apiVersion: v1:

    • Specifies the Kubernetes API version for the ConfigMap.
  • kind: ConfigMap:

    • Declares the type of Kubernetes resource as a ConfigMap.
  • metadata:

    • Contains metadata details for the ConfigMap, such as its name and namespace.

    • name: {{ include "nginx-chart.fullname" . }}-configmap:

      • Dynamically generates the ConfigMap name using the "nginx-chart.fullname" template function.
    • namespace: {{ .Release.Namespace }}:

      • Retrieves the namespace from the Helm release configuration.
  • data:

    • Defines key-value pairs for the ConfigMap data.

    • index.html: | ... :

      • Provides HTML content to be stored in the ConfigMap, representing a simple web page.

for deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-nginx
  labels:
    app: nginx
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
  • apiVersion: apps/v1:

    • Specifies the Kubernetes API version for the Deployment.
  • kind: Deployment:

    • Declares the type of Kubernetes resource as a Deployment.
  • metadata:

    • Contains metadata details for the Deployment, including its name and labels.

      • name: {{ .Release.Name }}-nginx:

        • Dynamically generates the Deployment name based on the Helm release.
      • labels: app: nginx:

        • Assigns a label to the Deployment for better identification.
  • spec:

    • Describes the desired state for the Deployment, including the number of replicas.

    • replicas: {{ .Values.replicaCount }}:

      • Retrieves the replica count from the Helm chart values.
    • selector:

      • Specifies the labels used to select which pods are controlled by the Deployment.
    • template:

      • Defines the pod template for the Deployment.

      • metadata: labels: app: nginx:

        • Assigns labels to the pod template for proper identification.
      • spec: containers: ...:

        • Specifies the containers running in the pod, including details like image, ports, and pull policy.

for service.yaml

apiVersion: v1
kind: Service
metadata:
  name: {{ include "nginx-chart.fullname" . }}-service
spec:
  selector:
    app.kubernetes.io/instance: {{ .Release.Name }}
  type: ClusterIP
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  • apiVersion: v1:

    • Specifies the Kubernetes API version for the Service.
  • kind: Service:

    • Declares the type of Kubernetes resource as a Service.
  • metadata:

    • Contains metadata details for the Service, including its name.

      • name: {{ include "nginx-chart.fullname" . }}-service:

        • Dynamically generates the Service name using the "nginx-chart.fullname" template function.
  • spec:

    • Describes the desired state for the Service.

    • selector: app.kubernetes.io/instance: {{ .Release.Name }}:

      • Selects pods with a matching label, associating them with the Service.
    • type: ClusterIP:

      • Specifies that the Service is of type ClusterIP, allowing internal cluster communication.
    • ports:

      • Configures port mappings for the Service.

        • protocol: TCP:

          • Defines the protocol used for the port.
        • port: 80:

          • Specifies the port on which the Service is accessible.
        • targetPort: 80:

          • Directs incoming traffic on the specified port to the target port on the associated pods.

For our values.yaml file

replicaCount: 2

image:
  repository: nginx
  tag: "1.16.0"
  pullPolicy: IfNotPresent

service:
  name: nginx-service
  type: ClusterIP
  port: 80
  targetPort: 9000

env:
  name: dev
  • replicaCount: 2:

    • Specifies the desired number of replicas for a Kubernetes Deployment. In this case, it's set to 2, indicating two replica pods.
  • image:

    • Describes the container image configuration.

      • repository: nginx:

        • Specifies the Docker image repository as "nginx."
      • tag: "1.16.0":

        • Specifies the Docker image tag as version "1.16.0."
      • pullPolicy: IfNotPresent:

        • Defines the policy for pulling the Docker image. In this case, it pulls the image only if it's not present locally.
  • service:

    • Configures the Kubernetes Service associated with the application.

      • name: nginx-service:

        • Specifies the name of the Service as "nginx-service."
      • type: ClusterIP:

        • Sets the Service type to ClusterIP, allowing internal cluster communication.
      • port: 80:

        • Defines the port on which the Service is accessible.
      • targetPort: 9000:

        • Specifies the target port on the associated pods, directing incoming traffic.
  • env:

    • Configures an environment variable.

      • name: dev:

        • Sets an environment variable named "name" with the value "dev."

This is our final output

kato@master1:~/helm-101/nginx-chart$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈
kato@master1:~/helm-101/nginx-chart$
kato@master1:~/helm-101/nginx-chart$

The command helm lint . is used to check the validity of a Helm chart and ensure that all indentations and configurations are correct. It performs a series of checks and provides feedback on potential issues.

The helm install --dry-run command is a useful way to simulate the installation of a Helm chart without actually deploying it to the cluster. It helps in validating the chart's correctness and identifying potential issues before a real deployment.

helm install --dry-run my-release nginx-chart:

The helm install command is used to deploy a Helm chart to a Kubernetes cluster. In your case:

helm install my-nginx nginx-chart-0.1.0.tgz

kato@master1:~/helm-101/nginx-chart$ helm install my-nginx nginx-chart-0.1.0.tgz
NAME: my-nginx
LAST DEPLOYED: Sun Mar 10 11:21:34 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
kato@master1:~/helm-101/nginx-chart$ helm list
NAME        NAMESPACE    REVISION    UPDATED                                    STATUS      CHART                APP VERSION
my-nginx    default      1           2024-03-10 11:21:34.733862264 +0000 UTC    deployed    nginx-chart-0.1.0    1.0

to check for everything deployed on your cluster

kato@master1:~/helm-101/nginx-chart$ kubectl get deployment
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
my-nginx-nginx   0/2     2            0           25s
kato@master1:~/helm-101/nginx-chart$ kubectl get services
NAME                           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes                     ClusterIP   10.233.0.1     <none>        443/TCP   15h
my-nginx-nginx-chart-service   ClusterIP   10.233.9.190   <none>        80/TCP    25s
kato@master1:~/helm-101/nginx-chart$ kubectl get configmap
NAME                             DATA   AGE
kube-root-ca.crt                 1      15h
my-nginx-nginx-chart-configmap   1      25s

Now with Helm we can deploy kubernetes objects and reduce complexity . check out my github for the source code

https://github.com/Gatete-Bruno/helm-101

Cheers 🍻