diff --git a/mkdocs/docs/concepts/services.md b/mkdocs/docs/concepts/services.md index a7d24fe9a..0703ce083 100644 --- a/mkdocs/docs/concepts/services.md +++ b/mkdocs/docs/concepts/services.md @@ -170,7 +170,7 @@ both are set per group. Router sits in front of inference backend workers (SGLang, vLLM, TensorRT-LLM) and decides which worker serves each request based on routing policy. -Below is an example for running `Qwen/Qwen3.8-Flash-Next` on `H200`: +Below are examples for running `Qwen/Qwen3.8-Flash-Next` with SMG and `zai-org/GLM-4.5-Air-FP8` with Dynamo on `H200`: === "SMG" @@ -234,77 +234,64 @@ Below is an example for running `Qwen/Qwen3.8-Flash-Next` on `H200`: ```yaml type: service - name: qwen38-flash-next-dynamo + name: glm-45-air-dynamo env: - HF_TOKEN - - MODEL_ID=Qwen/Qwen3.8-Flash-Next + - MODEL_ID=zai-org/GLM-4.5-Air-FP8 groups: - - replicas: 1 - docker: true + # The frontend and the workers discover each other via etcd + - name: etcd + replicas: 1 commands: - - apt-get update - - apt-get install -y python3-dev python3-venv - - python3 -m venv ~/dyn-venv - - source ~/dyn-venv/bin/activate - - pip install -U pip - - pip install "ai-dynamo[sglang]==1.1.1" - - git clone https://github.com/ai-dynamo/dynamo.git - # Brings up the NATS / etcd compose stack and runs the Dynamo HTTP frontend. - - docker compose -f dynamo/dev/docker-compose.yml up -d - | - python3 -m dynamo.frontend \ - --http-host 0.0.0.0 --http-port 8000 \ - --discovery-backend etcd --router-mode kv \ - --kv-cache-block-size 64 + curl -fsSL https://github.com/etcd-io/etcd/releases/download/v3.5.33/etcd-v3.5.33-linux-amd64.tar.gz \ + | tar -xz -C /usr/local/bin --strip-components=1 etcd-v3.5.33-linux-amd64/etcd + - | + etcd \ + --data-dir /tmp/etcd \ + --listen-client-urls http://0.0.0.0:2379 \ + --advertise-client-urls http://$DSTACK_MASTER_NODE_IP:2379 resources: - cpu: 4 + cpu: 2 + + - name: frontend + replicas: 1 + # The vLLM image provides vLLM's GLM tool call and reasoning parsers + image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.5.1 + commands: + - export ETCD_ENDPOINTS=http://${{ groups[0].replicas[0].IP_ADDRESS }}:2379 + - | + python3 -m dynamo.frontend \ + --http-port 8000 \ + --router-mode kv \ + --dyn-chat-processor vllm \ + --enable-auto-tool-choice \ + --tool-call-parser glm45 \ + --reasoning-parser glm45 router: type: dynamo + resources: + cpu: 4 - - replicas: 2 - python: "3.12" - nvcc: true + - name: worker + replicas: 2 + image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.5.1 commands: - # dstack injects DSTACK_ROUTER_INTERNAL_IP after the router replica - # is provisioned. Compose the etcd/NATS endpoints from it. - - export ETCD_ENDPOINTS="http://$DSTACK_ROUTER_INTERNAL_IP:2379" - - export NATS_SERVER="nats://$DSTACK_ROUTER_INTERNAL_IP:4222" - # Set to enable /health endpoint required by dstack probes. - - export DYN_SYSTEM_PORT="8000" - # Wait until the router's etcd and NATS ports are actually accepting connections. - - | - until curl -fsS "http://$DSTACK_ROUTER_INTERNAL_IP:2379/health" \ - && curl -fsS "http://$DSTACK_ROUTER_INTERNAL_IP:8222/healthz"; do - echo "waiting for etcd/NATS on $DSTACK_ROUTER_INTERNAL_IP..."; sleep 3 - done - - pip install "ai-dynamo[sglang]==1.1.1" + - export ETCD_ENDPOINTS=http://${{ groups[0].replicas[0].IP_ADDRESS }}:2379 + # vLLM binds the KV events endpoint only if it's a wildcard address, otherwise it connects - | - python3 -m dynamo.sglang \ - --model-path $MODEL_ID \ - --served-model-name $MODEL_ID \ - --discovery-backend etcd \ - --host 0.0.0.0 \ - --page-size 64 \ - --tp $DSTACK_GPUS_NUM \ - --ep $DSTACK_GPUS_NUM \ - --mem-fraction-static 0.85 \ - --chunked-prefill-size 8192 \ - --linear-attn-prefill-backend flashinfer \ - --linear-attn-decode-backend flashinfer \ - --mamba-ssm-dtype bfloat16 \ - --reasoning-parser auto + python3 -m dynamo.vllm \ + --model $MODEL_ID \ + --max-model-len 65536 \ + --kv-events-config '{"publisher":"zmq","topic":"kv-events","endpoint":"tcp://*:20080","enable_kv_cache_events":true}' resources: - gpu: H200:4 + gpu: H200 + disk: 200GB.. port: 8000 - model: Qwen/Qwen3.8-Flash-Next - - probes: - - type: http - url: /health - interval: 15s + model: zai-org/GLM-4.5-Air-FP8 ``` @@ -418,84 +405,77 @@ Below is an example for running `zai-org/GLM-4.5-Air-FP8` on `H200`: - MODEL_ID=zai-org/GLM-4.5-Air-FP8 groups: - - replicas: 1 - docker: true + # The frontend and the workers discover each other via etcd + - name: etcd + replicas: 1 commands: - - apt-get update - - apt-get install -y python3-dev python3-venv - - python3 -m venv ~/dyn-venv - - source ~/dyn-venv/bin/activate - - pip install -U pip - - pip install "ai-dynamo[sglang]==1.1.1" - - git clone https://github.com/ai-dynamo/dynamo.git - # Brings up the NATS / etcd compose stack and runs the Dynamo HTTP frontend. - - docker compose -f dynamo/dev/docker-compose.yml up -d - | - python3 -m dynamo.frontend \ - --http-host 0.0.0.0 --http-port 8000 \ - --discovery-backend etcd --router-mode kv \ - --kv-cache-block-size 64 + curl -fsSL https://github.com/etcd-io/etcd/releases/download/v3.5.33/etcd-v3.5.33-linux-amd64.tar.gz \ + | tar -xz -C /usr/local/bin --strip-components=1 etcd-v3.5.33-linux-amd64/etcd + - | + etcd \ + --data-dir /tmp/etcd \ + --listen-client-urls http://0.0.0.0:2379 \ + --advertise-client-urls http://$DSTACK_MASTER_NODE_IP:2379 resources: - cpu: 4 + cpu: 2 + + - name: frontend + replicas: 1 + # The vLLM image provides vLLM's GLM tool call and reasoning parsers + image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.5.1 + commands: + - export ETCD_ENDPOINTS=http://${{ groups[0].replicas[0].IP_ADDRESS }}:2379 + - | + python3 -m dynamo.frontend \ + --http-port 8000 \ + --router-mode kv \ + --dyn-chat-processor vllm \ + --enable-auto-tool-choice \ + --tool-call-parser glm45 \ + --reasoning-parser glm45 router: type: dynamo + resources: + cpu: 4 - - replicas: 4 - python: "3.12" - nvcc: true + # Only prefill workers publish KV events, as Dynamo's decode routing ignores prefix overlap + - name: prefill-worker + replicas: 4 + image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.5.1 commands: - # dstack injects DSTACK_ROUTER_INTERNAL_IP after the router replica - # is provisioned. Compose the etcd/NATS endpoints from it. - - export ETCD_ENDPOINTS="http://$DSTACK_ROUTER_INTERNAL_IP:2379" - - export NATS_SERVER="nats://$DSTACK_ROUTER_INTERNAL_IP:4222" - # Set to enable /health endpoint required by dstack probes. - - export DYN_SYSTEM_PORT="8000" - # Wait until the router's etcd and NATS are healthy. + - export ETCD_ENDPOINTS=http://${{ groups[0].replicas[0].IP_ADDRESS }}:2379 + - export VLLM_NIXL_SIDE_CHANNEL_HOST=$DSTACK_MASTER_NODE_IP + # vLLM binds the KV events endpoint only if it's a wildcard address, otherwise it connects - | - until curl -fsS "http://$DSTACK_ROUTER_INTERNAL_IP:2379/health" \ - && curl -fsS "http://$DSTACK_ROUTER_INTERNAL_IP:8222/healthz"; do - echo "waiting for etcd/NATS on $DSTACK_ROUTER_INTERNAL_IP..."; sleep 3 - done - - pip install "ai-dynamo[sglang]==1.1.1" - - | - python3 -m dynamo.sglang \ - --model-path $MODEL_ID --served-model-name $MODEL_ID \ - --discovery-backend etcd --host 0.0.0.0 \ - --page-size 64 \ - --disaggregation-mode prefill --disaggregation-transfer-backend nixl + python3 -m dynamo.vllm \ + --model $MODEL_ID \ + --max-model-len 65536 \ + --disaggregation-mode prefill \ + --kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_producer"}' \ + --kv-events-config '{"publisher":"zmq","topic":"kv-events","endpoint":"tcp://*:20080","enable_kv_cache_events":true}' resources: gpu: H200 + disk: 200GB.. - - replicas: 8 - python: "3.12" - nvcc: true + - name: decode-worker + replicas: 8 + image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.5.1 commands: - - export ETCD_ENDPOINTS="http://$DSTACK_ROUTER_INTERNAL_IP:2379" - - export NATS_SERVER="nats://$DSTACK_ROUTER_INTERNAL_IP:4222" - - export DYN_SYSTEM_PORT="8000" - - | - until curl -fsS "http://$DSTACK_ROUTER_INTERNAL_IP:2379/health" \ - && curl -fsS "http://$DSTACK_ROUTER_INTERNAL_IP:8222/healthz"; do - echo "waiting for etcd/NATS on $DSTACK_ROUTER_INTERNAL_IP..."; sleep 3 - done - - pip install "ai-dynamo[sglang]==1.1.1" + - export ETCD_ENDPOINTS=http://${{ groups[0].replicas[0].IP_ADDRESS }}:2379 + - export VLLM_NIXL_SIDE_CHANNEL_HOST=$DSTACK_MASTER_NODE_IP - | - python3 -m dynamo.sglang \ - --model-path $MODEL_ID --served-model-name $MODEL_ID \ - --discovery-backend etcd --host 0.0.0.0 \ - --page-size 64 \ - --disaggregation-mode decode --disaggregation-transfer-backend nixl + python3 -m dynamo.vllm \ + --model $MODEL_ID \ + --max-model-len 65536 \ + --disaggregation-mode decode \ + --kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_consumer"}' resources: gpu: H200 + disk: 200GB.. port: 8000 model: zai-org/GLM-4.5-Air-FP8 - - # Custom probe is required for PD disaggregation. - probes: - - type: http - url: /health - interval: 15s ``` diff --git a/mkdocs/docs/examples/inference/dynamo.md b/mkdocs/docs/examples/inference/dynamo.md index 5c9fecc23..998b00b47 100644 --- a/mkdocs/docs/examples/inference/dynamo.md +++ b/mkdocs/docs/examples/inference/dynamo.md @@ -12,7 +12,7 @@ This example shows how to deploy `zai-org/GLM-4.5-Air-FP8` using ## Apply a configuration Here's an example of a service that deploys `zai-org/GLM-4.5-Air-FP8` using -Dynamo with PD disaggregation. +Dynamo with PD disaggregation and vLLM workers.