Просмотр исходного кода

gemma4-12b: working recipe with distributed_backend=none

- Set distributed_backend to "none" (single-node recipe doesn't need NCCL/IB)
- Change served-model-name to short "gemma4-12b"
- Refactor build_docker_command to only inject NCCL/IB env vars when nnodes > 1
- Fix RAY_PORT to correct Redis default (6379, not recipe port)
- Drop port mapping (-p) — unnecessary with --privileged --network=host
- Fix tests to validate correct behavior, not parrot implementation
Alexander Korolev 4 месяцев назад
Родитель
Сommit
9d54d3f94c
3 измененных файлов с 68 добавлено и 43 удалено
  1. 4 3
      recipes/gemma4-12b/recipe.toml
  2. 55 37
      src/docker/mod.rs
  3. 9 3
      src/docker/tests.rs

+ 4 - 3
recipes/gemma4-12b/recipe.toml

@@ -2,10 +2,11 @@ engine = "vllm"
 name = "Gemma 4 12B IT (MTP)"
 docker_image = "vllm/vllm-openai:gemma4-unified"
 model = "google/gemma-4-12B-it"
-port = 8000
+# docker_image = "ghcr.io/timothystewart6/vllm-gb10:v0.23.0-gb10.1"
+# model = "RedHatAI/gemma-4-12B-it-NVFP4"
 tensor_parallel_size = 1
 pipeline_parallel_size = 1
-distributed_backend = "mp"
+distributed_backend = "none"
 
 # Single-node recipe: Gemma 4 12B with BF16, FP8 KV cache,
 # MTP speculative decoding (5 tokens), 196K context.
@@ -31,7 +32,7 @@ args = [
     "--limit-mm-per-prompt", """
 '{"image":4,"audio":1,"video":1}'""",
     "--trust-remote-code",
-    "--served-model-name", "google/gemma-4-12B-it",
+    "--served-model-name", "gemma4-12b",
 ]
 
 [env]

+ 55 - 37
src/docker/mod.rs

@@ -1,11 +1,17 @@
 pub mod health;
 
-use crate::config::{Cluster, Config, NcclConfig, Node, Recipe, load_recipe, resolve_cluster};
-use crate::doctor::try_repaired_image;
-use crate::ssh::{run_ssh, run_ssh_follow, run_ssh_with_retry};
+use std::borrow::Cow;
+
 use anyhow::{Context, Result};
 use tokio::time::{Duration, sleep};
 use tracing::info;
+
+use crate::{
+    config::{Cluster, Config, NcclConfig, Node, Recipe, load_recipe, resolve_cluster},
+    doctor::try_repaired_image,
+    ssh::{run_ssh, run_ssh_follow, run_ssh_with_retry},
+};
+
 pub async fn serve(
     config: &Config,
     recipe_name: &str,
@@ -335,52 +341,62 @@ fn build_docker_command(
     if !keep {
         flags.push("--rm".to_string());
     }
+
     let mut cmd = vec![
         format!("docker run -d {}", flags.join(" ")),
-        format!("-e NCCL_IB_DISABLE={}", nccl.ib_disable),
-        format!("-e NCCL_IB_HCA={}", nccl.ib_hca),
-        format!("-e NCCL_SOCKET_IFNAME={}", nccl.socket_ifname),
-        format!("-e GLOO_SOCKET_IFNAME={}", nccl.socket_ifname),
-        format!("-e TP_SOCKET_IFNAME={}", nccl.socket_ifname),
-        format!("-e NCCL_IB_GID_INDEX={}", nccl.ib_gid_index),
-        format!("-e HF_HOME=/root/.cache/huggingface"),
         format!("-v {}:/root/.cache/huggingface", cache_dir),
     ];
-    if is_sglang {
-        cmd.push(format!("-e SGLANG_WORKER_IP={}", node.ib_ip));
-    } else {
-        cmd.push(format!("-e VLLM_HOST_IP={}", node.ib_ip));
+
+    let mut env = vec![("HF_HOME", Cow::Borrowed("/root/.cache/huggingface"))];
+    if nnodes > 1 {
+        let worker_ip = Cow::Borrowed(node.ib_ip.as_str());
+        if is_sglang {
+            env.push(("SGLANG_WORKER_IP", worker_ip));
+        } else {
+            env.push(("VLLM_HOST_IP", worker_ip));
+        }
+        let nccl_socket_ifname = nccl.socket_ifname.as_str();
+        env.extend([
+            ("NCCL_IB_DISABLE", format!("{}", nccl.ib_disable).into()),
+            ("NCCL_IB_HCA", nccl.ib_hca.as_str().into()),
+            ("NCCL_SOCKET_IFNAME", nccl_socket_ifname.into()),
+            ("GLOO_SOCKET_IFNAME", nccl_socket_ifname.into()),
+            ("TP_SOCKET_IFNAME", nccl_socket_ifname.into()),
+            ("NCCL_IB_GID_INDEX", nccl.ib_gid_index.to_string().into()),
+            ("MN_IF_NAME", nccl_socket_ifname.into()),
+            ("UCX_NET_DEVICES", nccl_socket_ifname.into()),
+            ("OMPI_MCA_btl_tcp_if_include", nccl_socket_ifname.into()),
+            ("OMP_NUM_THREADS", "4".into()),
+            ("NCCL_IGNORE_CPU_AFFINITY", "1".into()),
+            ("NCCL_NET", "IB".into()),
+            ("NCCL_DEBUG", "WARN".into()),
+        ]);
     }
-    cmd.push(format!("-e MN_IF_NAME={}", nccl.socket_ifname));
-    cmd.push(format!("-e UCX_NET_DEVICES={}", nccl.socket_ifname));
-    cmd.push(format!(
-        "-e OMPI_MCA_btl_tcp_if_include={}",
-        nccl.socket_ifname
-    ));
-    cmd.push("-e OMP_NUM_THREADS=4".to_string());
-    cmd.push("-e NCCL_IGNORE_CPU_AFFINITY=1".to_string());
-    cmd.push("-e NCCL_NET=IB".to_string());
-    cmd.push("-e NCCL_DEBUG=WARN".to_string());
     if is_head {
-        cmd.push("-e VLLM_LOGGING_COLOR=1".to_string());
-        cmd.push("-e TERM=xterm-256color".to_string());
+        env.push(("VLLM_LOGGING_COLOR", "1".into()));
+        env.push(("TERM", "xterm-256color".into()));
     }
     for (k, v) in &recipe.env {
-        cmd.push(format!("-e {}={}", k, v));
-    }
-    if is_head {
-        cmd.push(format!("-p {}:{}", recipe.port, recipe.port));
+        env.push((k.as_str(), v.as_str().into()));
     }
     cmd.push(format!("--name sm121_{}_{}", recipe_name, node.rank));
     cmd.push(format!("--label sm121.recipe={}", recipe_name));
     cmd.push(format!("--label sm121.rank={}", node.rank));
     if recipe.distributed_backend == "ray" {
-        cmd.push(format!("-e RAY_ADDRESS={}:6379", cluster.master_ib_ip));
-        cmd.push(format!("-e RAY_PORT={}", recipe.port));
-        cmd.push(format!("-e RAY_NODE_IP_ADDRESS={}", node.ib_ip));
-        cmd.push(format!("-e RAY_OVERRIDE_NODE_IP_ADDRESS={}", node.ib_ip));
+        env.push((
+            "RAY_ADDRESS",
+            format!("{}:6379", cluster.master_ib_ip).into(),
+        ));
+        env.push(("RAY_PORT", "6379".into()));
+        env.push(("RAY_NODE_IP_ADDRESS", node.ib_ip.as_str().into()));
+        env.push(("RAY_OVERRIDE_NODE_IP_ADDRESS", node.ib_ip.as_str().into()));
+    }
+    for (k, v) in env {
+        cmd.push(format!("-e {k}={v}"));
     }
+
     cmd.push(recipe.docker_image.clone());
+
     if !recipe.entrypoint.is_empty() {
         let mut ep = recipe.entrypoint.clone();
         if ep.len() >= 3 && ep[ep.len() - 2] == "-c" {
@@ -389,13 +405,14 @@ fn build_docker_command(
         }
         cmd.extend(ep);
     }
+
     if is_sglang {
         cmd.push("--model-path".to_string());
-        cmd.push(recipe.model.clone());
-    } else {
-        cmd.push(recipe.model.clone());
     }
+    cmd.push(recipe.model.clone());
+
     cmd.extend(recipe.args.clone());
+
     let mut flags: Vec<String> = match recipe.distributed_backend.as_str() {
         "ray" | "mp" if is_sglang => vec![
             "--tp".into(),
@@ -440,5 +457,6 @@ fn build_docker_command(
     cmd.push(recipe.port.to_string());
     cmd
 }
+
 #[cfg(test)]
 mod tests;

+ 9 - 3
src/docker/tests.rs

@@ -96,8 +96,11 @@ fn mp() {
     assert!(cmd.contains("docker run -d --gpus all"));
     assert!(cmd.contains("-e NCCL_IB_HCA=r"));
     assert!(cmd.contains("-e K=V"));
-    assert!(cmd.contains("-p 8000:8000"));
     assert!(cmd.contains("--name sm121_r_0"));
+    assert!(
+        !cmd.contains("-p "),
+        "host networking: no port mapping expected"
+    );
     assert!(cmd.contains("--label sm121.recipe=r"));
     assert!(cmd.contains("--label sm121.rank=0"));
     assert!(cmd.contains("img"));
@@ -176,7 +179,7 @@ fn ray_backend() {
     r.distributed_backend = "ray".into();
     let cmd = run(&r, &tcls().nodes[0], true);
     assert!(cmd.contains("-e RAY_ADDRESS=1:6379"));
-    assert!(cmd.contains("-e RAY_PORT=8000"));
+    assert!(cmd.contains("-e RAY_PORT=6379"));
     assert!(cmd.contains("--node-rank 0"));
     assert!(cmd.contains("--distributed-executor-backend ray"));
 }
@@ -270,8 +273,11 @@ fn sglang_head() {
     assert!(!cmd.contains("--tensor-parallel-size"));
     assert!(!cmd.contains("--pipeline-parallel-size"));
     assert!(!cmd.contains("--distributed-executor-backend"));
-    assert!(cmd.contains("-p 8000:8000"));
     assert!(cmd.contains("-e TORCH_NCCL_ASYNC_ERROR_HANDLING=1"));
+    assert!(
+        !cmd.contains("-p "),
+        "host networking: no port mapping expected"
+    );
     assert!(cmd.contains("--port 8000"));
     assert!(cmd.contains("-e HF_HOME=/root/.cache/huggingface"));
     assert!(cmd.contains("-v /home/user/.cache/huggingface:/root/.cache/huggingface"));