Initial commit
This commit is contained in:
535
skills/helm-scaffold/references/testing-guide.md
Normal file
535
skills/helm-scaffold/references/testing-guide.md
Normal file
@@ -0,0 +1,535 @@
|
||||
# Helm Chart Testing Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This guide provides testing templates and commands for validating Helm charts before deployment. Always test charts with dry-run and template rendering before actual deployment.
|
||||
|
||||
## Testing Workflow
|
||||
|
||||
```
|
||||
1. Helm Lint → Validate chart structure
|
||||
2. Helm Template → Preview rendered manifests
|
||||
3. Dry-run Install → Test against cluster API
|
||||
4. Kubectl Dry-run → Final validation
|
||||
5. Actual Install → Deploy to cluster
|
||||
```
|
||||
|
||||
## Mock Values by Workload Type
|
||||
|
||||
### Deployment (Web Application)
|
||||
|
||||
```yaml
|
||||
# values-test.yaml
|
||||
image:
|
||||
repository: nginx
|
||||
tag: "1.25"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
replicaCount: 2
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "nginx"
|
||||
hosts:
|
||||
- host: test.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: test-tls
|
||||
hosts:
|
||||
- test.example.com
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
|
||||
livenessProbe:
|
||||
enabled: true
|
||||
path: /healthz
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
|
||||
readinessProbe:
|
||||
enabled: true
|
||||
path: /ready
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
|
||||
env:
|
||||
- name: ENVIRONMENT
|
||||
value: "test"
|
||||
- name: LOG_LEVEL
|
||||
value: "debug"
|
||||
- name: PORT
|
||||
value: "80"
|
||||
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 2
|
||||
maxReplicas: 5
|
||||
targetCPUUtilizationPercentage: 80
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
```
|
||||
|
||||
### StatefulSet (Database)
|
||||
|
||||
```yaml
|
||||
# values-test.yaml
|
||||
image:
|
||||
repository: postgres
|
||||
tag: "15"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
replicaCount: 3
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 5432
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: "standard"
|
||||
size: 10Gi
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 2Gi
|
||||
|
||||
livenessProbe:
|
||||
enabled: true
|
||||
path: /
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 30
|
||||
|
||||
readinessProbe:
|
||||
enabled: true
|
||||
path: /
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
|
||||
env:
|
||||
- name: POSTGRES_DB
|
||||
value: "testdb"
|
||||
- name: POSTGRES_USER
|
||||
value: "testuser"
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: "testpass123"
|
||||
- name: PGDATA
|
||||
value: "/data/pgdata"
|
||||
|
||||
podManagementPolicy: OrderedReady
|
||||
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: app.kubernetes.io/name
|
||||
operator: In
|
||||
values:
|
||||
- postgres
|
||||
topologyKey: kubernetes.io/hostname
|
||||
```
|
||||
|
||||
### Job (Batch Processing)
|
||||
|
||||
```yaml
|
||||
# values-test.yaml
|
||||
image:
|
||||
repository: busybox
|
||||
tag: "1.36"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
job:
|
||||
backoffLimit: 3
|
||||
activeDeadlineSeconds: 600
|
||||
ttlSecondsAfterFinished: 86400
|
||||
restartPolicy: OnFailure
|
||||
parallelism: 1
|
||||
completions: 1
|
||||
command:
|
||||
- /bin/sh
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
echo "Starting batch job..."
|
||||
echo "Processing data..."
|
||||
sleep 30
|
||||
echo "Job completed successfully!"
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
|
||||
env:
|
||||
- name: JOB_TYPE
|
||||
value: "batch-process"
|
||||
- name: BATCH_SIZE
|
||||
value: "1000"
|
||||
- name: OUTPUT_PATH
|
||||
value: "/output"
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
```
|
||||
|
||||
### CronJob (Scheduled Task)
|
||||
|
||||
```yaml
|
||||
# values-test.yaml
|
||||
image:
|
||||
repository: busybox
|
||||
tag: "1.36"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
cronJob:
|
||||
schedule: "*/5 * * * *" # Every 5 minutes for testing
|
||||
concurrencyPolicy: Forbid
|
||||
successfulJobsHistoryLimit: 3
|
||||
failedJobsHistoryLimit: 1
|
||||
startingDeadlineSeconds: 200
|
||||
suspend: false
|
||||
backoffLimit: 2
|
||||
activeDeadlineSeconds: 300
|
||||
restartPolicy: OnFailure
|
||||
command:
|
||||
- /bin/sh
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
echo "Running scheduled task at $(date)"
|
||||
echo "Performing backup/cleanup/sync..."
|
||||
sleep 10
|
||||
echo "Task completed at $(date)"
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
|
||||
env:
|
||||
- name: TASK_NAME
|
||||
value: "scheduled-backup"
|
||||
- name: RETENTION_DAYS
|
||||
value: "7"
|
||||
- name: TARGET
|
||||
value: "/backup"
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
```
|
||||
|
||||
## Testing Commands
|
||||
|
||||
### 1. Validate Chart Structure
|
||||
|
||||
```bash
|
||||
# Basic lint
|
||||
helm lint my-chart
|
||||
|
||||
# Lint with custom values
|
||||
helm lint my-chart -f values-test.yaml
|
||||
|
||||
# Lint with value overrides
|
||||
helm lint my-chart --set image.tag=latest
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
==> Linting my-chart
|
||||
[INFO] Chart.yaml: icon is recommended
|
||||
1 chart(s) linted, 0 chart(s) failed
|
||||
```
|
||||
|
||||
### 2. Render Templates Locally
|
||||
|
||||
```bash
|
||||
# Render all templates
|
||||
helm template my-release my-chart
|
||||
|
||||
# Render with test values
|
||||
helm template my-release my-chart -f values-test.yaml
|
||||
|
||||
# Render with inline overrides
|
||||
helm template my-release my-chart \
|
||||
--set image.tag=latest \
|
||||
--set replicaCount=3
|
||||
|
||||
# Show only specific resource
|
||||
helm template my-release my-chart | grep -A 30 "kind: Deployment"
|
||||
|
||||
# Save rendered manifests to file
|
||||
helm template my-release my-chart -f values-test.yaml > rendered.yaml
|
||||
|
||||
# Render for specific namespace
|
||||
helm template my-release my-chart --namespace production
|
||||
```
|
||||
|
||||
### 3. Dry-run Install
|
||||
|
||||
```bash
|
||||
# Dry-run against cluster API (requires cluster access)
|
||||
helm install my-release my-chart --dry-run --debug
|
||||
|
||||
# Dry-run with custom values
|
||||
helm install my-release my-chart \
|
||||
--dry-run \
|
||||
--debug \
|
||||
-f values-test.yaml
|
||||
|
||||
# Dry-run with namespace
|
||||
helm install my-release my-chart \
|
||||
--dry-run \
|
||||
--debug \
|
||||
--namespace test \
|
||||
--create-namespace
|
||||
```
|
||||
|
||||
**Expected behavior:**
|
||||
- Validates against cluster API
|
||||
- Shows what would be installed
|
||||
- Catches API version issues
|
||||
- Does NOT create resources
|
||||
|
||||
### 4. Validate with Kubectl
|
||||
|
||||
```bash
|
||||
# Validate rendered manifests
|
||||
helm template my-release my-chart | kubectl apply --dry-run=client -f -
|
||||
|
||||
# Validate with specific values
|
||||
helm template my-release my-chart -f values-test.yaml | kubectl apply --dry-run=client -f -
|
||||
|
||||
# Server-side dry-run (requires cluster)
|
||||
helm template my-release my-chart | kubectl apply --dry-run=server -f -
|
||||
```
|
||||
|
||||
### 5. Diff Against Existing Release
|
||||
|
||||
```bash
|
||||
# Install helm diff plugin first
|
||||
helm plugin install https://github.com/databus23/helm-diff
|
||||
|
||||
# Compare with existing release
|
||||
helm diff upgrade my-release my-chart -f values-test.yaml
|
||||
|
||||
# Show only changes
|
||||
helm diff upgrade my-release my-chart -f values-test.yaml --suppress-secrets
|
||||
```
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
### Pre-deployment Validation
|
||||
|
||||
- [ ] Chart passes `helm lint` without warnings
|
||||
- [ ] Templates render successfully with `helm template`
|
||||
- [ ] Dry-run install completes without errors
|
||||
- [ ] Image names are valid and accessible
|
||||
- [ ] Resource limits are appropriate
|
||||
- [ ] Labels and selectors match correctly
|
||||
- [ ] Health check paths are correct
|
||||
- [ ] Environment variables are set
|
||||
- [ ] Secrets are not in values.yaml
|
||||
- [ ] Ingress hostnames are valid
|
||||
- [ ] Service ports match container ports
|
||||
|
||||
### Workload-Specific Checks
|
||||
|
||||
#### Deployment
|
||||
- [ ] Replica count is appropriate
|
||||
- [ ] Rolling update strategy configured
|
||||
- [ ] HPA settings (if enabled) are sensible
|
||||
- [ ] Pod disruption budget considered
|
||||
|
||||
#### StatefulSet
|
||||
- [ ] Persistence configuration correct
|
||||
- [ ] Storage class exists
|
||||
- [ ] Headless service defined
|
||||
- [ ] Pod management policy appropriate
|
||||
- [ ] Volume claim templates valid
|
||||
|
||||
#### Job
|
||||
- [ ] Backoff limit reasonable
|
||||
- [ ] Active deadline set
|
||||
- [ ] TTL for cleanup configured
|
||||
- [ ] Restart policy appropriate
|
||||
- [ ] Command/args correct
|
||||
|
||||
#### CronJob
|
||||
- [ ] Schedule syntax valid
|
||||
- [ ] Concurrency policy appropriate
|
||||
- [ ] History limits set
|
||||
- [ ] Starting deadline configured
|
||||
- [ ] Job template valid
|
||||
|
||||
## Common Testing Scenarios
|
||||
|
||||
### Test 1: Minimal Values (Defaults)
|
||||
|
||||
```bash
|
||||
# Test with only required values
|
||||
helm template test my-chart --set image.repository=nginx
|
||||
```
|
||||
|
||||
### Test 2: Production-like Values
|
||||
|
||||
```bash
|
||||
# Test with production configuration
|
||||
helm template test my-chart -f values-prod.yaml
|
||||
```
|
||||
|
||||
### Test 3: Multiple Environments
|
||||
|
||||
```bash
|
||||
# Test dev environment
|
||||
helm template test my-chart -f values-dev.yaml
|
||||
|
||||
# Test staging environment
|
||||
helm template test my-chart -f values-staging.yaml
|
||||
|
||||
# Test production environment
|
||||
helm template test my-chart -f values-prod.yaml
|
||||
```
|
||||
|
||||
### Test 4: Value Overrides
|
||||
|
||||
```bash
|
||||
# Test with inline overrides
|
||||
helm template test my-chart \
|
||||
--set image.tag=v2.0.0 \
|
||||
--set replicaCount=5 \
|
||||
--set ingress.enabled=true
|
||||
```
|
||||
|
||||
### Test 5: Resource Validation
|
||||
|
||||
```bash
|
||||
# Check resource limits
|
||||
helm template test my-chart | grep -A 5 "resources:"
|
||||
|
||||
# Check security contexts
|
||||
helm template test my-chart | grep -A 10 "securityContext:"
|
||||
|
||||
# Check probes
|
||||
helm template test my-chart | grep -A 5 "Probe:"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: Template rendering fails
|
||||
|
||||
```bash
|
||||
# Debug with verbose output
|
||||
helm template test my-chart --debug
|
||||
|
||||
# Check specific template
|
||||
helm template test my-chart --show-only templates/deployment.yaml
|
||||
```
|
||||
|
||||
### Issue: Validation errors
|
||||
|
||||
```bash
|
||||
# Validate individual resources
|
||||
helm template test my-chart | kubectl apply --dry-run=client -f - --validate=strict
|
||||
|
||||
# Check for deprecated APIs
|
||||
helm template test my-chart | kubectl apply --dry-run=server -f -
|
||||
```
|
||||
|
||||
### Issue: Values not applied
|
||||
|
||||
```bash
|
||||
# Verify values are loaded
|
||||
helm template test my-chart -f values-test.yaml --debug | grep -A 5 "USER-SUPPLIED VALUES"
|
||||
|
||||
# Check final computed values
|
||||
helm template test my-chart -f values-test.yaml --debug | grep -A 20 "COMPUTED VALUES"
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always test before deploying** - Use dry-run and template rendering
|
||||
2. **Use realistic test data** - Mock values should resemble production
|
||||
3. **Test all environments** - Validate dev, staging, prod configurations
|
||||
4. **Validate security** - Check security contexts and RBAC
|
||||
5. **Check resource limits** - Ensure requests/limits are appropriate
|
||||
6. **Test failure scenarios** - Invalid values, missing fields
|
||||
7. **Document test process** - Share testing commands with team
|
||||
8. **Automate testing** - Include in CI/CD pipeline
|
||||
|
||||
## Automated Testing Example
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# test-chart.sh
|
||||
|
||||
set -e
|
||||
|
||||
CHART_DIR="my-chart"
|
||||
VALUES_FILE="values-test.yaml"
|
||||
|
||||
echo "Testing Helm chart: $CHART_DIR"
|
||||
|
||||
# Test 1: Lint
|
||||
echo "1. Running helm lint..."
|
||||
helm lint $CHART_DIR -f $VALUES_FILE
|
||||
|
||||
# Test 2: Template rendering
|
||||
echo "2. Rendering templates..."
|
||||
helm template test $CHART_DIR -f $VALUES_FILE > /tmp/rendered.yaml
|
||||
|
||||
# Test 3: Kubectl validation
|
||||
echo "3. Validating with kubectl..."
|
||||
kubectl apply --dry-run=client -f /tmp/rendered.yaml
|
||||
|
||||
# Test 4: Check for secrets in values
|
||||
echo "4. Checking for secrets in values..."
|
||||
if grep -i "password\|secret\|token" $VALUES_FILE; then
|
||||
echo "WARNING: Potential secrets found in values file!"
|
||||
fi
|
||||
|
||||
echo "✅ All tests passed!"
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Always follow this testing sequence:
|
||||
1. **Lint** the chart structure
|
||||
2. **Render** templates to preview
|
||||
3. **Dry-run** to validate against API
|
||||
4. **Review** rendered manifests
|
||||
5. **Deploy** to test environment first
|
||||
6. **Monitor** after deployment
|
||||
|
||||
Never skip testing, even for "small changes"!
|
||||
Reference in New Issue
Block a user