Helm Values
Managing values files and configuration overrides in Helm.
Values Hierarchy
Helm merges values from multiple sources (lower precedence first):
-
Built-in default values
-
Chart's values.yaml
-
Parent chart's values
-
Values files specified with -f (can be multiple)
-
Individual parameters with --set
values.yaml Structure
Organize by Resource
Global settings
global: environment: production domain: example.com
Application settings
app: name: myapp version: "1.0.0"
Image settings
image: repository: myregistry/myapp pullPolicy: IfNotPresent tag: "" # Overrides appVersion
Service settings
service: type: ClusterIP port: 80 targetPort: 8080
Ingress settings
ingress: enabled: false className: nginx annotations: {} hosts: - host: myapp.example.com paths: - path: / pathType: Prefix tls: []
Resources
resources: limits: cpu: 500m memory: 512Mi requests: cpu: 250m memory: 256Mi
Persistence
persistence: enabled: false storageClass: "" accessMode: ReadWriteOnce size: 8Gi
Override Strategies
Override with File
Single file
helm install myrelease ./mychart -f custom-values.yaml
Multiple files (later files override earlier)
helm install myrelease ./mychart
-f values-base.yaml
-f values-production.yaml
Override with --set
Single value
helm install myrelease ./mychart --set image.tag=2.0.0
Multiple values
helm install myrelease ./mychart
--set image.tag=2.0.0
--set replicaCount=5
Nested values
helm install myrelease ./mychart
--set ingress.enabled=true
--set ingress.hosts[0].host=myapp.com
Override with --set-string
Force string type (useful for numeric-looking strings)
helm install myrelease ./mychart
--set-string version="1.0"
Override with --set-file
Read value from file
helm install myrelease ./mychart
--set-file config=./config.json
Environment-Specific Values
values-development.yaml
replicaCount: 1
image: tag: "dev-latest" pullPolicy: Always
resources: limits: cpu: 200m memory: 256Mi
ingress: enabled: true hosts: - host: dev.myapp.com
postgresql: enabled: true
values-production.yaml
replicaCount: 5
image: tag: "1.0.0" pullPolicy: IfNotPresent
resources: limits: cpu: 1000m memory: 1Gi
ingress: enabled: true hosts: - host: myapp.com tls: - secretName: myapp-tls hosts: - myapp.com
postgresql: enabled: false external: host: prod-db.example.com
Global Values
Parent Chart values.yaml
global: environment: production storageClass: fast-ssd
postgresql: auth: existingSecret: db-credentials
Subchart Access
In subchart template
environment: {{ .Values.global.environment }}
Schema Validation
values.schema.json
{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": ["image"], "properties": { "replicaCount": { "type": "integer", "minimum": 1, "maximum": 10 }, "image": { "type": "object", "required": ["repository"], "properties": { "repository": { "type": "string" }, "tag": { "type": "string" }, "pullPolicy": { "type": "string", "enum": ["Always", "IfNotPresent", "Never"] } } }, "service": { "type": "object", "properties": { "type": { "type": "string", "enum": ["ClusterIP", "NodePort", "LoadBalancer"] }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 } } } } }
Secrets in Values
Don't Commit Secrets
values.yaml - public defaults
database: host: "" username: "" password: ""
values-secrets.yaml - not in git
database: host: "prod-db.example.com" username: "dbuser" password: "super-secret"
Use External Secrets
values.yaml
database: useExistingSecret: true existingSecretName: db-credentials
In template
{{- if .Values.database.useExistingSecret }} secretKeyRef: name: {{ .Values.database.existingSecretName }} key: password {{- else }} value: {{ .Values.database.password | quote }} {{- end }}
Complex Value Structures
Lists
values.yaml
extraEnvVars:
- name: LOG_LEVEL value: info
- name: API_KEY valueFrom: secretKeyRef: name: api-secret key: key
template
{{- range .Values.extraEnvVars }}
- name: {{ .name }} {{- if .value }} value: {{ .value | quote }} {{- else if .valueFrom }} valueFrom: {{- toYaml .valueFrom | nindent 4 }} {{- end }} {{- end }}
Maps
values.yaml
annotations: prometheus.io/scrape: "true" prometheus.io/port: "9090"
labels: team: platform environment: production
template
annotations: {{- range $key, $value := .Values.annotations }} {{ $key }}: {{ $value | quote }} {{- end }}
Best Practices
Document Values
values.yaml with comments
Number of replicas
@param replicaCount - Number of pod replicas
replicaCount: 3
Image configuration
@param image.repository - Docker image repository
@param image.tag - Docker image tag (defaults to Chart appVersion)
image: repository: myapp tag: ""
Sensible Defaults
Provide production-ready defaults
replicaCount: 3 # Not 1
resources: limits: cpu: 500m memory: 512Mi requests: cpu: 500m # Same as limit for guaranteed QoS memory: 512Mi
Feature Flags
Allow enabling/disabling features
features: metrics: enabled: true port: 9090
tracing: enabled: false endpoint: ""
View Computed Values
See final merged values
helm get values myrelease
See all values (including defaults)
helm get values myrelease --all
Template with values
helm template myrelease ./mychart -f custom-values.yaml