Repository navigation
Description
Steps to reproduce
-
Configure the
kubernetesbackend with a cluster that has two nodes with the same GPU, for example one A100 80GB each, and a fleet withnodes: 0... -
Use the first node's GPU outside dstack, for example with another workload, so that only the second node has a free GPU.
-
Run a task that keeps the GPU busy:
type: task name: busy image: dstackai/base:0.15-base-ubuntu24.04 commands: - sleep 180 resources: gpu: A100
-
While it runs, check
dstack ps -vanddstack offer --gpu A100(or the plan of anotherdstack apply).
Actual behaviour
dstack tries the first node's offer (trying node-a in the server log), and Kubernetes schedules the pod on the second node. dstack ps -v shows the right node:
NAME BACKEND RESOURCES INSTANCE TYPE PRICE STATUS
busy kubernetes cpu=x86:1 mem=1GB disk=10GB gpu=A100:80GB:1 node-b $0 running
But dstack offer and dstack apply list the run's busy instance on the first node:
# BACKEND RESOURCES INSTANCE TYPE PRICE
1 kubernetes cpu=x86:1 gpu=A100:80GB:1 node-a $0
2 kubernetes cpu=x86:1 gpu=A100:80GB:1 node-b $0
3 kubernetes cpu=x86:1 mem=1GB disk=10GB gpu=A100:80GB:1 node-a $0 busy
Expected behaviour
The busy instance is listed on node-b, as in dstack ps -v.
dstack version
master ead2cb470 and 0.22.4.
Notes
Root cause
- When a job is assigned, its instance stores the offer dstack tried (1,`` 2).```` The pod can run on another node: its node affinity selects every node with a matching GPU, not the node of the offer.
- After the pod is scheduled,
instances/check.py````` saves the provisioning data thatupdate_provisioning_data()rebuilds from the pod's node, but leaves the stored offer as it was. - Plans list busy and idle instances from the stored offer (
_get_offers_from_instances()), whiledstack psanddstack fleetuse the provisioning data (instance_model_to_instance()).
Only the display is affected: Kubernetes instances end with their jobs, so the stored offer isn't used to place other runs.
Suggested fix
In _get_offers_from_instances(), take the instance type from the provisioning data when it's set, as instance_model_to_instance() does.
Tested
Reproduced on k3s v1.31. node-b is a real node with nvidia.com/gpu: 1 advertised and the GPU Operator's nvidia.com/gpu.product label. node-a is simulated with kwok, with the same label and the nvidia.com/gpu taint GKE adds to GPU nodes, and its GPU is held by another pod. With the suggested fix, both dstack offer and the dstack apply plan list the busy instance on node-b. The tests in src/tests/_internal/server/services/runs, routers/test_runs.py, routers/test_fleets.py and core/backends/kubernetes pass.
It first showed up on GKE with two A100 nodes: a busy run was listed on the node dstack tried, while its pod ran on the other one.
Generated by Claude Code
Activity