# Understanding Helm Charts - From Confusion to Clarity

## What is a Helm Chart? (Simple Answer)

**A Helm chart is a ZIP file containing:**

1. Kubernetes YAML templates (Deployment, Service, etc.)
    
2. A `values.yaml` file with default configuration
    
3. A way to customize those templates
    

**Think of it like:**

* **Template** = A form with blank fields
    
* **values.yaml** = The default values to fill in those blanks
    
* **Your custom values** = Overriding those defaults
    

---

## The Confusion: Templates vs Values

### What Confuses People:

```plaintext
❓ "There's a Deployment template in the chart..."
❓ "There's a values.yaml with settings..."
❓ "How do these connect?"
❓ "What can I actually change?"
❓ "Where do I put MY configuration?"
```

### The Answer (Visual):

```plaintext
HELM CHART (what the chart maintainers created)
│
├── templates/
│   ├── deployment.yaml          ← Template with {{ .Values.* }} placeholders
│   ├── service.yaml             ← Template with {{ .Values.* }} placeholders
│   └── configmap.yaml           ← Template with {{ .Values.* }} placeholders
│
└── values.yaml                  ← DEFAULT values that fill those placeholders
    image:
      repository: postgres
      tag: "15"
    persistence:
      enabled: true
      size: 8Gi

YOUR CUSTOM VALUES (what you provide)
│
└── my-values.yaml               ← YOUR values that OVERRIDE defaults
    image:
      tag: "16"                  ← Override: Use version 16 instead
    persistence:
      size: 20Gi                 ← Override: Use 20Gi instead of 8Gi

RESULT (what actually gets deployed)
│
└── Kubernetes YAML              ← Template filled with YOUR values
    apiVersion: apps/v1
    kind: Deployment
    spec:
      template:
        spec:
          containers:
          - image: postgres:16    ← From your my-values.yaml
            volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: postgres-pvc
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    spec:
      resources:
        requests:
          storage: 20Gi           ← From your my-values.yaml
```

---

## How to Actually Use a Helm Chart (Step by Step)

### Step 1: Find the Chart

```bash
# Search for a chart
helm search hub postgresql

# Add the repository
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
```

### Step 2: Look at What You Can Configure

```bash
# See ALL available options
helm show values bitnami/postgresql

# This outputs the ENTIRE values.yaml - save it!
helm show values bitnami/postgresql > default-values.yaml
```

**What you see (example):**

```yaml
## @section Global parameters
global:
  imageRegistry: ""
  storageClass: ""

## @section Common parameters
architecture: standalone

## @section PostgreSQL Authentication parameters
auth:
  enablePostgresUser: true
  postgresPassword: ""
  username: ""
  password: ""
  database: ""

## @section PostgreSQL Primary parameters
primary:
  persistence:
    enabled: true
    storageClass: ""
    size: 8Gi
  
  resources:
    limits: {}
    requests:
      memory: 256Mi
      cpu: 250m
```

### Step 3: Understand the Structure

**The values.yaml has a HIERARCHY:**

```yaml
# Top level
auth:                    ← Top-level key
  username: "myapp"      ← Nested under 'auth'
  password: "secret"     ← Nested under 'auth'
  database: "mydb"       ← Nested under 'auth'

primary:                 ← Different top-level key
  persistence:           ← Nested under 'primary'
    enabled: true        ← Nested under 'persistence'
    size: 20Gi          ← Nested under 'persistence'
  resources:             ← Different nested key under 'primary'
    limits:              ← Nested under 'resources'
      cpu: 2000m         ← Nested under 'limits'
```

**This maps to template placeholders:**

```yaml
# In the chart's templates/deployment.yaml (you don't edit this):
spec:
  containers:
  - name: postgresql
    image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
    env:
    - name: POSTGRES_USER
      value: {{ .Values.auth.username }}
    - name: POSTGRES_PASSWORD
      value: {{ .Values.auth.password }}
    - name: POSTGRES_DB
      value: {{ .Values.auth.database }}
```

**When you provide:**

```yaml
# your-values.yaml
auth:
  username: "myapp"
  password: "secret123"
  database: "myappdb"
```

**Helm renders it as:**

```yaml
spec:
  containers:
  - name: postgresql
    image: postgres:15
    env:
    - name: POSTGRES_USER
      value: myapp          ← YOUR value inserted here
    - name: POSTGRES_PASSWORD
      value: secret123      ← YOUR value inserted here
    - name: POSTGRES_DB
      value: myappdb        ← YOUR value inserted here
```

### Step 4: Create Your Custom Values File

**DON'T copy the entire default values.yaml!**

**DO only specify what you want to CHANGE:**

```yaml
# my-postgres-values.yaml

# Only include what you're changing!
auth:
  username: myapp
  password: mySecurePassword123
  database: myappdb

primary:
  persistence:
    size: 20Gi
  
  resources:
    limits:
      cpu: 2000m
      memory: 4Gi
    requests:
      cpu: 500m
      memory: 1Gi
```

**Everything else uses the chart's defaults!**

### Step 5: Install the Chart

```bash
# Install with your custom values
helm install my-postgres bitnami/postgresql -f my-postgres-values.yaml

# Or install to specific namespace
helm install my-postgres bitnami/postgresql \
  --namespace database \
  --create-namespace \
  -f my-postgres-values.yaml
```

**What happens:**

1. Helm downloads the chart
    
2. Helm reads the chart's `values.yaml` (defaults)
    
3. Helm reads YOUR `my-postgres-values.yaml` (overrides)
    
4. Helm merges them (your values override defaults)
    
5. Helm fills the templates with the merged values
    
6. Helm applies the rendered YAML to Kubernetes
    

---

## The Three Ways to Provide Values

### Method 1: Values File (Recommended)

```bash
# Create my-values.yaml
cat > my-values.yaml <<EOF
auth:
  username: myapp
  database: myappdb
EOF

# Install with file
helm install postgres bitnami/postgresql -f my-values.yaml
```

### Method 2: Command Line (Quick Testing)

```bash
# Set individual values via --set
helm install postgres bitnami/postgresql \
  --set auth.username=myapp \
  --set auth.database=myappdb \
  --set primary.persistence.size=20Gi
```

### Method 3: Multiple Values Files (Advanced)

```bash
# Combine multiple files
helm install postgres bitnami/postgresql \
  -f base-values.yaml \
  -f production-overrides.yaml

# Later values override earlier ones
```

---

## Common Confusion Points - SOLVED

### Confusion 1: "What can I actually configure?"

**Answer:** Look at the default values.yaml

```bash
helm show values bitnami/postgresql > values.yaml
less values.yaml

# Search for what you need
grep -i "persistence" values.yaml
grep -i "resources" values.yaml
grep -i "password" values.yaml
```

**If it's in values.yaml, you can configure it!**

### Confusion 2: "How do I know the correct structure?"

**Answer:** Copy the structure EXACTLY from values.yaml

```yaml
# ❌ WRONG - flat structure
persistence.size: 20Gi

# ✅ CORRECT - nested structure (same as in values.yaml)
primary:
  persistence:
    size: 20Gi
```

**Rule:** Match the indentation/nesting from the default values.yaml

### Confusion 3: "Do I need to specify everything?"

**NO!** Only specify what you want to change.

```yaml
# ❌ Don't do this (500 lines)
# Copy entire values.yaml and modify a few lines

# ✅ Do this (10 lines)
# Only what you're changing
auth:
  username: myapp
  database: myappdb
```

### Confusion 4: "What if I want to see the final YAML?"

```bash
# Dry-run: See what will be created WITHOUT installing
helm install postgres bitnami/postgresql \
  -f my-values.yaml \
  --dry-run \
  --debug

# This shows you the FINAL rendered Kubernetes YAML
```

### Confusion 5: "How do I know if my values are valid?"

```bash
# Template: Render locally without installing
helm template postgres bitnami/postgresql -f my-values.yaml

# If it works, your values are valid
# If it fails, you'll see the error
```

---

## Real Example: From Confusion to Clarity

### Scenario: Deploy PostgreSQL

#### Step 1: Get Default Values

```bash
helm repo add bitnami https://charts.bitnami.com/bitnami
helm show values bitnami/postgresql > postgres-defaults.yaml
```

#### Step 2: Open and Search

```bash
# Open in your editor
code postgres-defaults.yaml

# Search for key sections (Ctrl+F):
# - "auth"          ← Authentication
# - "persistence"   ← Storage
# - "resources"     ← CPU/Memory
# - "initdb"        ← Initial scripts
```

#### Step 3: Find What You Need

**In postgres-defaults.yaml you find:**

```yaml
## Authentication parameters
auth:
  ## @param auth.enablePostgresUser Assign a password to the "postgres" admin user
  enablePostgresUser: true
  ## @param auth.postgresPassword Password for the "postgres" admin user
  postgresPassword: ""
  ## @param auth.username Name for a custom user to create
  username: ""
  ## @param auth.password Password for the custom user to create
  password: ""
  ## @param auth.database Name for a custom database to create
  database: ""
```

**And:**

```yaml
primary:
  ## PostgreSQL Primary persistence configuration
  persistence:
    ## @param primary.persistence.enabled Enable PostgreSQL Primary data persistence
    enabled: true
    ## @param primary.persistence.storageClass PVC Storage Class
    storageClass: ""
    ## @param primary.persistence.size PVC Storage Request
    size: 8Gi
```

#### Step 4: Create YOUR Values (Only What You Need)

```yaml
# my-postgres-values.yaml

# Authentication (copied structure from defaults)
auth:
  username: myapp
  password: MySecurePass123
  database: myappdb

# Storage (copied structure from defaults)
primary:
  persistence:
    enabled: true
    storageClass: local-path  # K3s storage class
    size: 20Gi                # Changed from default 8Gi

# Resources (copied structure from defaults)
  resources:
    limits:
      cpu: 2000m
      memory: 4Gi
    requests:
      cpu: 500m
      memory: 1Gi
```

#### Step 5: Verify Before Installing

```bash
# See what will be created
helm template test-postgres bitnami/postgresql \
  -f my-postgres-values.yaml \
  --namespace database

# Look through the output - verify:
# - POSTGRES_USER = myapp ✓
# - POSTGRES_DB = myappdb ✓
# - PVC size = 20Gi ✓
# - CPU limits = 2000m ✓
```

#### Step 6: Install

```bash
helm install postgres bitnami/postgresql \
  -f my-postgres-values.yaml \
  --namespace database \
  --create-namespace
```

---

## The Mental Model

```plaintext
┌─────────────────────────────────────────┐
│         HELM CHART (Package)            │
│  ┌────────────────────────────────┐    │
│  │  templates/                     │    │
│  │    deployment.yaml              │    │
│  │    service.yaml                 │    │
│  │    configmap.yaml               │    │
│  │                                 │    │
│  │  These have placeholders:       │    │
│  │    {{ .Values.auth.username }}  │    │
│  │    {{ .Values.persistence.size }}│   │
│  └────────────────────────────────┘    │
│                                         │
│  ┌────────────────────────────────┐    │
│  │  values.yaml (DEFAULTS)         │    │
│  │    auth:                        │    │
│  │      username: ""               │    │
│  │    persistence:                 │    │
│  │      size: 8Gi                  │    │
│  └────────────────────────────────┘    │
└─────────────────────────────────────────┘
                    │
                    │ You provide
                    ↓
┌─────────────────────────────────────────┐
│   YOUR VALUES (my-values.yaml)          │
│     auth:                               │
│       username: myapp  ← Override       │
│     persistence:                        │
│       size: 20Gi       ← Override       │
└─────────────────────────────────────────┘
                    │
                    │ Helm merges
                    ↓
┌─────────────────────────────────────────┐
│       FINAL RENDERED YAML               │
│   (Actually deployed to Kubernetes)     │
│                                         │
│   Deployment with:                      │
│     - username: myapp                   │
│     - PVC size: 20Gi                    │
└─────────────────────────────────────────┘
```

---

## Quick Reference Commands

```bash
# Search for charts
helm search hub <chart-name>

# Add repository
helm repo add <name> <url>
helm repo update

# View chart info
helm show chart <repo>/<chart>

# View README
helm show readme <repo>/<chart>

# View default values (IMPORTANT!)
helm show values <repo>/<chart>
helm show values <repo>/<chart> > values.yaml

# Test your values without installing
helm template <name> <repo>/<chart> -f my-values.yaml
helm install <name> <repo>/<chart> -f my-values.yaml --dry-run --debug

# Install chart
helm install <name> <repo>/<chart> -f my-values.yaml
helm install <name> <repo>/<chart> -f my-values.yaml -n <namespace> --create-namespace

# Upgrade chart
helm upgrade <name> <repo>/<chart> -f my-values.yaml

# Check what's installed
helm list
helm list -n <namespace>

# Get values of installed release
helm get values <name>
helm get values <name> -n <namespace>

# Uninstall
helm uninstall <name>
helm uninstall <name> -n <namespace>
```

---

## Key Takeaways

1. **Chart = Templates + Default Values**
    
2. **You only configure values, NOT templates**
    
3. **Your values OVERRIDE defaults (you don't need to copy everything)**
    
4. **Match the EXACT structure from default values.yaml**
    
5. **Use** `helm show values` to see what you can configure
    
6. **Use** `helm template` or `--dry-run` to verify before installing
    
7. **Values hierarchy must match (indentation matters!)**
    

---

## Practice Exercise

Try this right now:

```bash
# 1. Get the default values
helm repo add bitnami https://charts.bitnami.com/bitnami
helm show values bitnami/nginx > nginx-defaults.yaml

# 2. Open and find these sections:
# - replicaCount
# - service.type
# - ingress.enabled

# 3. Create your own values file:
cat > my-nginx-values.yaml <<EOF
replicaCount: 3
service:
  type: NodePort
EOF

# 4. See what it will create:
helm template test bitnami/nginx -f my-nginx-values.yaml

# 5. If it looks good, install:
helm install mynginx bitnami/nginx -f my-nginx-values.yaml
```
