Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
065cb2a
feat: update k8s deploy yamls to use binary/python3
hhzhang16 Jul 11, 2025
aee478c
config part working
tedzhouhk Jul 11, 2025
9455ad1
feat: add component type worker and bump image
hhzhang16 Jul 12, 2025
f3dd01a
fix: merge conflicts
mohammedabdulwahhab Jul 14, 2025
7de97ef
fix: using health checks exposed by dynamo-run
mohammedabdulwahhab Jul 14, 2025
16fd7f2
Merge branch 'main' of github.com:ai-dynamo/dynamo into hannahz/dep-2…
hhzhang16 Jul 14, 2025
3a29913
Merge branch 'hannahz/dep-216-create-deploy-crds-for-vllm_v1-example'…
hhzhang16 Jul 14, 2025
51835db
fix: check for message in logs
mohammedabdulwahhab Jul 14, 2025
39b377f
Merge branch 'hannahz/dep-216-create-deploy-crds-for-vllm_v1-example'…
mohammedabdulwahhab Jul 14, 2025
dddb45f
Merge branch 'hannahz/dep-216-create-deploy-crds-for-vllm_v1-example'…
tedzhouhk Jul 14, 2025
34bc79c
define apis
tedzhouhk Jul 14, 2025
8c22d14
update script
tedzhouhk Jul 14, 2025
9856dde
fix: add dynamodeployment lib
mohammedabdulwahhab Jul 14, 2025
61a215b
fix: working client lib
mohammedabdulwahhab Jul 14, 2025
5141334
fix: working client lib
mohammedabdulwahhab Jul 14, 2025
8e25a29
integrate with utils.dynamo_deployment
tedzhouhk Jul 15, 2025
1d87164
fix: port forward works
mohammedabdulwahhab Jul 15, 2025
aaf4544
Merge branch 'hzhou/profile_vllmv1_k8s' of https://github.com/ai-dyna…
mohammedabdulwahhab Jul 15, 2025
65dec07
pc
tedzhouhk Jul 15, 2025
0af209b
add dep; bug fix
tedzhouhk Jul 15, 2025
918733a
Merge branch 'main' of https://github.com/ai-dynamo/dynamo into hzhou…
tedzhouhk Jul 15, 2025
3f900ef
staging, port forward not working
tedzhouhk Jul 15, 2025
bd12d40
stage
tedzhouhk Jul 15, 2025
7ac43a9
Merge branch 'main' of https://github.com/ai-dynamo/dynamo into hzhou…
mohammedabdulwahhab Jul 15, 2025
9971acf
fix: running script
mohammedabdulwahhab Jul 16, 2025
a5d8aca
fix: fix
mohammedabdulwahhab Jul 16, 2025
7b1d99a
Merge branch 'main' of https://github.com/ai-dynamo/dynamo into hzhou…
tedzhouhk Jul 16, 2025
f8f9363
add logic to find a free port
tedzhouhk Jul 16, 2025
8e292f6
feat: add Kubernetes service account configuration for SLA profiling …
hhzhang16 Jul 17, 2025
d62731f
feat: use service DNS for interfacing with deployments when profiling…
hhzhang16 Jul 17, 2025
a1aea5a
Revert "feat: use service DNS for interfacing with deployments when p…
hhzhang16 Jul 17, 2025
06bfe3b
feat: use service DNS instead of port forwarding for K8s-deployed SLA…
hhzhang16 Jul 18, 2025
ff96b9e
add try-catch waiting for deployment
tedzhouhk Jul 18, 2025
5419885
Merge branch 'main' of https://github.com/ai-dynamo/dynamo into hzhou…
tedzhouhk Jul 21, 2025
d2b6b00
feat: clean up outlying DGDs upon SLA profiling failure (#2016)
hhzhang16 Jul 21, 2025
450d371
add debug info
tedzhouhk Jul 22, 2025
d8ffe1a
Merge branch 'hzhou/profile_vllmv1_k8s' of https://github.com/ai-dyna…
tedzhouhk Jul 22, 2025
769c98e
sla planner
tedzhouhk Jul 22, 2025
e726d43
add choices
tedzhouhk Jul 22, 2025
3663c5c
Merge branch 'main' of github.com:ai-dynamo/dynamo into hzhou/sla-pla…
hhzhang16 Jul 22, 2025
ff6c491
feat: vllm_v1 -> vllm and remove vllm_v0 from planner
hhzhang16 Jul 22, 2025
6ebfe73
feat: remove local connector from init
hhzhang16 Jul 22, 2025
fb89fc2
feat: remove LocalConnector from core
hhzhang16 Jul 22, 2025
047cecb
feat: rework prometheus file for planner deployment
hhzhang16 Jul 22, 2025
894f2e7
Merge branch 'main' of github.com:ai-dynamo/dynamo into hannahz/dep-2…
hhzhang16 Jul 23, 2025
cd268ca
Merge branch 'main' of github.com:ai-dynamo/dynamo into hzhou/sla-pla…
hhzhang16 Jul 23, 2025
0f5082c
deprecate old docs
tedzhouhk Jul 23, 2025
9751e65
Merge branch 'main' of https://github.com/ai-dynamo/dynamo into hzhou…
tedzhouhk Jul 23, 2025
c33713f
Merge branch 'hzhou/sla-planner-ux-refac' of github.com:ai-dynamo/dyn…
hhzhang16 Jul 24, 2025
33371db
feat: update prometheus to work
hhzhang16 Jul 24, 2025
60dd89d
feat: k8s connector scaling P/D in one call (#2103)
tedzhouhk Jul 25, 2025
61a5e9a
Merge branch 'main' of github.com:ai-dynamo/dynamo into hannahz/dep-2…
hhzhang16 Jul 25, 2025
41f1ca0
fix: vllm_v1 -> vllm
hhzhang16 Jul 25, 2025
1584cd0
feat: remove unneeded files
hhzhang16 Jul 25, 2025
dd3f161
docs: update docs
hhzhang16 Jul 25, 2025
97f3f88
fix: vllm config in profiler
hhzhang16 Jul 25, 2025
9b34ee9
feat: wip but tentatively working planner, with documentation
hhzhang16 Jul 25, 2025
eb56dbb
fi: use provided namespace for decode
hhzhang16 Jul 25, 2025
b68779d
feat: use k8s deployment info instead of hardcoding prometheus endpoint
hhzhang16 Jul 25, 2025
c8e394d
fix: if no requests have been made yet, don't try to access list
hhzhang16 Jul 25, 2025
1bbfd8d
feat: use SLAPLannerDefaults port
hhzhang16 Jul 25, 2025
ba6b5c1
docs: clean up sla planner deployment docs
hhzhang16 Jul 25, 2025
e533dda
feat: use DYNAMO_NAMESPACE env var instead of --namespace arg
hhzhang16 Jul 26, 2025
a548d74
feat: fixes for working planner
hhzhang16 Jul 26, 2025
f6af0d5
feat: skip adjustments if no traffic
hhzhang16 Jul 26, 2025
445fe74
docs: doc updates for planner deployment
hhzhang16 Jul 26, 2025
f0999da
Merge branch 'main' of github.com:ai-dynamo/dynamo into hannahz/dep-2…
hhzhang16 Jul 26, 2025
bab714c
feat: delete k8s.sh
hhzhang16 Jul 26, 2025
a29c397
docs: slight doc modification
hhzhang16 Jul 26, 2025
daa3c4e
update resources
tedzhouhk Jul 26, 2025
539ff3e
update readme
tedzhouhk Jul 26, 2025
f994128
feat: address coderabbit MR comments
hhzhang16 Jul 28, 2025
d44b042
Merge branch 'main' of github.com:ai-dynamo/dynamo into hannahz/dep-2…
hhzhang16 Jul 28, 2025
f601f88
fix pytest
tedzhouhk Jul 28, 2025
69d64dc
mypy
tedzhouhk Jul 28, 2025
1fdf3e9
feat: addressing MR comments
hhzhang16 Jul 28, 2025
bf58bd0
feat: addressing MR comments
hhzhang16 Jul 28, 2025
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
Prev Previous commit
Next Next commit
feat: wip but tentatively working planner, with documentation
  • Loading branch information
hhzhang16 committed Jul 25, 2025
commit 9b34ee9520e4e3423e40e9b07d4a2c5181055cec
44 changes: 20 additions & 24 deletions components/backends/vllm/deploy/disagg_planner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ metadata:
spec:
envs:
- name: DYNAMO_SERVICE_CONFIG
value: '{"Prometheus":{"global":{"scrape_interval":"5s"},"scrape_configs":[{"job_name":"prometheus","static_configs":[{"targets":["localhost:9090"]}]},{"job_name":"frontend","static_configs":[{"targets":["localhost:8000"]}]}]}}'
value: '{"Prometheus":{"global":{"scrape_interval":"5s"},"scrape_configs":[{"job_name":"prometheus","static_configs":[{"targets":["localhost:9090"]}]},{"job_name":"frontend","static_configs":[{"targets":["vllm-disagg-planner-frontend:8000"]}]}]}}'
services:
Frontend:
dynamoNamespace: vllm-disagg-planner
Expand All @@ -34,22 +34,20 @@ spec:
failureThreshold: 10
resources:
requests:
cpu: "2"
memory: "4Gi"
cpu: "4"
memory: "16Gi"
limits:
cpu: "2"
memory: "4Gi"
cpu: "4"
memory: "16Gi"
extraPodSpec:
mainContainer:
image: nvcr.io/nvidian/nim-llm-dev/vllm-runtime:dep-253.5
workingDir: /workspace/examples/vllm
image: nvcr.io/nvidian/nim-llm-dev/vllm-runtime:dep-253.11
workingDir: /workspace/components/backends/vllm
command:
- /bin/sh
- -c
args:
- dynamo
- run
- in=http
- out=dyn
- --http-port
- "8000"
- "python3 -m dynamo.frontend --http-port 8000"
Planner:
dynamoNamespace: vllm-disagg-planner
envFromSecret: hf-token-secret
Expand Down Expand Up @@ -87,7 +85,7 @@ spec:
mountPoint: /workspace/profiling_results
extraPodSpec:
mainContainer:
image: nvcr.io/nvidian/nim-llm-dev/vllm-runtime:dep-253.5
image: nvcr.io/nvidian/nim-llm-dev/vllm-runtime:dep-253.11
workingDir: /workspace/components/planner/src/dynamo/planner
args:
- python
Expand All @@ -106,6 +104,8 @@ spec:
envs:
- name: PYTHONPATH
value: "/workspace/components/planner/src"
- name: DYNAMO_PORT
value: "9090"
livenessProbe:
exec:
command:
Expand Down Expand Up @@ -134,15 +134,13 @@ spec:
memory: "2Gi"
extraPodSpec:
mainContainer:
image: nvcr.io/nvidian/nim-llm-dev/vllm-runtime:dep-233.17
image: nvcr.io/nvidian/nim-llm-dev/vllm-runtime:dep-253.11
workingDir: /workspace/components/backends/vllm
command:
- /bin/sh
- -c
args:
- python
- -m
- dynamo.planner.prometheus
- "python3 -m dynamo.planner.prometheus"
VllmDecodeWorker:
dynamoNamespace: vllm-disagg-planner
envFromSecret: hf-token-secret
Expand Down Expand Up @@ -178,15 +176,13 @@ spec:
gpu: "1"
extraPodSpec:
mainContainer:
image: nvcr.io/nvidian/nim-llm-dev/vllm-runtime:dep-233.17
image: nvcr.io/nvidian/nim-llm-dev/vllm-runtime:dep-253.11
workingDir: /workspace/components/backends/vllm
command:
- /bin/sh
- -c
args:
- /bin/sh
- -c
- "python3 -m dynamo.vllm --model Qwen/Qwen3-0.6B --enforce-eager 2>&1 | tee /tmp/vllm.log"
- "python3 -m dynamo.vllm --model Qwen/Qwen3-0.6B --namespace vllm-disagg-planner 2>&1 | tee /tmp/vllm.log"
VllmPrefillWorker:
dynamoNamespace: vllm-disagg-planner
envFromSecret: hf-token-secret
Expand Down Expand Up @@ -222,10 +218,10 @@ spec:
gpu: "1"
extraPodSpec:
mainContainer:
image: nvcr.io/nvidian/nim-llm-dev/vllm-runtime:dep-233.17
image: nvcr.io/nvidian/nim-llm-dev/vllm-runtime:dep-253.11
workingDir: /workspace/components/backends/vllm
command:
- /bin/sh
- -c
args:
- python3 -m dynamo.vllm --model Qwen/Qwen3-0.6B --enforce-eager --is-prefill-worker 2>&1 | tee /tmp/vllm.log
- python3 -m dynamo.vllm --model Qwen/Qwen3-0.6B --is-prefill-worker --namespace vllm-disagg-planner 2>&1 | tee /tmp/vllm.log
64 changes: 48 additions & 16 deletions components/backends/vllm/src/dynamo/vllm/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,16 @@ def parse_args() -> Config:
default=DEFAULT_ENDPOINT,
help=f"Dynamo endpoint string in 'dyn://namespace.component.endpoint' format. Default: {DEFAULT_ENDPOINT}",
)
parser.add_argument(
"--namespace",
type=str,
default="dynamo",
help="Dynamo namespace for this worker. Default: dynamo",
)
parser.add_argument(
"--is-prefill-worker",
action="store_true",
help="Enable prefill functionality for this worker. Currently overwrites the --endpoint to be a specially chosen dyn://dynamo.prefill.generate",
help="Enable prefill functionality for this worker. Uses the provided namespace to construct dyn://namespace.prefill.generate",
)

parser = AsyncEngineArgs.add_cli_args(parser)
Expand All @@ -80,7 +86,7 @@ def parse_args() -> Config:
config.served_model_name = None

if args.is_prefill_worker:
args.endpoint = "dyn://dynamo.prefill.generate"
args.endpoint = f"dyn://{args.namespace}.prefill.generate"

endpoint_str = args.endpoint.replace("dyn://", "", 1)
endpoint_parts = endpoint_str.split(".")
Expand Down Expand Up @@ -127,6 +133,14 @@ async def allocate_and_reserve_port(
"""

node_name = socket.gethostname()
try:
node_ip = socket.gethostbyname(node_name)
except socket.gaierror:
# If hostname cannot be resolved, fall back to localhost
logger.warning(
f"Hostname '{node_name}' cannot be resolved, falling back to '127.0.0.1'"
)
node_ip = "127.0.0.1"

for attempt in range(1, max_attempts + 1):
# Hold socket open just long enough to reserve in ETCD
Expand All @@ -136,7 +150,7 @@ async def allocate_and_reserve_port(
port = sock.getsockname()[1]

# Reserve in ETCD while holding the socket
key = f"dyn://{namespace}/ports/{node_name}/{port}"
key = f"dyn://{namespace}/ports/{node_ip}/{port}"
value = {
"worker_id": worker_id,
"reason": reason,
Expand Down Expand Up @@ -238,23 +252,41 @@ def overwrite_args(config):
raise ValueError(f"{key} not found in AsyncEngineArgs from vLLM.")


def set_side_channel_host_and_port(config: Config, hostname: Optional[str] = None):
"""vLLM V1 NixlConnector creates a side channel to exchange metadata with other NIXL connectors.
This sets the port number for the side channel.
def get_host_ip() -> str:
"""Get the IP address of the host.
This is needed for the side channel to work in multi-node deployments.
"""
if hostname is None:
hostname = socket.gethostname()
# Test if hostname is usable by attempting to bind to it
try:
host_name = socket.gethostname()
except socket.error as e:
logger.warning(f"Failed to get hostname: {e}, falling back to '127.0.0.1'")
return "127.0.0.1"
else:
try:
# Get the IP address of the hostname - this is needed for the side channel to work in multi-node deployments
host_ip = socket.gethostbyname(host_name)
# Test if the IP is actually usable by binding to it
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as test_socket:
test_socket.bind((hostname, 0))
except (socket.error, socket.gaierror):
# If hostname is not usable, fall back to localhost
test_socket.bind((host_ip, 0))
return host_ip
except socket.gaierror as e:
logger.warning(
f"Hostname '{hostname}' is not usable, falling back to '127.0.0.1'"
f"Hostname '{host_name}' cannot be resolved: {e}, falling back to '127.0.0.1'"
)
hostname = "127.0.0.1"
return "127.0.0.1"
except socket.error as e:
# If hostname is not usable for binding, fall back to localhost
logger.warning(
f"Hostname '{host_name}' is not usable for binding: {e}, falling back to '127.0.0.1'"
)
return "127.0.0.1"


os.environ["VLLM_NIXL_SIDE_CHANNEL_HOST"] = hostname
def set_side_channel_host_and_port(config: Config):
"""vLLM V1 NixlConnector creates a side channel to exchange metadata with other NIXL connectors.
This sets the port number for the side channel.
"""
host_ip = get_host_ip()
os.environ["VLLM_NIXL_SIDE_CHANNEL_HOST"] = host_ip
os.environ["VLLM_NIXL_SIDE_CHANNEL_PORT"] = str(config.side_channel_port)
logger.debug(f"Set NIXL side channel to {hostname}:{config.side_channel_port}")
logger.debug(f"Set NIXL side channel to {host_ip}:{config.side_channel_port}")
4 changes: 2 additions & 2 deletions components/planner/src/dynamo/planner/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ class SLAPlannerDefaults(BasePlannerDefaults):


class VllmComponentName:
prefill_worker = "VllmPrefillWorker"
prefill_worker = "prefill"
prefill_worker_endpoint = "generate"
decode_worker = "VllmDecodeWorker"
decode_worker = "backend"
decode_worker_endpoint = "generate"


Expand Down
1 change: 1 addition & 0 deletions components/planner/src/dynamo/planner/prometheus.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ async def start_prometheus_server(config):
cmd = [
"prometheus",
f"--config.file={config_path}",
"--web.listen-address=0.0.0.0:9090",
]

logger.info(f"Prometheus cmd: {cmd}")
Expand Down
11 changes: 9 additions & 2 deletions components/planner/src/dynamo/planner/utils/planner_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,14 @@ async def make_adjustments(self):

# compute how many replicas are needed for decode
# 1. apply d_correction_factor to the ITL SLA
corrected_itl = self.args.itl / self.d_correction_factor
# Prevent divide by zero when d_correction_factor is 0 (no metrics yet)
if self.d_correction_factor <= 0:
logger.warning(
f"d_correction_factor is {self.d_correction_factor}, using default value of 1.0"
)
corrected_itl = self.args.itl
else:
corrected_itl = self.args.itl / self.d_correction_factor
# 2. reversely find out what is best throughput/gpu that can achieve corrected_itl under the predicted context length
pred_decode_thpt_per_gpu = (
self.decode_interpolator.find_best_throughput_per_gpu(
Expand Down Expand Up @@ -274,7 +281,7 @@ async def make_adjustments(self):
WORKER_COMPONENT_NAMES[self.args.backend].prefill_worker: next_num_p,
WORKER_COMPONENT_NAMES[self.args.backend].decode_worker: next_num_d,
}
self.connector.set_component_replicas(target_replicas, blocking=False)
await self.connector.set_component_replicas(target_replicas, blocking=False)

async def run(self):
"""Main loop for the planner"""
Expand Down
8 changes: 5 additions & 3 deletions docs/architecture/sla_planner.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,13 @@ Finally, SLA planner applies the change by scaling up/down the number of prefill

## Deploying

To deploy SLA-planner, ensure etcd and NATS are running first, then use the frontend that reports metrics at `/metrics` HTTP endpoint. You can also use your own frontend, but it must report number of requests, ISL, OSL, TTFT, ITL in the same format.

SLA-planner and prometheus server are provided as common components that can be directly imported from `dynamo` package.
For detailed deployment instructions including setup, configuration, troubleshooting, and architecture overview, see the [SLA Planner Deployment Guide](../guides/dynamo_deploy/sla_planner_deployment.md).

**Quick Start:**
```bash
cd components/backends/vllm/deploy
kubectl apply -f disagg_planner.yaml -n {$NAMESPACE}
```

> [!NOTE]
> The SLA planner requires a frontend that reports metrics at `/metrics` HTTP endpoint with number of requests, ISL, OSL, TTFT, ITL in the correct format. The VLLM frontend provides these metrics automatically.
Loading