Creating Your Own Helm Chart

idsulik

Suleiman Dibirov

Posted on September 7, 2024

Creating Your Own Helm Chart

While Helm provides a vast ecosystem of pre-built Charts for popular applications, there are times when you need to deploy custom applications or tailor existing ones beyond their default configurations. Creating your own Helm Chart allows you to define, package, and manage your Kubernetes applications with precision and consistency. In this section, we'll walk through the process of creating a custom Helm Chart, customizing its templates, and deploying it to your Kubernetes cluster.

1. Creating a Helm Chart

Helm makes it easy to scaffold a new Chart with the helm create command. This command generates a directory structure with all the necessary files and directories to get you started.

helm create my-app
Enter fullscreen mode Exit fullscreen mode

This command creates a new directory called my-app with the following structure:

my-app/
├── Chart.yaml          # Metadata about the Chart (name, version, etc.)
├── values.yaml         # Default configuration values
├── charts/             # Dependency Charts
├── templates/          # Kubernetes resource templates
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── _helpers.tpl
│   └── ...             # Other template files
└── .helmignore         # Patterns to ignore when packaging the Chart
Enter fullscreen mode Exit fullscreen mode

Key Files and Directories:

  • Chart.yaml: Contains metadata about your Chart, such as its name, version, and description.
  • values.yaml: Holds the default configuration values for your Chart. Users can override these values during installation.
  • templates/: Contains Kubernetes manifest templates that Helm uses to generate the final resource definitions.
  • charts/: Directory for Chart dependencies. If your application relies on other Charts, they can be placed here.
  • .helmignore: Specifies files and directories to exclude when packaging the Chart.

2. Customizing the Templates

The generated templates are generic and need to be customized to fit your application's requirements. Helm uses the Go templating language, which allows you to inject dynamic values and logic into your Kubernetes manifests.

Example: Customizing deployment.yaml

Let's customize the deployment.yaml template to better suit a simple web application.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-app.fullname" . }}
  labels:
    {{- include "my-app.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ include "my-app.name" . }}
      app.kubernetes.io/instance: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ include "my-app.name" . }}
        app.kubernetes.io/instance: {{ .Release.Name }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - containerPort: {{ .Values.service.port }}
          livenessProbe:
            httpGet:
              path: /
              port: {{ .Values.service.port }}
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /
              port: {{ .Values.service.port }}
            initialDelaySeconds: 5
            periodSeconds: 10
Enter fullscreen mode Exit fullscreen mode

Key Customizations:

  • Metadata Naming: Uses helper templates like {{ include "my-app.fullname" . }} to generate consistent and unique names.
  • Replica Count: Configures the number of pod replicas based on values.yaml.
  • Image Configuration: Sets the container image repository, tag, and pull policy from values.yaml.
  • Probes: Defines liveness and readiness probes to ensure the application is running correctly.

Example: Customizing service.yaml

apiVersion: v1
kind: Service
metadata:
  name: {{ include "my-app.fullname" . }}
  labels:
    {{- include "my-app.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: {{ .Values.service.targetPort }}
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: {{ include "my-app.name" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
Enter fullscreen mode Exit fullscreen mode

Key Customizations:

  • Service Type and Ports: Configures the service type (e.g., ClusterIP, NodePort, LoadBalancer) and ports based on values.yaml.
  • Selectors: Ensures the Service targets the correct Pods using labels.

3. Defining Default Values

The values.yaml file holds the default configuration values for your Chart. Users can override these values during installation or upgrade to customize the deployment.

Example values.yaml:

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

replicaCount: 2

image:
  repository: nginx
  tag: stable
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80
  targetPort: 80

ingress:
  enabled: false
  annotations: {}
  hosts:
    - host: chart-example.local
      paths: []
  tls: []

resources: {}
Enter fullscreen mode Exit fullscreen mode

Customizing Values:

  • replicaCount: Number of pod replicas.
  • image: Container image settings.
  • service: Service type and port configurations.
  • ingress: Ingress settings for external access.
  • resources: Resource requests and limits for containers.

4. Packaging and Deploying Your Helm Chart

Once you've customized your Chart, you can package it and deploy it to your Kubernetes cluster.

a. Packaging the Chart

Packaging your Chart creates a .tgz archive that can be shared or stored in a Helm repository.

helm package my-app
Enter fullscreen mode Exit fullscreen mode

This command generates a file like my-app-0.1.0.tgz in your current directory.

b. Installing the Custom Chart

You can install your packaged Chart using the helm install command. If you haven't packaged it, you can also install directly from the Chart directory.

Installing from the Packaged Chart:

helm install my-app-release ./my-app-0.1.0.tgz
Enter fullscreen mode Exit fullscreen mode

Installing Directly from the Chart Directory:

helm install my-app-release ./my-app
Enter fullscreen mode Exit fullscreen mode

Parameters:

  • my-app-release: The name of your Helm release.
  • ./my-app or ./my-app-0.1.0.tgz: Path to your Chart directory or packaged Chart.
c. Verifying the Installation

After installation, verify that your application is running correctly.

helm list
Enter fullscreen mode Exit fullscreen mode
helm status my-app-release
Enter fullscreen mode Exit fullscreen mode

These commands will show the status of your release and the resources created in your Kubernetes cluster.

d. Updating the Chart

If you make changes to your Chart, you can upgrade the release to apply the updates.

  1. Update the Chart Files: Modify the templates or values.yaml as needed.
  2. Upgrade the Release:
   helm upgrade my-app-release ./my-app
Enter fullscreen mode Exit fullscreen mode

If you have packaged the Chart, specify the .tgz file instead:

   helm upgrade my-app-release ./my-app-0.1.0.tgz
Enter fullscreen mode Exit fullscreen mode
e. Sharing Your Chart

To share your custom Chart with others or use it across multiple projects, consider hosting it in a Helm repository. You can use public repositories like Artifact Hub or set up your own private repository.

Adding a Repository:

helm repo add my-repo https://my-repo-url.com/charts
Enter fullscreen mode Exit fullscreen mode

Pushing Your Chart to a Repository:

You can use tools like ChartMuseum to host your own Helm repository or utilize cloud storage solutions.

5. Best Practices for Creating Helm Charts

Creating effective Helm Charts involves following best practices to ensure your Charts are maintainable, reusable, and user-friendly.

  • Use Meaningful Defaults: Set sensible default values in values.yaml to make your Chart easy to use out of the box.
  • Template Helpers: Utilize helper templates (_helpers.tpl) to avoid repetition and maintain consistency across your templates.
  • Versioning: Follow semantic versioning in Chart.yaml to manage changes and compatibility.
  • Documentation: Provide clear documentation within your Chart, including comments in values.yaml and a README.md file.
  • Validation: Implement schema validation for your values.yaml to catch configuration errors early.
  • Modularity: Break down complex applications into sub-Charts or use dependencies to promote reusability.

Example: Using Helper Templates

In templates/_helpers.tpl:

{{/*
Return the name of the Chart.
*/}}
{{- define "my-app.name" -}}
{{ .Chart.Name }}
{{- end }}

{{/*
Return the full name of the release.
*/}}
{{- define "my-app.fullname" -}}
{{ .Release.Name }}-{{ .Chart.Name }}
{{- end }}

{{/*
Return common labels.
*/}}
{{- define "my-app.labels" -}}
app.kubernetes.io/name: {{ include "my-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
Enter fullscreen mode Exit fullscreen mode

These helpers streamline the naming and labeling process across your templates, ensuring consistency and reducing duplication.

6. Testing Your Helm Chart

Before deploying your Chart to a production environment, it's essential to test it to ensure it behaves as expected.

a. Linting the Chart

Helm provides a linting tool to check your Chart for common issues.

helm lint ./my-app
Enter fullscreen mode Exit fullscreen mode

This command will analyze your Chart files and report any warnings or errors that need to be addressed.

b. Dry-Run Installation

Perform a dry-run installation to see what resources Helm would create without actually deploying them.

helm install my-app-release ./my-app --dry-run --debug
Enter fullscreen mode Exit fullscreen mode

This is useful for verifying that your templates render correctly with the given values.

c. Unit Testing with Helm Tests

Helm allows you to define tests within your Chart to verify the deployment's functionality.

  1. Create Test Templates: Add test pods in the templates/tests/ directory.

templates/tests/test-connection.yaml:

   apiVersion: v1
   kind: Pod
   metadata:
     name: "{{ include "my-app.fullname" . }}-test-connection"
     labels:
       {{- include "my-app.labels" . | nindent 4 }}
       helm.sh/hook: test
   spec:
     containers:
       - name: wget
         image: busybox
         command: ['wget']
         args: ['{{ include "my-app.fullname" . }}:{{ .Values.service.port }}']
     restartPolicy: Never
Enter fullscreen mode Exit fullscreen mode
  1. Run the Tests:
   helm test my-app-release
Enter fullscreen mode Exit fullscreen mode

Helm will execute the test pods and report the results, helping you verify that your application is functioning as intended.

7. Conclusion

Creating your own Helm Charts empowers you to manage Kubernetes applications with greater control and flexibility. By defining reusable templates, setting configurable values, and adhering to best practices, you can streamline your deployment processes and ensure consistency across environments.

Key Takeaways:

  • Scaffolding: Use helm create to generate the basic structure of a Chart.
  • Customization: Tailor the templates and values.yaml to fit your application's needs.
  • Packaging and Deployment: Package your Chart for distribution and deploy it using Helm commands.
  • Best Practices: Follow guidelines to create maintainable and reusable Charts.
  • Testing: Validate your Charts with linting and Helm tests to ensure reliability.

In the next section, we'll explore Helm repositories in more detail, including how to add, manage, and leverage them to access a wide range of Charts for your Kubernetes deployments.

💖 💪 🙅 🚩
idsulik
Suleiman Dibirov

Posted on September 7, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related