Skip to main content

Implementing Chart Best Practices

1. Following Naming Conventions

Aspect Convention Notes
Chart Name myapp Use lowercase letters and hyphens only
Version 1.2.3 Follow semantic versioning (MAJOR.MINOR.PATCH)
App Version 2.0.1 Version of the application being deployed
API Version v2 Must be v2 for Helm 3+

Example: Chart Metadata

apiVersion: v2
name: myapp
description: A Helm chart for myapp
version: 1.2.3
appVersion: 2.0.1

2. Using Fullname Templates

Template Description Usage
fullnameOverride Overrides the full name of the release {{- if .Values.fullnameOverride -}}{{ .Values.fullnameOverride }}{{- else }}{{ include "myapp.fullname" . }}{{- end }}
nameOverride Overrides the name of the chart {{- if .Values.nameOverride -}}{{ .Values.nameOverride }}{{- else }}{{ .Chart.Name }}{{- end }}
fullReleaseName Full release name including namespace {{ include "myapp.fullname" . }}-{{ .Release.Namespace }}

Example: Defining fullname template

{{- define "myapp.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
Note: The fullnameOverride and nameOverride values are useful for overriding the release name in specific environments or namespaces.

3. Implementing Proper Labels

Label Key Value Example Description
app.kubernetes.io/name myapp Application name
app.kubernetes.io/instance myapp-production-12345 Unique instance name
app.kubernetes.io/version v1.2.3 Application version
app.kubernetes.io/component frontend Component within the app (e.g., frontend, backend)
app.kubernetes.io/part-of myapp Name of the overall application the chart belongs to
app.kubernetes.io/managed-by helm Tool managing the resource (e.g., helm, kustomize)

Example: Setting Labels in Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "myapp.fullname" . }}
  labels:
    app.kubernetes.io/name: {{ include "myapp.name" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/version: "{{ .Chart.AppVersion }}"
    app.kubernetes.io/component: frontend
    app.kubernetes.io/part-of: myapp
    app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ include "myapp.name" . }}
      app.kubernetes.io/instance: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ include "myapp.name" . }}
        app.kubernetes.io/instance: {{ .Release.Name }}
        app.kubernetes.io/version: "{{ .Chart.AppVersion }}"
        app.kubernetes.io/component: frontend
Note: These labels follow the Kubernetes common labels specification for better integration with tools like Prometheus, Grafana, and other observability systems.

4. Using Annotations Appropriately

Annotation Key Description Example Value Usage Context
helm.sh/chart Identifies the chart name and version "myapp-1.2.3" Required for all charts
app.kubernetes.io/name Name of the application "myapp" Used for labeling and discovery
app.kubernetes.io/version Version of the application "v1.2.3" Used for tracking upgrades
app.kubernetes.io/instance Name of the chart instance "myapp-production" Used to distinguish deployments
app.kubernetes.io/managed-by Tool managing the chart "helm" Used for automation and tracking
meta.helm.sh/release-name Release name of the chart "myapp-release" Used by Helm to identify releases
meta.helm.sh/release-namespace Namespace where the chart is installed "production" Used by Helm to scope releases

Example: Setting Annotations in Chart Metadata

annotations:
  helm.sh/chart: "myapp-1.2.3"
  app.kubernetes.io/name: "myapp"
  app.kubernetes.io/version: "v1.2.3"
  app.kubernetes.io/managed-by: "helm"
Note: Annotations should be used to provide metadata that helps with chart management, tracking, and integration with other tools. Avoid using them for configuration or runtime settings.
Warning: Do not use annotations for sensitive data. Helm does not encrypt or obfuscate annotation values, so they may be visible in logs or UIs.

5. Making Charts Configurable

Property Description Default Value Example
replicaCount Number of replicas for the deployment 1 replicaCount: 3
image.repository Image repository for the application nginx
image:
  repository: myapp
image.tag Image tag to use for the application latest
image:
  tag: v1.2.3
service.type Kubernetes service type (e.g., ClusterIP, NodePort) ClusterIP
service:
  type: NodePort
resources.limits.cpu CPU limit for the pod 500m
resources:
  limits:
    cpu: 1000m
resources.requests.memory Memory request for the pod 256Mi
resources:
  requests:
    memory: 512Mi

Example: Configuring a Chart with Values

replicaCount: 2
image:
  repository: myapp
  tag: v1.0.0
service:
  type: LoadBalancer
resources:
  limits:
    cpu: 1000m
    memory: 1Gi
  requests:
    cpu: 500m
    memory: 256Mi
Note: Values files can be overridden during installation using helm install --set key=value or by providing a custom values file with -f.

Best Practices for Chart Configuration

  • Use values.yaml to define default configuration values.
  • Allow users to override these values via helm install --set or custom values files.
  • Define sensible defaults for common configuration options like replicas, image tags, and resource limits.
  • Use templates/_helpers.tpl to define reusable templates for common patterns.

6. Providing Sensible Defaults

Property Default Value Description
replicaCount 1 Number of replicas for the deployment
image.repository nginx Container image repository name
image.tag latest Container image tag to use
service.type ClusterIP Kubernetes service type to expose the application
service.port 80 Port to expose the service on
resources.limits.cpu 500m CPU limit for the pod
resources.limits.memory 512Mi Memory limit for the pod
resources.requests.cpu 250m CPU request for the pod
resources.requests.memory 256Mi Memory request for the pod

Example: Default Values in a Values File

replicaCount: 1
image:
  repository: nginx
  tag: latest
service:
  type: ClusterIP
  port: 80
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi
Note: Default values should be chosen to provide a working configuration out-of-the-box while allowing customization for specific environments.

7. Documenting Chart Usage

Example: README.md structure

# MyChart

A Helm chart for deploying MyApplication.

## Prerequisites

- Kubernetes 1.20+
- Helm 3.0+

## Installing the Chart

To install the chart:

```bash
helm install my-release ./my-chart
```

## Configuration

The following table lists the configurable parameters of the chart and their default values.

### Parameters

| Name                      | Description                         | Value     |
| ------------------------- | ----------------------------------- | --------- |
| `replicaCount`            | Number of replicas                  | `1`       |
| `image.repository`        | Image repository                    | `nginx`   |
| `image.tag`               | Image tag                           | `latest`  |
Field Description Required Default Value
name Chart name Yes None
version Chart version (SemVer 2) Yes None
appVersion Application version (e.g., 1.2.3) No None
description Short description of the chart No None
keywords List of keywords No None
home Home page URL No None
sources List of source URLs No None
maintainers List of maintainers with name and email No None
Note: The appVersion field should be updated when the application version changes, even if the chart version remains the same.

Example: Values documentation

# Default values for my-chart.
# 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: ""

service:
  type: ClusterIP
  port: 80

# Additional annotations for resources
annotations: {}

8. Creating Comprehensive NOTES.txt

Example: notes.txt content

Thank you for installing {{ .Chart.Name }}.

Your release is named {{ .Release.Name }}.

To learn more about the release, try:

  helm status {{ .Release.Name }}
  helm get all {{ .Release.Name }}

Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
  {{- range $host := .Values.ingress.hosts }}
  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ $host.path }}
  {{- end }}
{{- else if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "myapp.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "myapp.fullname" . }} -o jsonpath="{.status.loadBalancer.ingress[0].hostname}")
  echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "myapp.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
{{- end }}
Field Description Usage
.Chart.Name Name of the chart Used in welcome messages and logs
.Release.Name Name of the release Used to reference specific deployment instance
.Values.ingress.enabled Flag to enable ingress Conditional logic for URL access methods
.Values.service.type Type of Kubernetes service (NodePort, LoadBalancer, ClusterIP) Used to determine how to access the application
Note: The NOTES.txt file is rendered using Go templates and can include any valid Helm template syntax.
Warning: Avoid including sensitive information like passwords or secrets in NOTES.txt.

Best Practices for NOTES.txt

  • Include clear instructions for accessing the deployed application.
  • Use conditional logic to provide relevant information based on configuration values.
  • Provide links or commands that users can run to verify their deployment.
  • Keep the content concise and actionable.

9. Implementing Resource Limits

Resource Type Property Description Example
requests cpu, memory Minimum resources required for pod scheduling
{
  "cpu": "250m",
  "memory": "64Mi"
}
limits cpu, memory Maximum resources a pod can consume
{
  "cpu": "500m",
  "memory": "128Mi"
}

Example: Setting Resource Limits in a Chart

resources:
  requests:
    memory: "64Mi"
    cpu: "250m"
  limits:
    memory: "128Mi"
    cpu: "500m"
Note: Setting resource limits helps prevent pods from consuming too many resources and affecting other pods on the same node.

10. Using Health Checks

Check Type Configuration Description
livenessProbe
livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10
Defines how to check if the pod is alive. If the probe fails, Kubernetes will restart the pod.
readinessProbe
readinessProbe:
  tcpSocket:
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5
Checks if the pod is ready to serve traffic. If the probe fails, the pod will not receive traffic.
startupProbe
startupProbe:
  exec:
    command:
      - cat
      - /tmp/healthy
  initialDelaySeconds: 10
  periodSeconds: 5
Used to determine when a pod is ready to start accepting traffic after startup. It's useful for applications that take time to initialize.

Example: Health Check Configuration in Values.yaml

healthCheck:
  livenessProbe:
    httpGet:
      path: /health
      port: 8080
    initialDelaySeconds: 30
    periodSeconds: 10
  readinessProbe:
    tcpSocket:
      port: 8080
    initialDelaySeconds: 5
    periodSeconds: 5
Note: Ensure that the health check endpoints do not consume excessive resources or block critical operations.
Warning: Misconfigured health checks can lead to unnecessary pod restarts or traffic routing issues.

11. Following Helm Chart Conventions

Convention Description Best Practice
Chart.yaml Contains metadata about the chart Include name, version, appVersion, description, maintainers, keywords, and sources
Values.yaml Default configuration values for the chart Use descriptive names and provide sensible defaults; separate values by component or feature
Templates Directory containing Kubernetes manifests Use templates to make charts reusable; follow naming conventions like deployment.yaml, service.yaml
Notes.txt Post-installation instructions Provide clear, actionable steps for users to access the deployed application

Example: Chart.yaml structure

apiVersion: v2
name: my-app
description: A Helm chart for my application
type: application
version: 1.0.0
appVersion: "1.0"

Example: Values.yaml structure

replicaCount: 1
image:
  repository: nginx
  tag: "1.20"
service:
  type: ClusterIP
  port: 80

Was this article helpful?