Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ai-ml/gke-ray/kueue-concurrent-admission/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Run ephemeral RayJobs with Kueue concurrent admission

[![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://ssh.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https://github.com/GoogleCloudPlatform/kubernetes-engine-samples&cloudshell_tutorial=README.md&cloudshell_workspace=ai-ml/gke-ray/kueue-concurrent-admission)

These samples show how to start ephemeral RayJobs faster across multiple
resource flavors by using Kueue concurrent admission on Google Kubernetes
Engine (GKE).
84 changes: 84 additions & 0 deletions ai-ml/gke-ray/kueue-concurrent-admission/ephemeral-rayjob.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START gke_ai_ml_gke_ray_kueue_concurrent_admission_ephemeral_rayjob]
apiVersion: ray.io/v1
kind: RayJob
metadata:
name: ephemeral-gpu-job
labels:
# Kueue admits this RayJob through the LocalQueue defined in kueue-setup.yaml.
kueue.x-k8s.io/queue-name: user-queue
spec:
entrypoint: |
python -c "
import ray, time, socket
ray.init()
print('Cluster resources:', ray.cluster_resources())
@ray.remote(num_gpus=1)
def gpu_task(task_id):
ip = socket.gethostbyname(socket.gethostname())
print(f'Task {task_id} running on node with IP: {ip}')
time.sleep(5)
return ip
futures = [gpu_task.remote(i) for i in range(3)]
results = ray.get(futures)
print('Tasks successfully executed on nodes:', set(results))
"
# Delete the RayCluster after the job finishes, which makes the job ephemeral.
shutdownAfterJobFinishes: true
rayClusterSpec:
rayVersion: '2.58.0'
headGroupSpec:
rayStartParams:
dashboard-host: '0.0.0.0'
template:
spec:
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
containers:
- name: ray-head
image: rayproject/ray:2.58.0
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "1"
memory: "2Gi"
workerGroupSpecs:
- groupName: worker-group
replicas: 3
minReplicas: 3
maxReplicas: 3
rayStartParams: {}
template:
spec:
nodeSelector:
cloud.google.com/gke-accelerator: nvidia-tesla-t4
containers:
- name: ray-worker
image: rayproject/ray:2.58.0
resources:
requests:
nvidia.com/gpu: "1"
cpu: "2"
memory: "8Gi"
limits:
nvidia.com/gpu: "1"
cpu: "2"
memory: "8Gi"
# [END gke_ai_ml_gke_ray_kueue_concurrent_admission_ephemeral_rayjob]
76 changes: 76 additions & 0 deletions ai-ml/gke-ray/kueue-concurrent-admission/kueue-setup.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START gke_ai_ml_gke_ray_kueue_concurrent_admission_kueue_setup]
apiVersion: kueue.x-k8s.io/v1beta2
kind: ResourceFlavor
metadata:
name: reservation-flavor
spec:
nodeLabels:
cloud.google.com/gke-nodepool: gpu-pool-reservation
---
apiVersion: kueue.x-k8s.io/v1beta2
kind: ResourceFlavor
metadata:
name: dws-flex-flavor
spec:
nodeLabels:
cloud.google.com/gke-nodepool: gpu-pool-dws-flex
---
apiVersion: kueue.x-k8s.io/v1beta2
kind: ClusterQueue
metadata:
name: cluster-queue
spec:
namespaceSelector: {}
queueingStrategy: BestEffortFIFO
# Concurrent admission lets Kueue provision capacity in several flavors at
# the same time instead of trying them one after another.
concurrentAdmissionPolicy:
migration:
# Move the workload to an earlier (more preferred) flavor if that flavor
# becomes ready first.
mode: TryPreferredFlavors
constraints:
# Stop trying additional flavors once this flavor is reached.
lastAcceptableFlavorName: reservation-flavor
resourceGroups:
- coveredResources: ["nvidia.com/gpu", "cpu", "memory"]
flavors:
- name: reservation-flavor
resources:
- name: "nvidia.com/gpu"
nominalQuota: "3"
- name: "cpu"
nominalQuota: "8"
- name: "memory"
nominalQuota: "32Gi"
- name: dws-flex-flavor
resources:
- name: "nvidia.com/gpu"
nominalQuota: "3"
- name: "cpu"
nominalQuota: "8"
- name: "memory"
nominalQuota: "32Gi"
---
apiVersion: kueue.x-k8s.io/v1beta2
kind: LocalQueue
metadata:
name: user-queue
namespace: default
spec:
clusterQueue: cluster-queue
# [END gke_ai_ml_gke_ray_kueue_concurrent_admission_kueue_setup]