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.tag | Image tag to use for the application | latest |
|
| service.type | Kubernetes service type (e.g., ClusterIP, NodePort) | ClusterIP |
|
| resources.limits.cpu | CPU limit for the pod | 500m |
|
| resources.requests.memory | Memory request for the pod | 256Mi |
|
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.yamlto define default configuration values. - Allow users to override these values via
helm install --setor custom values files. - Define sensible defaults for common configuration options like replicas, image tags, and resource limits.
- Use
templates/_helpers.tplto 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 | |
| limits | cpu, memory |
Maximum resources a pod can consume | |
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 | |
Defines how to check if the pod is alive. If the probe fails, Kubernetes will restart the pod. |
| readinessProbe | |
Checks if the pod is ready to serve traffic. If the probe fails, the pod will not receive traffic. |
| startupProbe | |
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 |