helm-chart-scaffolding · diff
git:20260307.47a5dbc to git:20260522.be57c0b
2 added, 494 removed. Audit A to A.
---
name: helm-chart-scaffolding
description: 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.
---
# Helm Chart Scaffolding
Comprehensive guidance for creating, organizing, and managing Helm charts for packaging and deploying Kubernetes applications.
## Purpose
This skill provides step-by-step instructions for building production-ready Helm charts, including chart structure, templating patterns, values management, and validation strategies.
## When to Use This Skill
Use this skill when you need to:
- Create new Helm charts from scratch
- Package Kubernetes applications for distribution
- Manage multi-environment deployments with Helm
- Implement templating for reusable Kubernetes manifests
- Set up Helm chart repositories
- Follow Helm best practices and conventions
- ## Helm Overview
-
- **Helm** is the package manager for Kubernetes that:
-
- - Templates Kubernetes manifests for reusability
- - Manages application releases and rollbacks
- - Handles dependencies between charts
- - Provides version control for deployments
- - Simplifies configuration management across environments
-
- ## Step-by-Step Workflow
-
- ### 1. Initialize Chart Structure
-
- **Create new chart:**
-
- ```bash
- helm create my-app
- ```
-
- **Standard 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 ignore
- ```
-
- ### 2. Configure Chart.yaml
-
- **Chart metadata defines the package:**
-
- ```yaml
- 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.enabled
- ```
-
- **Reference:** See `assets/Chart.yaml.template` for complete example
-
- ### 3. Design values.yaml Structure
-
- **Organize values hierarchically:**
-
- ```yaml
- # 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: false
- ```
-
- **Reference:** See `assets/values.yaml.template` for complete structure
-
- ### 4. Create Template Files
-
- **Use Go templating with Helm functions:**
-
- **templates/deployment.yaml:**
-
- ```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 }}
- ```
-
- ### 5. Create Template Helpers
-
- **templates/\_helpers.tpl:**
-
- ```yaml
- {{/*
- 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 }}
- ```
-
- ### 6. Manage Dependencies
-
- **Add dependencies in Chart.yaml:**
-
- ```yaml
- dependencies:
- - name: postgresql
- version: "12.0.0"
- repository: "https://charts.bitnami.com/bitnami"
- condition: postgresql.enabled
- ```
-
- **Update dependencies:**
-
- ```bash
- helm dependency update
- helm dependency build
- ```
-
- **Override dependency values:**
-
- ```yaml
- # values.yaml
- postgresql:
- enabled: true
- auth:
- database: myapp
- username: myapp
- password: changeme
- primary:
- persistence:
- enabled: true
- size: 10Gi
- ```
-
- ### 7. Test and Validate
-
- **Validation commands:**
-
- ```bash
- # 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-app
- ```
-
- **Validation script:**
-
- ```bash
- #!/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`
-
- ### 8. Package and Distribute
-
- **Package the chart:**
-
- ```bash
- helm package my-app/
- # Creates: my-app-1.0.0.tgz
- ```
-
- **Create chart repository:**
-
- ```bash
- # 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:**
-
- ```bash
- helm repo add my-repo https://charts.example.com
- helm repo update
- helm install my-app my-repo/my-app
- ```
-
- ### 9. Multi-Environment Configuration
-
- **Environment-specific values files:**
-
- ```
- my-app/
- ├── values.yaml # Defaults
- ├── values-dev.yaml # Development
- ├── values-staging.yaml # Staging
- └── values-prod.yaml # Production
- ```
-
- **values-prod.yaml:**
-
- ```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: 100Gi
- ```
-
- **Install with environment:**
-
- ```bash
- helm install my-app ./my-app -f values-prod.yaml --namespace production
- ```
-
- ### 10. Implement Hooks and Tests
-
- **Pre-install hook:**
-
- ```yaml
- # 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: Never
- ```
-
- **Test connection:**
-
- ```yaml
- # 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: Never
- ```
-
- **Run tests:**
-
- ```bash
- helm test my-app
- ```
-
- ## Common Patterns
-
- ### Pattern 1: Conditional Resources
-
- ```yaml
- {{- if .Values.ingress.enabled }}
- apiVersion: networking.k8s.io/v1
- kind: Ingress
- metadata:
- name: {{ include "my-app.fullname" . }}
- spec:
- # ...
- {{- end }}
- ```
-
- ### Pattern 2: Iterating Over Lists
-
- ```yaml
- env:
- {{- range .Values.env }}
- - name: {{ .name }}
- value: {{ .value | quote }}
- {{- end }}
- ```
-
- ### Pattern 3: Including Files
-
- ```yaml
- data:
- config.yaml: |
- {{- .Files.Get "config/application.yaml" | nindent 4 }}
- ```
-
- ### Pattern 4: Global Values
-
- ```yaml
- global:
- imageRegistry: docker.io
- imagePullSecrets:
- - name: regcred
+ ## Detailed patterns and worked examples
- # Use in templates:
- image: {{ .Values.global.imageRegistry }}/{{ .Values.image.repository }}
- ```
+ Detailed pattern documentation lives in `references/details.md`. Read that file when the navigation tier above is insufficient.
## Best Practices
1. **Use semantic versioning** for chart and app versions
2. **Document all values** in values.yaml with comments
3. **Use template helpers** for repeated logic
4. **Validate charts** before packaging
5. **Pin dependency versions** explicitly
6. **Use conditions** for optional resources
7. **Follow naming conventions** (lowercase, hyphens)
8. **Include NOTES.txt** with usage instructions
9. **Add labels** consistently using helpers
10. **Test installations** in all environments
## Troubleshooting
**Template rendering errors:**
```bash
helm template my-app ./my-app --debug
```
**Dependency issues:**
```bash
helm dependency update
helm dependency list
```
**Installation failures:**
```bash
helm install my-app ./my-app --dry-run --debug
kubectl get events --sort-by='.lastTimestamp'
```
## Related Skills
- `k8s-manifest-generator` - For creating base Kubernetes manifests
- `gitops-workflow` - For automated Helm chart deployments