@@ -1307,10 +1307,15 @@ serve_debug() {
13071307 kubectl describe pods -n " ${SERVE_NAMESPACE} " 2>&1 || true
13081308 echo " --- events ---"
13091309 kubectl get events -n " ${SERVE_NAMESPACE} " --sort-by=.lastTimestamp 2>&1 || true
1310- echo " --- logs (all pods, all containers, last 200 lines) ---"
1310+ echo " --- logs (all pods, all containers, last 200 lines; --previous for crash loops ) ---"
13111311 for p in $( kubectl get pods -n " ${SERVE_NAMESPACE} " -o name 2> /dev/null) ; do
13121312 echo " === ${p} ==="
13131313 kubectl logs -n " ${SERVE_NAMESPACE} " " ${p# pod/ } " --all-containers --tail=200 2>&1 || true
1314+ # CrashLoopBackOff replaces the current container before this dump
1315+ # runs, so the dying process's stdout is on --previous. Missing
1316+ # previous (first start, or already GC'd) is a no-op.
1317+ echo " === ${p} (previous) ==="
1318+ kubectl logs -n " ${SERVE_NAMESPACE} " " ${p# pod/ } " --all-containers --previous --tail=200 2>&1 || true
13141319 done
13151320 } | tee serve-logs/" ${SERVE_NAME} " .log
13161321}
@@ -1384,7 +1389,24 @@ spec:
13841389 - name: main
13851390 image: ${SERVE_RUNTIME_IMAGE}
13861391 workingDir: /workspace/examples/backends/vllm
1387- command: ["python3", "-m", "dynamo.vllm"]
1392+ # A bare ` python3 -m dynamo.vllm` here crash-looped on GKE before
1393+ # binding its health port (run 32732018329), while inference-perf
1394+ # served the same runtime on the SAME cluster minutes earlier
1395+ # using this wrapper. GKE mounts the node driver at
1396+ # /usr/local/nvidia without putting it on LD_LIBRARY_PATH, so
1397+ # vLLM cannot dlopen libcuda.so.1 ("Failed to infer device type",
1398+ # observed live in gke-default qualification — see the same
1399+ # wrapper in validators/performance/testdata/inference).
1400+ # Shell APPEND with \$ {VAR:+} so we do not clobber
1401+ # the image's nixl/ucx/cuda entries or create a leading empty
1402+ # ld.so entry. Harmless no-op when the path is absent (EKS/AKS
1403+ # GPU Operator toolkit). \$ so the unquoted heredoc does not
1404+ # expand LD_LIBRARY_PATH at render time.
1405+ command:
1406+ - /bin/bash
1407+ - -c
1408+ - export LD_LIBRARY_PATH="\$ {LD_LIBRARY_PATH:+\$ {LD_LIBRARY_PATH}:}/usr/local/nvidia/lib64"; exec python3 -m dynamo.vllm "\$ @"
1409+ - dynamo.vllm
13881410 args:
13891411 - --model
13901412 - ${SERVE_MODEL}
@@ -1402,9 +1424,12 @@ phase_serve() {
14021424 # DynamoGraphDeployment in demos/cuj2-inference.md
14031425 # (demos/workloads/inference/vllm-agg.yaml): the KAI queue and a
14041426 # two-component (Frontend + decode Worker) graph serving an OpenAI-compatible
1405- # endpoint. Frontend placement intentionally diverges — the demo pins
1406- # nodeGroup=cpu-worker; this graph selects the GPU pool for both components
1407- # (pool-selection note below, #1644). The worker requests its GPU as a scalar
1427+ # endpoint. Two intentional divergences from the demo: Frontend placement
1428+ # (the demo pins nodeGroup=cpu-worker; this graph selects the GPU pool for
1429+ # both components — pool-selection note below, #1644), and the worker
1430+ # command (the demo uses python3 -m dynamo.vllm; this graph wraps it with
1431+ # the GKE driver-lib append used by inference-perf, or vLLM cannot see
1432+ # libcuda.so.1 on gke-default). The worker requests its GPU as a scalar
14081433 # nvidia.com/gpu limit — the device-plugin production default (#1327).
14091434 #
14101435 # Tolerations are a portable SUPERSET of the taints across all UAT clusters
@@ -1424,7 +1449,9 @@ phase_serve() {
14241449 # no device: the Frontend declares no nvidia.com/gpu limit, so the device
14251450 # plugin never allocates one to it. This matches how the inference-perf
14261451 # validator places every component on the GPU cohort
1427- # (validators/performance/inference_perf_constraint.go).
1452+ # (validators/performance/inference_perf_constraint.go). The worker command
1453+ # is the same GKE driver-lib append as that validator's Dynamo templates;
1454+ # without it, vLLM crash-loops on gke-default (run 32732018329).
14281455 #
14291456 # This selects the POOL, not a node: the pool holds two GPU nodes and nothing
14301457 # constrains the two components to the same one, so they may be split. That is
0 commit comments