Values reference
Full reference of all supported values.yaml keys.
Minimal starter
Copy this as a starting point for a single Deployment:
deployments:
- name: my-app
image:
repository: my-org/my-app
tag: "1.0.0"
service:
port: 8080
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
memory: 256Mi
cpu: 200m
Everything else is optional — add sections only when you need them.
Structure
Top-level keys are lists by workload type, plus global (chart-level) keys:
deployments:
- name: my-api
# workload options …
statefulsets:
- name: my-db
# workload options …
cronjobs:
- name: my-job
# workload options …
# Global keys
serviceAccount: …
rbac: …
imagePullSecrets: …
configMaps: …
secrets: …
sealedSecrets: …
persistentVolumeClaims: …
persistentVolumes: …
extraManifests: …
Workload options
Basic
| Key | Type | Default | Description |
|---|---|---|---|
name | string | — | Required. Name used for all Kubernetes resources. |
replicaCount | number | 1 | Replica count. Omitted from output when 1. Not used for CronJobs. |
strategy | object | RollingUpdate | Deployment strategy (Deployment only). |
# Recreate
strategy:
type: Recreate
# RollingUpdate with limits
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
Image
| Key | Type | Default | Description |
|---|---|---|---|
image.repository | string | — | Image repository, e.g. nginx or quay.io/myorg/app |
image.tag | string | — | Image tag, e.g. "1.25" |
image.digest | string | — | Image digest — overrides tag when set |
image.pullPolicy | string | IfNotPresent | IfNotPresent, Always, or Never |
CronJob schedule
Only for workloads in cronjobs[]. These keys go at the workload top level (not nested):
| Key | Type | Default | Description |
|---|---|---|---|
schedule | string | — | Cron expression, e.g. "0 * * * *" |
concurrencyPolicy | string | Forbid | Allow, Forbid, or Replace |
successfulJobsHistoryLimit | number | 3 | How many completed Job records to keep |
failedJobsHistoryLimit | number | 1 | How many failed Job records to keep |
backoffLimit | number | 3 | Max retries before marking a Job as failed |
restartPolicy | string | OnFailure | OnFailure or Never |
suspend | bool | false | Suspend the CronJob (no new Jobs start) |
startingDeadlineSeconds | number | — | Seconds after a missed schedule window to still start a Job |
activeDeadlineSeconds | number | — | Max duration of a single Job run |
cronjobs:
- name: nightly-report
image:
repository: my-org/reporter
tag: "2.0"
schedule: "0 2 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
backoffLimit: 2
restartPolicy: OnFailure
Service
Not available for CronJobs.
| Key | Type | Default | Description |
|---|---|---|---|
service.enabled | bool | true | Create a Service. Set to false to disable. |
service.type | string | ClusterIP | ClusterIP, NodePort, or LoadBalancer |
service.port | number | 80 | Service port |
service.targetPort | string/number | http | Container port or named port |
service.headless | bool | false (true for StatefulSets on v1.2.0+) | Set clusterIP: None. Headless is the default for StatefulSets since v1.2.0. |
service.protocol | string | TCP | TCP or UDP |
service.extraPorts | list | — | Additional port definitions |
service:
enabled: true
port: 8080
targetPort: http
extraPorts:
- name: metrics
port: 9090
targetPort: 9090
Route (OpenShift)
Not available for CronJobs.
| Key | Type | Default | Description |
|---|---|---|---|
route.enabled | bool | false | Create an OpenShift Route |
route.host | string | — | Custom hostname |
route.path | string | / | Path prefix |
route.targetPort | string | — | Named port on the Service |
route.tls.enabled | bool | auto | Auto-set when TLS config is present |
route.tls.termination | string | — | edge, passthrough, or reencrypt |
route.tls.insecureEdgeTerminationPolicy | string | — | Redirect, Allow, or None |
route.tls.certificate | string | — | PEM certificate body |
route.tls.key | string | — | PEM private key body |
route:
enabled: true
host: api.apps.example.com
tls:
termination: edge
insecureEdgeTerminationPolicy: Redirect
Ingress
Not available for CronJobs.
| Key | Type | Default | Description |
|---|---|---|---|
ingress.enabled | bool | false | Create an Ingress |
ingress.* | — | — | Any standard Ingress spec keys (className, hosts, tls, etc.) |
ingress:
enabled: true
className: nginx
hosts:
- host: api.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: api-tls
hosts:
- api.example.com
Ports, env, and resources
| Key | Type | Description |
|---|---|---|
ports | list | Container port definitions |
env | list | Environment variables (name/value or valueFrom) |
envFrom | list | Load all keys from a ConfigMap or Secret |
resources | object | CPU and memory requests and limits |
ports:
- name: http
containerPort: 8080
protocol: TCP
env:
- name: LOG_LEVEL
value: info
- name: DB_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url
envFrom:
- configMapRef:
name: my-config
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
memory: 256Mi
cpu: 200m
Command and args
| Key | Type | Description |
|---|---|---|
command | list | Override the container entrypoint |
args | list | Override the container command arguments |
command: ["python", "-m", "myapp"]
args: ["--port", "8080"]
Health probes
Not available for CronJobs. Each probe requires enabled: true to be rendered by the template.
livenessProbe:
enabled: true
httpGet:
path: /healthz
port: http
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
enabled: true
httpGet:
path: /ready
port: http
initialDelaySeconds: 5
periodSeconds: 5
startupProbe:
enabled: true
httpGet:
path: /healthz
port: http
failureThreshold: 30
periodSeconds: 10
Labels and annotations
| Key | Type | Description |
|---|---|---|
labels | object | Extra labels on the workload resource (Deployment / StatefulSet / CronJob) |
podLabels | object | Extra labels on Pods |
annotations | object | Extra annotations on the workload resource |
podAnnotations | object | Extra annotations on Pods |
labels:
tier: backend
annotations:
kubernetes.io/change-cause: "initial deployment"
podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
Security context
| Key | Type | Description |
|---|---|---|
podSecurityContext | object | Pod-level security context |
securityContext | object | Container-level security context |
podSecurityContext:
runAsNonRoot: true
runAsUser: 1000
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
Volumes and mounts
| Key | Type | Description |
|---|---|---|
extraVolumes | list | Volumes to attach (PVC, ConfigMap, or Secret) |
volumeMounts | list | Where to mount volumes inside the container |
extraVolumes:
- name: data
persistentVolumeClaim:
claimName: my-pvc
- name: config
configMap:
name: my-config
- name: creds
secret:
secretName: my-secret
volumeMounts:
- name: data
mountPath: /data
- name: config
mountPath: /etc/config
subPath: app.conf
Scheduling
| Key | Type | Default | Description |
|---|---|---|---|
nodeSelector | object | — | Node label selector |
tolerations | list | — | Pod tolerations |
affinity | object | — | Node or pod affinity rules |
terminationGracePeriodSeconds | number | 30 | Grace period before a Pod is force-killed |
Sidecars and init containers
| Key | Type | Description |
|---|---|---|
sidecars | list | Additional containers in the Pod (same spec as containers[]) |
initContainers | list | Init containers run before the main container |
initContainers:
- name: migrate
image: my-org/migrate:1.0.0
command: ["./migrate", "up"]
sidecars:
- name: proxy
image: envoyproxy/envoy:v1.29.0
StatefulSet-specific
Only applicable for workloads in statefulsets[].
| Key | Type | Description |
|---|---|---|
serviceName | string | Governing Service name (defaults to workload name) |
podManagementPolicy | string | OrderedReady (default) or Parallel |
updateStrategy | object | e.g. {type: RollingUpdate} |
volumeClaimTemplates | list | PVC templates — one PVC is created per Pod |
statefulsets:
- name: my-db
image:
repository: postgres
tag: "15"
podManagementPolicy: Parallel
updateStrategy:
type: RollingUpdate
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 10Gi
Autoscaling (HPA)
Deployment only.
| Key | Type | Description |
|---|---|---|
autoscaling.enabled | bool | Create an HPA |
autoscaling.minReplicas | number | Minimum replicas |
autoscaling.maxReplicas | number | Maximum replicas |
autoscaling.metrics | list | HPA metric sources |
autoscaling.behavior | object | Scale-up / scale-down behavior |
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
When HPA is enabled, replicaCount is not set in the Deployment spec (the HPA controls it).
KEDA
Deployment: keda.scaledObject. CronJob: keda.scaledJob.
# Deployment — ScaledObject
keda:
scaledObject:
enabled: true
minReplicaCount: 0
maxReplicaCount: 10
pollingInterval: 30
triggers:
- type: kafka
metadata:
bootstrapServers: kafka:9092
topic: my-topic
lagThreshold: "10"
# CronJob — ScaledJob
keda:
scaledJob:
enabled: true
maxReplicaCount: 10
triggers:
- type: rabbitmq
metadata:
queueName: my-queue
Pod Disruption Budget
Deployment and StatefulSet only. Set minAvailable or maxUnavailable, not both.
| Key | Type | Description |
|---|---|---|
podDisruptionBudget.enabled | bool | Create a PDB |
podDisruptionBudget.minAvailable | string/number | Min available pods, e.g. 1 or "50%" |
podDisruptionBudget.maxUnavailable | string/number | Max unavailable pods, e.g. 1 or "25%" |
podDisruptionBudget:
enabled: true
minAvailable: 1
Certificate (cert-manager)
Deployment and StatefulSet only.
| Key | Type | Default | Description |
|---|---|---|---|
certificate.enabled | bool | — | Create a cert-manager Certificate |
certificate.secretName | string | <name>-tls | Secret to store the issued certificate |
certificate.duration | string | 2160h | Certificate lifetime |
certificate.renewBefore | string | 360h | Renew this long before expiry |
certificate.dnsNames | list | — | DNS names to include on the certificate |
certificate.issuerRef.name | string | — | Issuer or ClusterIssuer name |
certificate.issuerRef.kind | string | ClusterIssuer | ClusterIssuer or Issuer |
certificate.issuerRef.group | string | cert-manager.io | Issuer API group |
certificate:
enabled: true
dnsNames:
- api.example.com
issuerRef:
name: letsencrypt-prod
Global options
These keys sit at the top level of values.yaml, outside any workload list.
serviceAccount
| Key | Type | Default | Description |
|---|---|---|---|
serviceAccount.create | bool | true | Create a ServiceAccount |
serviceAccount.name | string | release name | ServiceAccount name. Defaults to the Helm release name. |
Omit entirely to use the defaults (ServiceAccount created, named after the release).
rbac
| Key | Type | Description |
|---|---|---|
rbac.create | bool | Create a Role + RoleBinding for the ServiceAccount |
rbac.rules | list | RBAC policy rules |
rbac:
create: true
rules:
- apiGroups: [""]
resources: [pods, configmaps]
verbs: [get, list, watch]
imagePullSecrets
imagePullSecrets:
- name: my-registry-secret
configMaps
configMaps:
- name: my-config
data:
APP_ENV: production
LOG_LEVEL: info
secrets
Plain Secrets are stored unencrypted in etcd. If you need to commit them to Git, use Sealed Secrets instead.
secrets:
- name: my-secret
stringData:
DB_URL: postgres://user:pass@host/db
API_KEY: secret123
Any key accepted by the Kubernetes Secret spec can be included (e.g. type, data, stringData).
sealedSecrets
Requires the Sealed Secrets controller.
sealedSecrets:
- name: my-sealed-secret
encryptedData:
MY_SECRET: AgBy3i4OJSWK...
persistentVolumeClaims
| Key | Type | Default | Description |
|---|---|---|---|
name | string | — | PVC name |
size | string | — | Storage size, e.g. 10Gi |
storageClassName | string | — | Storage class name |
accessModes | list | [ReadWriteOnce] | Access modes |
persistentVolumeClaims:
- name: my-data
size: 10Gi
storageClassName: thin-csi
accessModes:
- ReadWriteOnce
persistentVolumes
PersistentVolumes rendered with the release. Note: this chart uses size (not capacity.storage) as a shorthand field:
persistentVolumes:
- name: my-pv
size: 10Gi
accessModes:
- ReadWriteOnce
reclaimPolicy: Retain
storageClassName: thin-csi
extraManifests
Any additional Kubernetes manifests rendered alongside the release:
extraManifests:
- apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress
spec:
podSelector: {}
ingress:
- {}