Stage 5 · Platform
Release Packaging with Helm & Kustomize
Values Management
values.yaml, schema validation, environment files, secrets references, and override precedence.
Values Structure
values.yaml defines default configuration. Structure values logically: image, service, resources, autoscaling, ingress, etc. Use comments to document each value. Provide sensible defaults that work out of the box.
# Application settings
replicaCount: 2
image:
repository: ghcr.io/my-org/my-app
tag: "1.0.0"
pullPolicy: IfNotPresent
# Service configuration
service:
type: ClusterIP
port: 80
targetPort: 8080
# Resource allocation
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
# Autoscaling
autoscaling:
enabled: false
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
# Ingress
ingress:
enabled: false
className: nginx
annotations: {}
hosts:
- host: api.example.com
paths:
- path: /
pathType: Prefix
tls: []Logical grouping makes values easy to understand. Sensible defaults (2 replicas, moderate resources) work for most environments. Autoscaling is disabled by default — enable it in production values.
Schema Validation
JSON Schema validates values.yaml before rendering. Catch errors early: wrong types, missing required values, or out-of-range numbers. Schema validation prevents broken deployments from bad configuration.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["image"],
"properties": {
"replicaCount": {
"type": "integer",
"minimum": 1,
"maximum": 50
},
"image": {
"type": "object",
"required": ["repository"],
"properties": {
"repository": {
"type": "string",
"pattern": "^[a-z0-9.-]+(/[a-z0-9.-]+)*$"
},
"tag": {
"type": "string"
},
"pullPolicy": {
"type": "string",
"enum": ["Always", "IfNotPresent", "Never"]
}
}
},
"resources": {
"type": "object",
"properties": {
"requests": {
"type": "object",
"properties": {
"cpu": { "type": "string" },
"memory": { "type": "string" }
}
}
}
}
}
}The schema enforces: replicaCount must be 1-50, image.repository is required and must match a pattern, pullPolicy must be one of three values. Invalid values cause helm install to fail immediately.
Override Precedence
Values are merged in order of precedence: default values.yaml < dependency values < parent chart values < -f file values < --set values. Later sources override earlier ones. This allows layered configuration.
# Default values (lowest precedence)
helm install my-release ./my-chart
# Override with file
helm install my-release ./my-chart -f values-prod.yaml
# Override with multiple files (later files win)
helm install my-release ./my-chart -f values-base.yaml -f values-prod.yaml
# Override specific values (highest precedence)
helm install my-release ./my-chart \
--set replicaCount=5 \
--set image.tag=2.0.0 \
--set resources.limits.cpu=1
# Set values from a file
helm install my-release ./my-chart --set-file config.script=script.sh--set overrides take highest precedence. Multiple -f files merge in order. This allows: base values < environment values < CLI overrides. The final merged values are used for rendering.
Environment-Specific Files
Create values files per environment: values-dev.yaml, values-staging.yaml, values-prod.yaml. Each overrides only environment-specific settings. The base values.yaml provides defaults.
replicaCount: 5
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 20
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "2"
memory: "2Gi"
ingress:
enabled: true
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: api.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: api-tls
hosts:
- api.example.comProduction values override: higher replica count, autoscaling enabled, larger resources, ingress enabled with TLS. Only environment-specific values are overridden — everything else uses defaults.
Secrets in Values
Never commit plain-text secrets to values files. Use External Secrets, Sealed Secrets, or Vault integration. Reference secrets by name in values, not by value.
# In values.yaml — reference secret names, not values
database:
host: postgres-service
port: 5432
credentialsSecret: db-credentials # Secret name
credentialsKey: password # Key in the secret
# In template — use the reference
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.database.credentialsSecret }}
key: {{ .Values.database.credentialsKey }}Values reference secrets by name and key. The actual secret is created separately (External Secrets, Sealed Secrets). This keeps sensitive data out of Git while maintaining configuration flexibility.
Best Practices
- Document every value with comments in values.yaml
- Use JSON Schema to validate values
- Provide sensible defaults that work out of the box
- Never commit secrets to values files
- Use environment-specific files for overrides
- Test with helm template before helm install
- Use --dry-run to validate without deploying
The helm show values command displays the values.yaml with comments. This is the primary documentation for chart users. Keep comments up-to-date and clear.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.