Design, organize, and manage Helm charts for templating and packaging Kubernetes applications with reusable configurations. Use when creating Helm charts, packaging Kubernetes applications, or implementing templated deployments.
Install with Tessl CLI
npx tessl i github:wshobson/agents --skill helm-chart-scaffolding89
Does it follow best practices?
If you maintain this skill, you can automatically optimize it using the tessl CLI to improve its score:
npx tessl skill review --optimize ./path/to/skillValidation for skill structure
Comprehensive guidance for creating, organizing, and managing Helm charts for packaging and deploying Kubernetes applications.
This skill provides step-by-step instructions for building production-ready Helm charts, including chart structure, templating patterns, values management, and validation strategies.
Use this skill when you need to:
Helm is the package manager for Kubernetes that:
Create new chart:
helm create my-appStandard chart structure:
my-app/
├── Chart.yaml # Chart metadata
├── values.yaml # Default configuration values
├── charts/ # Chart dependencies
├── templates/ # Kubernetes manifest templates
│ ├── NOTES.txt # Post-install notes
│ ├── _helpers.tpl # Template helpers
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── serviceaccount.yaml
│ ├── hpa.yaml
│ └── tests/
│ └── test-connection.yaml
└── .helmignore # Files to ignoreChart metadata defines the package:
apiVersion: v2
name: my-app
description: A Helm chart for My Application
type: application
version: 1.0.0 # Chart version
appVersion: "2.1.0" # Application version
# Keywords for chart discovery
keywords:
- web
- api
- backend
# Maintainer information
maintainers:
- name: DevOps Team
email: devops@example.com
url: https://github.com/example/my-app
# Source code repository
sources:
- https://github.com/example/my-app
# Homepage
home: https://example.com
# Chart icon
icon: https://example.com/icon.png
# Dependencies
dependencies:
- name: postgresql
version: "12.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
- name: redis
version: "17.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabledReference: See assets/Chart.yaml.template for complete example
Organize values hierarchically:
# Image configuration
image:
repository: myapp
tag: "1.0.0"
pullPolicy: IfNotPresent
# Number of replicas
replicaCount: 3
# Service configuration
service:
type: ClusterIP
port: 80
targetPort: 8080
# Ingress configuration
ingress:
enabled: false
className: nginx
hosts:
- host: app.example.com
paths:
- path: /
pathType: Prefix
# Resources
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
# Autoscaling
autoscaling:
enabled: false
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 80
# Environment variables
env:
- name: LOG_LEVEL
value: "info"
# ConfigMap data
configMap:
data:
APP_MODE: production
# Dependencies
postgresql:
enabled: true
auth:
database: myapp
username: myapp
redis:
enabled: falseReference: See assets/values.yaml.template for complete structure
Use Go templating with Helm functions:
templates/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-app.fullname" . }}
labels:
{{- include "my-app.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "my-app.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "my-app.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- toYaml .Values.env | nindent 12 }}templates/_helpers.tpl:
{{/*
Expand the name of the chart.
*/}}
{{- define "my-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "my-app.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "my-app.labels" -}}
helm.sh/chart: {{ include "my-app.chart" . }}
{{ include "my-app.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "my-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "my-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}Add dependencies in Chart.yaml:
dependencies:
- name: postgresql
version: "12.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabledUpdate dependencies:
helm dependency update
helm dependency buildOverride dependency values:
# values.yaml
postgresql:
enabled: true
auth:
database: myapp
username: myapp
password: changeme
primary:
persistence:
enabled: true
size: 10GiValidation commands:
# Lint the chart
helm lint my-app/
# Dry-run installation
helm install my-app ./my-app --dry-run --debug
# Template rendering
helm template my-app ./my-app
# Template with values
helm template my-app ./my-app -f values-prod.yaml
# Show computed values
helm show values ./my-appValidation script:
#!/bin/bash
set -e
echo "Linting chart..."
helm lint .
echo "Testing template rendering..."
helm template test-release . --dry-run
echo "Checking for required values..."
helm template test-release . --validate
echo "All validations passed!"Reference: See scripts/validate-chart.sh
Package the chart:
helm package my-app/
# Creates: my-app-1.0.0.tgzCreate chart repository:
# Create index
helm repo index .
# Upload to repository
# AWS S3 example
aws s3 sync . s3://my-helm-charts/ --exclude "*" --include "*.tgz" --include "index.yaml"Use the chart:
helm repo add my-repo https://charts.example.com
helm repo update
helm install my-app my-repo/my-appEnvironment-specific values files:
my-app/
├── values.yaml # Defaults
├── values-dev.yaml # Development
├── values-staging.yaml # Staging
└── values-prod.yaml # Productionvalues-prod.yaml:
replicaCount: 5
image:
tag: "2.1.0"
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 20
ingress:
enabled: true
hosts:
- host: app.example.com
paths:
- path: /
pathType: Prefix
postgresql:
enabled: true
primary:
persistence:
size: 100GiInstall with environment:
helm install my-app ./my-app -f values-prod.yaml --namespace productionPre-install hook:
# templates/pre-install-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "my-app.fullname" . }}-db-setup
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
spec:
containers:
- name: db-setup
image: postgres:15
command: ["psql", "-c", "CREATE DATABASE myapp"]
restartPolicy: NeverTest connection:
# templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "my-app.fullname" . }}-test-connection"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "my-app.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: NeverRun tests:
helm test my-app{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "my-app.fullname" . }}
spec:
# ...
{{- end }}env:
{{- range .Values.env }}
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}data:
config.yaml: |
{{- .Files.Get "config/application.yaml" | nindent 4 }}global:
imageRegistry: docker.io
imagePullSecrets:
- name: regcred
# Use in templates:
image: {{ .Values.global.imageRegistry }}/{{ .Values.image.repository }}Template rendering errors:
helm template my-app ./my-app --debugDependency issues:
helm dependency update
helm dependency listInstallation failures:
helm install my-app ./my-app --dry-run --debug
kubectl get events --sort-by='.lastTimestamp'assets/Chart.yaml.template - Chart metadata templateassets/values.yaml.template - Values structure templatescripts/validate-chart.sh - Validation scriptreferences/chart-structure.md - Detailed chart organizationk8s-manifest-generator - For creating base Kubernetes manifestsgitops-workflow - For automated Helm chart deploymentsade0c7a
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.