# Building Your Own Helm Chart

## Building Your Own Helm Chart

Helm charts are a powerful way to package, share, and deploy Kubernetes applications. While using existing charts is beneficial, there are times when you need to create a custom chart tailored to your specific application. In this lesson, we’ll guide you through the process of building your own Helm chart from scratch. By the end of this lesson, you’ll be able to structure a Helm chart, create templates, define default values, and package your chart for deployment.

## **Setting Up Your Environment**

Before you start building your own Helm chart, ensure that your environment is properly set up.

### **Prerequisites**

* **Helm CLI**: Ensure Helm is installed and configured on your local machine.
* **Kubernetes Cluster**: You should have access to a Kubernetes cluster, either locally (e.g., using Minikube) or on the cloud.
* **Text Editor**: Use a code editor like VS Code, Vim, or any other that you prefer.

### **Creating a New Helm Chart**

Helm provides a command to scaffold a new chart directory structure. This command creates all the necessary files and folders for a new chart.

**Command to Create a New Helm Chart:**

```bash
helm create myapp
```

* **`myapp`**: This is the name of your new Helm chart. Helm will create a directory named `myapp` with the basic structure and files inside.

After running this command, you’ll see the following directory structure:

```markdown
codemyapp/
  Chart.yaml
  values.yaml
  charts/
  templates/
    deployment.yaml
    service.yaml
    _helpers.tpl
```

### **Understanding the Helm Chart Structure**

Each Helm chart follows a specific structure, with files and directories that serve distinct purposes. Let’s explore each component:

**`Chart.yaml`**

The `Chart.yaml` file contains metadata about your chart, such as its name, version, and description.

**Example `Chart.yaml`:**

```yaml
apiVersion: v2
name: myapp
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: "1.0"
```

* **`apiVersion`**: Indicates the chart’s API version (usually `v2` for Helm 3).
* **`name`**: The name of your chart.
* **`description`**: A brief description of what your chart does.
* **`type`**: Indicates whether it’s an `application` or a `library`.
* **`version`**: The version of the chart itself.
* **`appVersion`**: The version of the application being deployed.

**`values.yaml`**

The `values.yaml` file defines default configuration values for your chart. These values can be overridden at deployment time.

**Example `values.yaml`:**

```yaml
replicaCount: 2
image:
  repository: nginx
  tag: "1.19.0"
  pullPolicy: IfNotPresent
service:
  type: ClusterIP
  port: 80
resources: {}
```

* **`replicaCount`**: Default number of replicas for the deployment.
* **`image`**: Specifies the default Docker image, tag, and pull policy.
* **`service.type`**: Defines the default service type (e.g., `ClusterIP`).
* **`resources`**: Placeholder for resource requests and limits.

**`templates/` Directory**

This directory contains the Go templates that will be rendered into Kubernetes manifests. These templates define the Kubernetes resources your application will use.

**Common Template Files:**

* **`deployment.yaml`**: Defines the Deployment resource.
* **`service.yaml`**: Defines the Service resource.
* **`_helpers.tpl`**: Contains helper functions for use in your templates.

**Example `deployment.yaml` Template:**

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "myapp.fullname" . }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ include "myapp.name" . }}
  template:
    metadata:
      labels:
        app: {{ include "myapp.name" . }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        ports:
        - containerPort: 80
```

* **`{{ .Values.replicaCount }}`**: Pulls the value from `values.yaml`.
* **`{{ include "myapp.fullname" . }}`**: Uses a helper function defined in `_helpers.tpl` to generate a name.

### **`charts/` Directory**

The `charts/` directory is used to manage dependencies. If your chart depends on other charts, those charts will be stored here.

### **`helpers.tpl`**

The `_helpers.tpl` file is a place to store reusable template code. Functions defined here can be called from other templates within your chart.

**Example `_helpers.tpl` Function:**

```yaml
{{- define "myapp.name" -}}
{{ .Chart.Name | lower }}
{{- end -}}

{{- define "myapp.fullname" -}}
{{ .Release.Name }}-{{ include "myapp.name" . }}
{{- end -}}
```

* **`define`**: Declares a new template function.
* **`include`**: Calls a function defined elsewhere in the chart.

## **Creating and Customizing Templates**

With the basic structure in place, you can now create and customize the templates to define the Kubernetes resources that your application requires.

### **Defining a Deployment Template**

Let’s start by defining a basic Deployment template in `templates/deployment.yaml`.

**Example `deployment.yaml`:**

```yaml
yamlCopy codeapiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "myapp.fullname" . }}
  labels:
    app: {{ include "myapp.name" . }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ include "myapp.name" . }}
  template:
    metadata:
      labels:
        app: {{ include "myapp.name" . }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        ports:
        - containerPort: 80
```

### **Defining a Service Template**

Next, create a Service template in `templates/service.yaml` to expose your application.

**Example `service.yaml`:**

```yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include "myapp.fullname" . }}
  labels:
    app: {{ include "myapp.name" . }}
spec:
  type: {{ .Values.service.type }}
  ports:
  - port: {{ .Values.service.port }}
    targetPort: 80
  selector:
    app: {{ include "myapp.name" . }}
```

* **`type: {{ .Values.service.type }}`**: Configures the service type from `values.yaml`.
* **`port: {{ .Values.service.port }}`**: Sets the service port based on `values.yaml`.

**Adding Custom Logic with Conditionals**

To make your chart more flexible, you can add conditionals in your templates. For example, you might want to add resource limits only if they are specified.

**Example Conditional Logic:**

```yaml
resources:
{{- if .Values.resources.requests }}
  requests:
    cpu: {{ .Values.resources.requests.cpu }}
    memory: {{ .Values.resources.requests.memory }}
{{- end }}
{{- if .Values.resources.limits }}
  limits:
    cpu: {{ .Values.resources.limits.cpu }}
    memory: {{ .Values.resources.limits.memory }}
{{- end }}
```

## **Packaging and Deploying Your Helm Chart**

Once you’ve defined your templates and customized your chart, the next step is to package and deploy it.

### **Packaging Your Chart**

You can package your Helm chart into a `.tgz` file, which can then be distributed or stored in a Helm repository.

**Command to Package a Chart:**

```bash
helm package myapp
```

This command creates a `myapp-0.1.0.tgz` file, which can be shared or uploaded to a Helm repository.

### **Deploying the Packaged Chart**

To deploy your packaged chart, use the `helm install` command, specifying the chart archive and a release name.

**Deploying Your Packaged Chart:**

```bash
helm install my-release ./myapp-0.1.0.tgz
```

Helm will render the templates, create the Kubernetes resources, and track the release.

### **Hands-on Example: Building and Deploying a Simple Web Application**

Let’s build a Helm chart for a simple web application and deploy it to a Kubernetes cluster.

**Steps:**

1. **Create a New Chart**:

   ```bash
   helm create webapp
   ```
2. **Edit the `values.yaml`**: Customize the application’s settings.

   ```yaml
   replicaCount: 3
   image:
     repository: httpd
     tag: "2.4"
   service:
     type: LoadBalancer
     port: 8080
   ```
3. **Customize the Deployment Template**: Ensure the deployment uses the custom settings.
4. **Package the Chart**:

   ```bash
   helm package webapp
   ```
5. **Deploy the Packaged Chart**:

   ```bash
   helm install my-webapp ./webapp-0.1.0.tgz
   ```
6. **Verify the Deployment**:

   ```bash
   helm status my-webapp
   ```

## **Summary**

Building your own Helm chart allows you to create reusable, configurable packages for deploying applications on Kubernetes. By understanding the structure of a Helm chart and how to create and customize templates, you can tailor deployments to fit specific needs, making your Kubernetes applications more flexible and easier to manage.
