KubeRay Operator
Install
By Helm
$ helm repo add kuberay https://ray-project.github.io/kuberay-helm/
"kuberay" has been added to your repositories
$ helm repo update
$ helm pull kuberay/kuberay-operator
$ helm install kuberay kuberay-operator-1.6.0.tgz -n kuberay --create-namespace
NAME: kuberay
LAST DEPLOYED: Tue Apr 7 14:59:15 2026
NAMESPACE: kuberay
STATUS: deployed
REVISION: 1
TEST SUITE: None
Show installed workloads:
$ kubectl get all -n kuberay
NAME READY STATUS RESTARTS AGE
pod/kuberay-operator-7c458bbb56-lf8ql 1/1 Running 0 33s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kuberay-operator ClusterIP 10.106.211.164 <none> 8080/TCP 33s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/kuberay-operator 1/1 1 1 33s
NAME DESIRED CURRENT READY AGE
replicaset.apps/kuberay-operator-7c458bbb56 1 1 1 33s
Show installed API resources:
$ kubectl api-resources --api-group=ray.io
NAME SHORTNAMES APIVERSION NAMESPACED KIND
rayclusters ray.io/v1 true RayCluster
raycronjobs ray.io/v1 true RayCronJob
rayjobs ray.io/v1 true RayJob
rayservices ray.io/v1 true RayService
Install a ray cluster
Again, by helm:
$ helm pull kuberay/ray-cluster
Install (with autoscaler enabled):
$ helm install ray-cluster ray-cluster-1.6.0.tgz --set head.rayStartParams.num-cpus=0 --set worker.rayStartParams.num-cpus=1 --set head.enableInTreeAutoscaling=true --set worker.replicas=0 --set worker.maxReplicas=50
NAME: ray-cluster
LAST DEPLOYED: Tue Apr 7 15:58:39 2026
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
Show the workloads:
$ kubectl get raycluster,po
NAME DESIRED WORKERS AVAILABLE WORKERS CPUS MEMORY GPUS STATUS AGE
raycluster.ray.io/ray-cluster-kuberay 1 1 1 5Gi 0 ready 58s
NAME READY STATUS RESTARTS AGE
pod/ray-cluster-kuberay-head-ftv6k 2/2 Running 0 58s
pod/ray-cluster-kuberay-workergroup-worker-xldnq 1/1 Running 0 58s
Note
The autoscaler run as a sidecar in the head pod, so there are two containers.
Though
worker.replicasset to 1, there is still one worker started.
Show the service:
$ kubectl get svc -lapp.kubernetes.io/name=kuberay
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ray-cluster-kuberay-head-svc ClusterIP None <none> 10001/TCP,8265/TCP,6379/TCP,8080/TCP,8000/TCP 2m
Check ray status on the head node:
$ kubectl exec -it $(kubectl get pods --selector=ray.io/node-type=head -o custom-columns=POD:metadata.name --no-headers) -- ray status
efaulted container "ray-head" out of: ray-head, autoscaler
======== Autoscaler status: 2026-04-07 02:41:37.379691 ========
Node status
---------------------------------------------------------------
Active:
(no active nodes)
Idle:
1 headgroup
1 workergroup
Pending:
(no pending nodes)
Recent failures:
(no failures)
Resources
---------------------------------------------------------------
Total Usage:
0.0/1.0 CPU
0B/6.00GiB memory
0B/1.52GiB object_store_memory
From request_resources:
(none)
Pending Demands:
(no resource demands)
Submit a job
Forward the service port:
$ kubectl port-forward service/ray-cluster-kuberay-head-svc 8265:8265 > /dev/null &
Then submit a job:
$ ray job submit --address http://localhost:8265 --working-dir . -- python count_hosts.py
You will see the number of workers increased when running and decreased after the job is done.