Problem
Ray's large-cluster best practices recommend setting resources: {"CPU": 0} on the head node so tasks and actors aren't scheduled there:
"Due to the heavy networking load (and the GCS and dashboard processes), we recommend setting the quantity of logical CPU resources to 0 on the head node."
On KubeRay this is configured via headGroupSpec.rayStartParams.num-cpus: "0" (and typically num-gpus: "0"). However, in chart/templates/rayservice.yaml at the current chart version, the head's rayStartParams block is hard-coded:
headGroupSpec:
rayStartParams:
dashboard-host: "0.0.0.0"
There is no {{ toYaml .Values.head.rayStartParams }} rendering, so any head.rayStartParams set via values is silently ignored. The same is effectively true for workers — the workerGroupSpec uses rayStartParams: {} with no values surface.
This forces operators who want to follow Ray's head-node guidance to either fork the chart or apply Kustomize patches on top of the rendered Helm output, both of which are significant overhead for a one-line template change.
Proposal
Expose head.rayStartParams and worker.rayStartParams as values-level dicts, with the chart's existing keys (e.g. dashboard-host) merged in as defaults that users can override.
Values addition (chart/values.yaml):
head:
# ...existing keys...
# Ray start parameters merged into headGroupSpec.rayStartParams.
# The chart sets `dashboard-host: "0.0.0.0"` by default; add other
# parameters here, e.g. num-cpus: "0" to follow Ray's head-node guidance:
# https://docs.ray.io/en/latest/cluster/vms/user-guides/large-cluster-best-practices.html#configuring-the-head-node
rayStartParams: {}
worker:
# ...existing keys...
rayStartParams: {}
Template change (chart/templates/rayservice.yaml):
headGroupSpec:
rayStartParams:
dashboard-host: "0.0.0.0"
{{- with .Values.head.rayStartParams }}
{{- toYaml . | nindent 8 }}
{{- end }}
workerGroupSpecs:
- ...
rayStartParams:
{{- with .Values.worker.rayStartParams }}
{{- toYaml . | nindent 8 }}
{{- end }}
(Or merge via mergeOverwrite so user-set keys always win over chart defaults — equivalent for a flat dict.)
Example: applying Ray's head-node recommendation
After this change, an operator could write:
head:
rayStartParams:
num-cpus: "0"
num-gpus: "0"
…and the rendered RayService would have:
headGroupSpec:
rayStartParams:
dashboard-host: "0.0.0.0"
num-cpus: "0"
num-gpus: "0"
This pins Serve replicas and Ray actors/tasks to worker pods, freeing the head for GCS, dashboard, and Serve controller traffic — which is the canonical KubeRay/Ray production pattern.
Why this is more than a corner-case
- The recommendation is explicit in upstream Ray docs and applies to essentially every multi-pod KubeRay deployment.
- Without it, operators routinely hit head-pod resource pressure once Serve replicas grow, especially under load.
rayStartParams is the canonical extension point for Ray cluster behavior on KubeRay; not exposing it forces every chart user to work around the same gap.
References
Problem
Ray's large-cluster best practices recommend setting
resources: {"CPU": 0}on the head node so tasks and actors aren't scheduled there:On KubeRay this is configured via
headGroupSpec.rayStartParams.num-cpus: "0"(and typicallynum-gpus: "0"). However, inchart/templates/rayservice.yamlat the current chart version, the head'srayStartParamsblock is hard-coded:There is no
{{ toYaml .Values.head.rayStartParams }}rendering, so anyhead.rayStartParamsset via values is silently ignored. The same is effectively true for workers — the workerGroupSpec usesrayStartParams: {}with no values surface.This forces operators who want to follow Ray's head-node guidance to either fork the chart or apply Kustomize patches on top of the rendered Helm output, both of which are significant overhead for a one-line template change.
Proposal
Expose
head.rayStartParamsandworker.rayStartParamsas values-level dicts, with the chart's existing keys (e.g.dashboard-host) merged in as defaults that users can override.Values addition (
chart/values.yaml):Template change (
chart/templates/rayservice.yaml):(Or merge via
mergeOverwriteso user-set keys always win over chart defaults — equivalent for a flat dict.)Example: applying Ray's head-node recommendation
After this change, an operator could write:
…and the rendered RayService would have:
This pins Serve replicas and Ray actors/tasks to worker pods, freeing the head for GCS, dashboard, and Serve controller traffic — which is the canonical KubeRay/Ray production pattern.
Why this is more than a corner-case
rayStartParamsis the canonical extension point for Ray cluster behavior on KubeRay; not exposing it forces every chart user to work around the same gap.References
headGroupSpec.rayStartParams