---
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

## Chart Complexity Classification

Before starting, classify your chart to determine the appropriate approach:

| Level | Characteristics | CI Handling | Example |
|-------|-----------------|-------------|---------|
| **Simple** | Single container, no external deps, standard probes | Full lint + install | Static site, simple API |
| **Standard** | Multiple resources, ConfigMaps/Secrets, optional deps | Full lint + install | Web app with ingress |
| **Complex** | External services required, multi-port, JVM config | Lint only, skip install | OpenMetadata, data platforms |
| **Operator** | CRDs, webhooks, cluster-wide resources | Lint only, manual test | Prometheus Operator |

**Quick Decision:**
- Needs database/search/messaging at runtime? → **Complex** (exclude from install tests)
- Has admin port separate from main port? → Check `assets/patterns/multi-port-service.yaml`
- JVM application? → Check `assets/patterns/jvm-application.yaml`

> **Details**: See `references/chart-complexity.md` for full classification guide and CI configuration.

## Research Strategy

Before creating a chart, research the application:

1. **Check for official chart** - Many projects maintain their own Helm charts
2. **Review Docker documentation** - Container entrypoint, environment variables, ports
3. **Identify external dependencies** - What services does the app need?

**If documentation scraping fails**, use alternative methods:
- Search GitHub for existing implementations
- Check Docker Hub for environment variable documentation
- Review Kubernetes deployment examples in project repos

> **Details**: See `references/research-strategy.md` for complete fallback strategies and information gathering checklist.

## Structured Development Workflow

For complex charts or when contributing to existing projects, use a structured approach:

### Workflow Selection

| Chart Complexity | Official Chart Exists | Workflow |
|------------------|----------------------|----------|
| Simple/Standard | No | **Fast Path** - Quick research, create, validate |
| Simple/Standard | Yes (use as-is) | **Skip** - Use existing chart |
| Complex/Operator | No | **Full Workflow** - Research → Plan → Implement |
| Any | Yes (extend) | **Full Workflow** with contribution strategy |

### Research Phase

Systematically investigate the application before creating templates:
1. Check for existing charts (official, community)
2. Gather configuration details (image, ports, env vars)
3. Document findings in structured format
4. Get approval for complex applications

> **Details**: See `references/research-phase-workflow.md`

### Planning Phase

Translate research into actionable implementation plan:
1. Create high-level plan with target features
2. Break down into atomic components (phases)
3. Draft phase plans for each component
4. Get sequential approvals
5. Map plans to GitHub issues (optional)

> **Details**: See `references/planning-phase-workflow.md`

### Implementation Phase

Execute with quality gates and review checkpoints:
1. Create worktree and draft PR immediately
2. Implement following phase plan
3. Run sanity checks (lint, template, security)
4. Pause for external review when needed
5. Submit PR when complete, clean up worktree

> **Details**: See `references/implementation-workflow.md`

### Extending Existing Charts

When an official chart exists but needs improvements:
1. Decide: fork repo vs copy locally
2. Review upstream patterns and values schema
3. Maintain compatibility for contribution
4. Document differences and improvements
5. Prepare upstream contribution (PR or patch)

> **Details**: See `references/extend-contribute-strategy.md`

## 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

# Use in templates:
image: {{ .Values.global.imageRegistry }}/{{ .Values.image.repository }}
```

## Pattern Templates

Ready-to-use patterns for common scenarios. Copy values and template sections to your chart.

### External Services

| Pattern | Use When | File |
|---------|----------|------|
| Database | Chart connects to MySQL or PostgreSQL | `assets/patterns/external-database.yaml` |
| Search | Chart connects to Elasticsearch or OpenSearch | `assets/patterns/external-search.yaml` |
| Messaging | Chart connects to Airflow, Kafka, RabbitMQ, or Redis | `assets/patterns/external-messaging.yaml` |

All patterns include:
- Values structure with `existingSecret` support
- Helper template functions
- Environment variable configuration
- Example configurations

### Application Architecture

| Pattern | Use When | File |
|---------|----------|------|
| Multi-Port Service | App has main + admin/metrics ports | `assets/patterns/multi-port-service.yaml` |
| JVM Application | Java/Kotlin/Scala app needing heap/GC config | `assets/patterns/jvm-application.yaml` |
| Health Probes (Multi-Port) | Different probes on different ports | `assets/patterns/health-probes-multiport.yaml` |

### Quick Reference

For port numbers, environment variables, and connection strings:
- `references/external-services.md` - Common services reference table

## 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'
```

## Reference Files

### Chart Templates
- `assets/Chart.yaml.template` - Chart metadata template
- `assets/values.yaml.template` - Values structure template

### Pattern Files
- `assets/patterns/external-database.yaml` - MySQL/PostgreSQL configuration
- `assets/patterns/external-search.yaml` - Elasticsearch/OpenSearch configuration
- `assets/patterns/external-messaging.yaml` - Airflow/Kafka/RabbitMQ/Redis configuration
- `assets/patterns/multi-port-service.yaml` - Multiple ports pattern
- `assets/patterns/jvm-application.yaml` - JVM heap/GC/JMX configuration
- `assets/patterns/health-probes-multiport.yaml` - Probes on different ports

### Workflow Templates
- `assets/templates/research-summary.md` - Research findings documentation
- `assets/templates/high-level-plan.md` - High-level chart plan
- `assets/templates/phase-plan.md` - Per-phase implementation plan
- `assets/templates/issue-structure.md` - GitHub issue hierarchy

### References
- `references/chart-structure.md` - Detailed chart organization
- `references/chart-complexity.md` - Chart complexity classification guide
- `references/research-strategy.md` - Documentation research and fallback strategies
- `references/external-services.md` - Common ports, env vars, connection strings
- `references/extend-contribute-strategy.md` - Extending and contributing to existing charts
- `references/research-phase-workflow.md` - Research phase structured workflow
- `references/planning-phase-workflow.md` - Planning phase structured workflow
- `references/implementation-workflow.md` - Implementation phase with checkpoints

### Scripts
- `scripts/validate-chart.sh` - Validation script

## Related Skills

- `k8s-manifest-generator` - For creating base Kubernetes manifests
- `gitops-workflow` - For automated Helm chart deployments
