Helm Values Reference
This page documents the configuration values you are most likely to override when installing the runtime-operator Helm chart. For the authoritative list of every value the chart supports, run:
helm show values oci://ghcr.io/wasmcloud/charts/runtime-operator --version <version>Top-level structure
The chart's values.yaml is organized into five top-level sections:
| Section | Purpose |
|---|---|
global | Settings that apply across all components (image registry, TLS, image pull secrets) |
nats | The bundled NATS server — set enabled: false to connect an external NATS cluster instead |
operator | The wasmCloud runtime-operator deployment |
gateway | Deprecated in 2.0.3. Legacy runtime-gateway. Set enabled: false to skip installing it |
runtime | Host group deployments (pods running the wash host binary) |
global
global.image.registry
Override the container image registry for all components at once. Useful for air-gapped or mirrored deployments.
global:
image:
registry: myregistry.example.comSee Private Registries and Air-Gapped Deployments for the full mirroring workflow.
global.tls.enabled
Set to false to disable TLS for NATS connections and skip certificate generation. Intended for clusters where a service mesh (e.g. Istio, Linkerd) provides mTLS between pods.
global:
tls:
enabled: falseWhen global.tls.enabled is false, the chart ignores global.certificates.generate — no self-signed certs are created and NATS runs plaintext.
global.certificates.generate
Controls whether the chart generates self-signed TLS certificates for NATS and the control plane. Set to false when bringing your own certificate secrets. See the TLS: bring your own certificates recipe for the full BYOC flow.
global.nats.schedulerUrl and global.nats.dataUrl
The chart exposes two NATS URLs separately:
global.nats.schedulerUrl— the control-plane URL the operator (-nats-url) and the host runtime (--scheduler-nats-url) connect to for workload scheduling and host heartbeats.global.nats.dataUrl— the data-plane URL the host runtime (--data-nats-url) uses for Wasm workload messaging, key-value, and blobstore backends.
Both default to nats://nats.<release-namespace>.svc.cluster.local:4222 when left empty. Splitting them lets workloads target a separate NATS cluster from the scheduler — useful when application traffic and operator coordination live on different brokers.
global:
nats:
schedulerUrl: "nats://control-plane.example.internal:4222"
dataUrl: "nats://data-plane.example.internal:4222"Per-host-group overrides are also available via runtime.hostGroups[].schedulerNatsUrl and runtime.hostGroups[].dataNatsUrl.
operator, nats, runtime — pod labels and annotations
Each deployment accepts podLabels and podAnnotations that are merged into the pod template. This is most commonly used for service mesh injection:
operator:
podLabels:
sidecar.istio.io/inject: "true"
podAnnotations:
proxy.istio.io/config: '{"holdApplicationUntilProxyStarts": true}'
nats:
podLabels:
sidecar.istio.io/inject: "true"
runtime:
podLabels:
sidecar.istio.io/inject: "true"operator
operator.watchNamespaces
By default, the operator watches every namespace in the cluster. Set watchNamespaces to a list of namespace names to scope it down:
operator:
watchNamespaces:
- team-a
- team-bWhen watchNamespaces is populated, the chart drops the operator's cluster-wide ClusterRole and ClusterRoleBinding entirely and renders a set of Role + RoleBinding pairs in each watched namespace instead. Per watched namespace:
<release>-workload-crdcovers theruntime.wasmcloud.devworkload resources —artifacts,workloads,workloadreplicasets,workloaddeployments, plus their/statusand/finalizerssubresources<release>-workload-namespacecovers per-workload core resources —configmaps,secrets,events,services(plusservices/finalizers)<release>-endpointslicecoversendpointslicesfor Kubernetes-native traffic routing
Host CRD grants stay on the namespaced Role in the operator's own namespace (host pods aren't tenant-scoped), and <release>-leader-election continues to live there too. The net effect: an operator.watchNamespaces install holds no cluster-wide permissions for workload resources and can be deployed with namespace-admin RBAC alone for those namespaces.
This namespaced-by-default behavior for the runtime.wasmcloud.dev apiGroup landed in 2.3.0 (#5208). Earlier releases bound the workload CRD verbs cluster-wide even when watchNamespaces was set.
operator.hostNamespaces
List of namespaces where host pods run. The operator's pod informer cache and per-namespace pod RBAC cover this set so the host-pod controller can manage finalizers on host pods. Leave empty when host pods only run in the operator's own namespace (the chart's default).
operator:
hostNamespaces:
- team-a
- team-bWhen you set runtime.hostGroups[].namespace to deploy host pods outside the operator's namespace, also include those namespaces here — otherwise the operator can't observe or finalize the host pods running there.
operator.allowSharedHosts
Default: true. Controls whether WorkloadDeployments can schedule onto hosts whose Host.environment differs from the workload's own namespace, via spec.template.spec.environment.
operator:
allowSharedHosts: falseThe default (true) lets workloads with no environment set schedule onto any matching host, regardless of which tenant namespace the host runs in. This is permissive: in a multi-tenant cluster where each tenant has its own namespace and host pods, a workload in team-a can target hosts in team-b simply by setting spec.template.spec.environment: team-b.
Set to false when namespace boundaries are part of your tenant isolation model. With allowSharedHosts: false:
- Scheduling is locked to the workload's own namespace.
- Any cross-namespace
environmentvalue is rejected with aCrossEnvironmentSchedulingDeniedWarning Event and aHostSelection=Falsecondition on the Workload.
See Troubleshooting: Workload stays unscheduled with allowSharedHosts: false for the symptom and resolution patterns.
operator.env, operator.envFrom, and operator.extraArgs
Three passthrough fields that let chart users wire operator-side configuration without forking the chart:
operator.env— additional environment variables for the operator container, appended after the chart-managed vars. Standard Kubernetes env shape (supportsvalueFromwithsecretKeyRef/configMapKeyRef).operator.envFrom— populate the operator container's environment from ConfigMaps or Secrets, using the standard KubernetesenvFromshape.operator.extraArgs— additional CLI args appended verbatim to the operator container, for operator flags the chart does not template (e.g.-leader-elect,-cpu-backpressure-threshold=75).
operator:
env:
- name: LOG_LEVEL
value: debug
envFrom:
- secretRef:
name: operator-extra-config
extraArgs:
- "-leader-elect"operator.probes
Probe timings for the operator deployment (values-driven since 2.9.0), each individually disableable. Liveness fails only on a permanently closed NATS connection (since 2.4.0): the operator stays healthy while reconnecting, so a NATS rolling restart does not restart it. The startup probe (new in 2.9.0) covers the initial NATS connect window, since the operator binds its health port only after connecting.
operator:
probes:
startup:
periodSeconds: 5
failureThreshold: 24
liveness:
initialDelaySeconds: 15
periodSeconds: 20
failureThreshold: 3
readiness:
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 3operator.image.tag
Defaults to the chart's appVersion. Override only when you need to pin to a specific operator build that differs from the chart release:
operator:
image:
tag: "2.9.0"The same pattern applies to gateway.image.tag and runtime.image.tag.
gateway (deprecated)
The runtime-gateway is deprecated (since 2.0.3) and will be removed in a future release. HTTP routing is handled by the runtime-operator via EndpointSlices tied to user-defined Kubernetes Services. See Expose a Workload via Kubernetes Service for the replacement pattern.
To skip installing the gateway, set gateway.enabled: false.
gateway:
enabled: falseruntime
Three 2.9.0 values render host flags that a pre-2.9.0 host image refuses, crash-looping the pod: probes.endpoint.enabled (--probe-addr), runtime.drainDelaySeconds (--drain-delay), and runtime.natsConnectTimeoutSeconds (--nats-connect-timeout). probes.endpoint.enabled: false can be set per host group, but the other two are chart-wide with no per-group override, so a release containing a pinned older host image must clear both for every group, or split the pinned hosts into their own release.
runtime.env, runtime.envFrom, and runtime.extraArgs
Chart-wide host configuration applied to every host group's container. Per-host-group values (see runtime.hostGroups[].env etc.) are appended after these, letting one group extend the chart-wide defaults without redefining them.
runtime.env— additional environment variables applied to every host group container, appended after the chart-managed vars (WASMCLOUD_HOST_IP,WASMCLOUD_HOST_ENVIRONMENT) and before any per-host-groupenv.runtime.envFrom— populate every host group container's environment from ConfigMaps or Secrets.runtime.extraArgs— additional CLI args appended to every host group container, for host flags the chart does not template. Merged with per-host-groupextraArgs.
runtime:
env:
- name: RUST_LOG
value: info
envFrom:
- configMapRef:
name: shared-host-config
extraArgs:
- "--max-concurrent-workloads=64"runtime.hostGroups
A host group is a Deployment of pods running the wash host. You can define multiple groups to isolate workloads or provide specialized capabilities (e.g. WebGPU-enabled hosts):
runtime:
hostGroups:
- name: default
replicas: 3
http:
enabled: true
port: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
- name: gpu
replicas: 1
webgpu:
enabled: trueWorkloadDeployment manifests target a group via spec.template.spec.hostSelector.hostgroup.
runtime.hostGroups[].namespace
Namespace to deploy this host group's Deployment, Service, generated TLS Secret, and ServiceAccount into. Empty (default) deploys to the chart release's namespace.
runtime:
hostGroups:
- name: team-a
namespace: team-a
replicas: 2When you override this, ensure the namespace exists and is included in operator.hostNamespaces so the operator has the pod RBAC and informer cache access it needs to manage host pod lifecycle there. Each host's Host.environment will reflect the namespace where its pod runs, which is what allowSharedHosts: false matches against for namespace-scoped scheduling.
runtime.hostGroups[].schedulerNatsUrl and runtime.hostGroups[].dataNatsUrl
Per-host-group overrides for the NATS URLs the host runtime connects to. Both fall back to the chart-wide global.nats.schedulerUrl / global.nats.dataUrl when empty, which in turn fall back to the in-cluster NATS service.
runtime:
hostGroups:
- name: edge
replicas: 2
dataNatsUrl: "nats://edge-data.example.internal:4222"Use this when a single chart release runs host groups against different data-plane brokers (for example, regional NATS clusters for an edge group while the default group stays on the in-cluster broker).
runtime.hostGroups[].env, envFrom, and extraArgs
Per-host-group versions of the chart-wide runtime.env / envFrom / extraArgs fields. These are appended after the chart-wide values, so a group can extend the shared defaults without redeclaring them.
runtime:
env:
- name: RUST_LOG
value: info
hostGroups:
- name: gpu
replicas: 1
env:
- name: RUST_LOG
value: debug # overrides the chart-wide value for this group only
extraArgs:
- "--wasi-webgpu-debug"runtime.hostGroups[].volumes, volumeMounts, and ports
Optional passthrough fields rendered directly into the host group's pod and container spec, letting chart users mount ConfigMaps / Secrets / persistent volumes and expose extra container ports without forking the chart.
runtime.hostGroups[].volumes— appended to the pod'sspec.volumes. Standard Kubernetes volume shape.runtime.hostGroups[].volumeMounts— appended to the host container'svolumeMounts. Pair each entry with a matchingvolumesentry above.runtime.hostGroups[].ports— appended to the host container'sports. Typically used to expose a metrics scrape port for Prometheus.
runtime:
hostGroups:
- name: default
replicas: 3
volumes:
- name: app-config
configMap:
name: my-host-config
volumeMounts:
- name: app-config
mountPath: /etc/wasmcloud/config
readOnly: true
ports:
- name: metrics
containerPort: 9090
protocol: TCPAll three fields render unconditionally, so they survive a global.tls.enabled: false install. Do not re-list the HTTP port in ports — the chart already renders it from .http.port, and a duplicate containerPort fails Deployment validation. See Filesystems and Volumes for the broader volume story.
runtime.hostGroups[].wasmProposals
A per-host-group list of top-level Wasm proposals to enable on the engine. The chart renders each entry as a --wasm-proposal argument on the host container.
runtime:
hostGroups:
- name: default
replicas: 3
# Enable the async component model + garbage collection proposals for this group.
wasmProposals:
- component-model-async
- gcRecognized values are component-model-async, component-model-map (added in 2.7.0), gc, exception-handling, wide-arithmetic, threads, and tail-call. WASI 0.3 always brings the component-model-async proposal along with it, and as of wasmCloud 2.7.0 the engine also enables the Component Model map type proposal unconditionally, so neither needs to be listed explicitly on 2.7.0-and-later hosts.
runtime.hostGroups[].http.port
The port the host's HTTP server listens on inside the pod, and the port the operator populates into each managed EndpointSlice. The upstream chart default is 9191; the values.local.yaml overlay overrides it to 80 for local development.
runtime.hostGroups[].webgpu.enabled
Enables the WebGPU plugin on hosts in the group. Requires a host image built with the wasi-webgpu feature.
runtime.ociCaPaths and runtime.hostGroups[].ociCaPaths
Introduced in 2.7.0. PEM bundles of additional CA certificates the host trusts when pulling artifacts (e.g., workload components, host component plugins, or washlet artifacts) from OCI registries. runtime.ociCaPaths applies chart-wide; the per-host-group form is additive. The chart renders entries as --oci-ca-path arguments (the paths must be mounted into the pod via volumes/volumeMounts).
For an in-cluster registry signed by the chart's own CA (with global.tls.enabled), the CA bundle is already mounted:
runtime:
ociCaPaths:
- /runtime-cert/ca.crtPrefer this over --allow-insecure-registries, which switches every registry to plain HTTP. Credentials travel in the clear and no certificate is checked at all.
For trusting private CAs on components' outbound HTTPS (a separate mechanism from OCI pulls), pass --http-client-ca-path/--http-client-trust-roots via runtime.hostGroups[].extraArgs with the bundle mounted the same way.
runtime.resources.defaultHeapMemory and runtime.resources.coreInstances
Introduced in 2.8.0. Wasmtime engine sizing for hosts, set inside the resources block alongside the Kubernetes requests and limits (the chart strips them out before rendering the container resources). Both are passed to the host as environment variables, so older host images ignore them.
defaultHeapMemory: Ceiling on any single guest linear memory. Defaults to wasmtime's 4 GiB.coreInstances: Number of instance slots in wasmtime's pooling allocator. Defaults to 1000.
Sizes accept Kubernetes quantity suffixes (Gi/GiB binary, G/GB decimal, bare values are bytes):
runtime:
resources:
limits:
memory: "2Gi"
defaultHeapMemory: "512Mi"
coreInstances: "500"The chart also forwards resources.limits.memory to the host as its guest memory budget, set as the WASH_HOST_MAX_GUEST_MEMORY environment variable rather than the --max-guest-memory flag so an older host image ignores it (since 2.8.0). When no limit is set, the host derives the budget as three quarters of the cgroup or physical memory limit, clamped between 256 MiB and 1 TiB. Since 2.9.0 the host counts guest memory use against the budget and can enforce it; see guestMemoryMode below.
These values size the engine for the whole host; they are not per-workload limits. A host group with its own resources block replaces the chart-wide runtime.resources wholesale, so repeat these keys per group if you use both.
runtime.resources.guestMemoryMode
How the host treats the guest memory budget (since 2.9.0): count, the default when unset, records what enforcement would refuse without refusing anything; enforce refuses guest memory growth past the budget. Set inside the resources block like the sizing values above; passed to the host as the WASH_GUEST_MEMORY_MODE environment variable.
Under enforce, a guest whose memory.grow would cross the budget sees the growth fail (the same result as hitting its own heap ceiling), not a trap. A refusal during instantiation surfaces as a workload start error. The host publishes guest_memory.in_use, guest_memory.high_water, guest_memory.limit, guest_memory.refused, and guest_memory.would_refuse metrics whenever an OpenTelemetry exporter is configured, so the intended rollout is: run in count, watch high_water and would_refuse, then switch to enforce. (See metrics you can scale on for the host's guest metrics generally.)
Leave headroom. The chart forwards resources.limits.memory verbatim, so an enforced budget equal to the pod limit can be OOM-killed before a refusal ever fires; the host warns at startup when an enforced budget exceeds 90% of the detected memory limit. Set limits.memory above the guest budget you want, or set a lower budget explicitly with WASH_HOST_MAX_GUEST_MEMORY in runtime.env.
runtime.resources.maxConcurrentStarts
How many workload starts, the image pull plus the compile, a host admits at once (since 2.9.0); further start commands queue. Set inside the resources block; passed as WASH_MAX_CONCURRENT_STARTS. When unset, the host sizes it to one fewer than the CPUs it can see, clamped between 1 and 4, and logs the effective value on its startup line. A literal 0 is preserved by the chart and clamps to 1.
Compilation runs off the host's serving runtime (since 2.9.0), so a host keeps heartbeating and serving traffic through a burst of starts, and a stop command can overtake a queued start. Each admitted compile spreads across every core the process can see, so this value bounds how many compiles contend with serving traffic, not how many threads a compile uses. To make each compile single-threaded instead, set WASMTIME_PARALLEL_COMPILATION=false in runtime.env.
runtime.probes and runtime.hostGroups[].probes
Host pods expose HTTP health endpoints on a dedicated probes port (since 2.9.0; default 8081, rendered as --probe-addr):
/livezmeans "restart me": it fails when the host's command loop has stalled or its HTTP ingress has stopped permanently./readyzmeans "stop sending me work": it fails while the host isstartingordraining, and while the HTTP ingress connection ceiling is reached.
The failure body names the failing condition, so kubectl describe pod shows why a probe failed. Chart defaults:
runtime:
probes:
endpoint:
enabled: true # false restores the pre-2.9.0 TCP probe on the http port
port: 8081
startupFailureThreshold: 60 # 60 failures at the fixed 5s startup period, a 5 minute budget
readiness:
enabled: true
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 1
failureThreshold: 3
liveness:
enabled: true # also gates the startup probe
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 5Liveness is deliberately slower than readiness: a restart loses every workload on the host. Unlike resources, a per-group hostGroups[].probes block overlays runtime.probes field by field, so a group can retune one timing without redeclaring the rest. The chart refuses to render when the probe port collides with the group's HTTP port or a declared container port.
runtime.drainDelaySeconds and runtime.natsConnectTimeoutSeconds
Host pods drain on termination instead of exiting immediately (since 2.9.0):
- On SIGTERM the host reports
draining: readiness fails and the pod leaves its Service endpoints while the host is still serving. - The host keeps serving for
runtime.drainDelaySeconds(default5, rendered as--drain-delay). - In-flight commands get 5 seconds to finish, and each plugin's stop is capped by
WASH_PLUGIN_STOP_TIMEOUT_SECS(default 5 seconds) plus a 1 second grace.
The chart now sets terminationGracePeriodSeconds on every pod (previously hardcoded to 0): runtime: 15, operator: 45, gateway: 45, nats: 30. Rendering fails if the runtime grace is less than drainDelaySeconds + 5. A second signal exits immediately rather than waiting out the drain.
runtime.natsConnectTimeoutSeconds (default 60, rendered as --nats-connect-timeout) lets a starting host wait for a NATS server that is not up yet instead of exiting and burning pod restarts.
runtime.hostGroups[].networking
Maps to the host's socket policy and connection quota flags. The chart renders these keys as host flags since 2.9.0; the block existed in the 2.8.0 values file but was not wired to the host, so on earlier charts set these through extraArgs:
| Key | Default | Host flag |
|---|---|---|
allowHostLoopback | false | --allow-host-loopback |
socketEgress | count | --socket-egress |
denySpecialRanges | true | --deny-special-ranges |
denyPrivateRanges | false | --deny-private-ranges |
maxConnections | empty (derived from the descriptor limit) | --max-connections |
maxOutboundHttpConnectionsPerWorkload | 128 | --max-outbound-http-connections-per-workload |
maxOutboundSocketConnectionsPerWorkload | 256 | --max-outbound-socket-connections-per-workload |
maxInboundSocketConnectionsPerWorkload | 256 | --max-inbound-socket-connections-per-workload |
maxHttpIngressConnections | empty (a quarter of the descriptor limit, floor 256; since 2.9.0) | --max-http-ingress-connections |
allowHostLoopback and denyPrivateRanges render as presence flags, so setting them to false is the same as omitting them; only denySpecialRanges renders an explicit value. See Concurrency and connections and Workload security for what these bound. publishPorts and publishPortRange appear in the values file but are not yet wired to the host; setting them has no effect.
runtime.hostGroups[].plugins
One declaration block configures host plugins of both kinds (since 2.9.0): native plugins built into the host (an entry with only an id) and host component plugins (an entry with an image or file source). A native entry, and any entry carrying config, secrets, allowlists, or binding fields, is rendered into the host's config file rather than CLI arguments, so credentials never appear in the pod spec; a bare component entry (id plus a source) still renders as a --host-plugin argument. Each entry accepts:
config/configFrom/secretFrom: entry-wide configuration, layered under each binding's own.workloadConfig:deny(the default),warn, orallow. Underdeny, host-owned keys (connection and credential settings) come only from this declaration: a workload manifest that sets one or widens a grant ceiling is refused at deploy, and once any binding is declared for a plugin, so is a manifest naming a binding the declaration does not carry.warnbehaves likeallowbut logs everythingdenywould refuse, for rehearsing a lockdown.hostOwnedKeys: additional keys to claim for the host underdeny.bindings: a map of label to{config, configFrom, secretFrom}. A component imports the plugin's interface under that label (the Component Model'simplementsclause), and the labeled import resolves against the binding's config layered over the entry's.- Component-plugin-only fields:
maxRestarts,digest(an OCI digest pin),allowedHosts,allowedIpNameLookups. (Aportsfield appears in the values file but is not yet wired to the host.)
runtime:
hostGroups:
- name: default
plugins:
- id: wasmcloud-nats
workloadConfig: deny
config:
servers: nats://nats.example.com:4222
subject-allow: 'orders.>'
secretFrom:
- name: nats-credsruntime.hostGroups[].hostPlugins remains as a deprecated alias: its entries are concatenated onto plugins and rendered identically, so prefer plugins for new declarations. The chart refuses to render the removed wasmcloudNats and wasmcloudNatsWorkloadConfig keys with a message pointing at plugins.
runtime.hostGroups[].wasmcloudNatsUrl
The default NATS address for the wasmcloud:nats plugin's per-workload connections (since 2.9.0; rendered as --wasmcloud-nats-url). Empty means the group's data NATS URL and its TLS settings; when set, the data plane's TLS does not carry over. The inherited bundle is address and TLS only, never credentials; provide credentials through the plugin's plugins entry.
runtime.hostGroups[].http.tls.certificate.generate.ipAddresses
Introduced in 2.7.0. Additional IP SANs for the host group's generated TLS certificate; needed when clients reach the host group by IP rather than name. Note that the chart reuses an existing hostgroup-<name>-http-tls Secret if one exists, so adding ipAddresses to a live release takes effect only after that Secret is deleted and the certificate regenerated.
runtime.image.tag
Defaults to the chart's appVersion; leave unset to track the chart release.
Related documentation
- Kubernetes Operator introduction — install and deploy walk-through
- Private Registries — mirroring images for air-gapped deployments
- TLS: bring your own certificates
- Expose a Workload via Kubernetes Service