AIBrix 多节点推理编排指南:RayClusterFleet 与 StormService 双路径实战
AIBrix 多节点推理编排指南RayClusterFleet 与 StormService 双路径实战【免费下载链接】aibrixCost-efficient and pluggable Infrastructure components for GenAI inference项目地址: https://gitcode.com/GitHub_Trending/ai/aibrix导读当单个 GPU 节点的显存装不下一个大模型时就需要把模型切分到多个节点上做分布式推理。AIBrix 为此提供了两条互补的编排路径基于 KubeRay 的RayClusterFleet / RayClusterReplicaSet适合标准 vLLM 多节点部署由 Ray 负责进程放置与 worker 协调以及纯 Kubernetes 原生的StormService通过podGroupSize实现多角色、多节点分组无需 KubeRay适合 Prefill/Decode 分离与引擎原生的多节点后端如 SGLang、vLLM 配合 MPI/NCCL 与 RDMA。读完本文你将掌握两种抽象的选型依据、完整可复制的 YAML 示例、验证命令以及常见故障排查方法。选型两种编排抽象怎么选分布式推理把一个大模型拆分到多节点上执行首要动机是单机显存放不下超大模型。AIBrix 提供两种编排抽象二者在orchestration.aibrix.ai/v1alpha1API 组下共存选型取决于你的部署拓扑与基础设施抽象基础设施要求最适合的场景RayClusterFleet已安装 KubeRay operator标准的多节点 vLLM 部署由 Ray 负责进程放置与 worker 协调StormService原生 Kubernetes无需 KubeRayPrefill-DecodePD分离架构、自定义多角色架构或直接使用引擎原生分布式后端如 SGLang、vLLM 搭配 MPI/NCCL 与 RDMA 网络两个抽象并不是二选一的排他方案KubeRay 对 AIBrix 其余功能是可选的只在用到 RayClusterFleet / RayClusterReplicaSet 时才需要安装见 安装指南。基于 KubeRay 的编排RayClusterFleet为什么把 Ray 和 Kubernetes 组合在一起管理多节点推理需要在两个层面协调应用内intra-application细粒度的任务调度、worker 之间的通信这是 Ray 的强项集群外cluster-level容器调度、自动扩缩容、滚动更新等标准运维这是 Kubernetes 的强项。Ray 擅长前者但依赖外部系统处理集群生命周期Kubernetes 擅长后者但缺乏分布式计算语义。AIBrix 把两者组合起来Ray 负责内部分布式计算Kubernetes 负责副本生命周期与环境搭建。每个应用实例对应一个独立的 Ray 集群Service 面向代表应用实例的 Ray 集群而非单个 Pod进行服务封装。AIBrix 提供两个 API 来管理 Ray 集群RayClusterReplicaSet与RayClusterFleet分别镜像 Kubernetes 的ReplicaSet与Deployment模式。绝大多数情况下RayClusterFleet是你需要配置的主资源。分层工作原理从外到内共四层RayClusterFleet承载Deployment的发布语义滚动更新或重建策略Recreate/RollingUpdate、版本历史revisionHistoryLimit、paused、minReadySeconds与进度截止时间progressDeadlineSeconds。任何对spec.template的修改都会生成一个新的RayClusterReplicaSetfleet 按strategy在新旧集合之间迁移副本。RayClusterReplicaSet维持固定数量的 KubeRayRayCluster对象存活消失一个就补一个。它的 spec 是ReplicaSet的子集replicas、selector、template、minReadySeconds你通常不会直接创建它。RayCluster是 KubeRay 的资源其 spec 直接取自 fleet 的spec.template.spec仅在 head/worker Pod 模板上额外加上 fleet-name 标签因此 KubeRay 支持的一切rayVersion、headGroupSpec、workerGroupSpecs、rayStartParams都可用。引擎运行在 head Pod 上Ray 作为其分布式执行器vLLM 对应--distributed-executor-backend rayworker Pod 只运行ray start把 GPU 贡献给 Ray 集群。就绪判定只有当 KubeRay 报告的RayClusterProvisioned与HeadPodReady两个 condition 都为True且所有期望的 worker 都就绪时Ray 集群才算就绪。这两个 condition 由 KubeRay 的RayClusterStatusConditionsfeature gate 产生AIBrix 的安装命令会显式开启它见下文前置条件没有该 gate 的集群永远不会报告 ready 副本。路由网关通过model.aibrix.ai/name标签发现模型 Pod但会忽略带有ray.io/node-type: worker标签的 Pod因此请求只会被路由到 head Pod。fleet 控制器会为每个 Pod 打上orchestration.aibrix.ai/raycluster-fleet-name标签便于指标与路由状态映射回所属 fleet。前置条件KubeRay operator对 AIBrix 其他功能是可选的仅在用到 RayClusterFleet / RayClusterReplicaSet 时需要。使用安装指南中的 Helm 命令安装该命令固定使用打过补丁的 operator 镜像并开启就绪判定所依赖的RayClusterStatusConditionsfeature gatehelm repo add kuberay https://ray-project.github.io/kuberay-helm/ helm repo update helm install kuberay-operator kuberay/kuberay-operator --namespace aibrix-system \ --create-namespace \ --version 1.2.1 \ --set-string env[0].nameENABLE_PROBES_INJECTION \ --set-string env[0].valuefalse \ --set fullnameOverridekuberay-operator \ --set featureGates[0].nameRayClusterStatusConditions \ --set featureGates[0].enabledtrue \ --set image.repositoryaibrix/kuberay-operator \ --set image.tagv1.2.1-patch-20250726head Pod 与每个 worker Pod 都需要GPU 节点一个包含 Ray 的引擎镜像v0.6.6 起官方 vLLM 镜像开箱即用更早版本见下文容器镜像要求。配置参考RayClusterFleetSpec定义在 rayclusterfleet_types.go关键字段如下字段类型说明replicasint32需要运行的 Ray 集群数量默认 1selectorLabelSelector必须匹配template.metadata.labels中的标签必填templateRayClusterTemplateSpec每个 Ray 集群的metadata与specspec是 KubeRay 的RayClusterSpec原样透传并给 Pod 模板追加 fleet-name 标签strategyDeploymentStrategyRecreate或RollingUpdate含maxSurge、maxUnavailable语义与Deployment一致minReadySecondsint32Ray 集群保持就绪多长时间后才算可用默认 0revisionHistoryLimitint32为回滚保留的旧RayClusterReplicaSet数量默认 10pausedbool暂停控制器对模板变更的响应progressDeadlineSecondsint32停滞的发布超过该秒数后在status.conditions中报告失败默认 600status字段包括replicas、updatedReplicas、readyReplicas、availableReplicas、unavailableReplicas、observedGeneration、conditions与scalingTargetSelector。fleet 暴露 Kubernetesscale子资源见 类型定义因此kubectl scale rayclusterfleet name --replicasN并且 PodAutoscaler 可以把kind: RayClusterFleet作为scaleTargetRef直接使用。需要关注的标签与注解Key用途model.aibrix.ai/namelabel设置在 head 与 worker Pod 模板上网关靠它发现模型 PodPodAutoscaler 则使用 fleet 的 scale selectorray.io/overwrite-container-cmd: true注解加在 Ray 集群模板上让 KubeRay 尊重你写的容器command/args而不是自己生成ray start命令KubeRay 仍会把生成的命令注入环境变量KUBERAY_GEN_RAY_START_CMD供你自行执行示例就是这么做的。生成的变量不含ulimit需在自己的命令里设置ray.io/node-typelabelKubeRay 自动设置head或worker网关路由时跳过workerPodorchestration.aibrix.ai/raycluster-fleet-namelabelfleet 控制器自动设置把 Pod 映射回所属 fleet不要自行设置并行度 sizing使用 Ray executor 时引擎的 tensor-parallel 大小必须等于整个 Ray 集群的 GPU 总数head workers。下面的示例在 1 个 GPU 的 head Pod 1 个 GPU 的 worker Pod 上运行--tensor-parallel-size 2。RayClusterFleet 完整示例以下是一个部署两节点分布式推理集群的完整RayClusterFleet示例源文件见 samples/distributed/fleet-two-node.yamlapiVersion: orchestration.aibrix.ai/v1alpha1 kind: RayClusterFleet metadata: name: qwen-coder-7b-instruct labels: app.kubernetes.io/name: aibrix app.kubernetes.io/managed-by: kustomize spec: replicas: 1 selector: matchLabels: model.aibrix.ai/name: qwen-coder-7b-instruct strategy: type: RollingUpdate rollingUpdate: maxSurge: 25% maxUnavailable: 25% template: metadata: labels: model.aibrix.ai/name: qwen-coder-7b-instruct annotations: ray.io/overwrite-container-cmd: true spec: rayVersion: 2.10.0 headGroupSpec: rayStartParams: dashboard-host: 0.0.0.0 template: metadata: labels: model.aibrix.ai/name: qwen-coder-7b-instruct spec: containers: - name: ray-head image: vllm/vllm-openai:v0.7.1 command: [/bin/bash, -c] args: - ulimit -n 65536 apt update apt install -y wget net-tools pip3 install ray[default] pyarrow pandas echo [INFO] Starting Ray head node... eval $KUBERAY_GEN_RAY_START_CMD echo [INFO] Waiting for Ray dashboard to be ready... until curl --max-time 5 --fail http://127.0.0.1:8265 /dev/null 21; do echo [WAITING] $(date -u %Y-%m-%dT%H:%M:%SZ) - Ray dashboard not ready yet...; sleep 2; done echo [SUCCESS] Ray dashboard is available! vllm serve Qwen/Qwen2.5-Coder-7B-Instruct \ --served-model-name qwen-coder-7b-instruct \ --tensor-parallel-size 2 \ --distributed-executor-backend ray \ --host 0.0.0.0 \ --port 8000 \ --dtype half ports: - containerPort: 6379 name: gcs-server - containerPort: 8265 name: dashboard - containerPort: 10001 name: client - containerPort: 8000 name: service resources: limits: cpu: 4 nvidia.com/gpu: 1 requests: cpu: 4 nvidia.com/gpu: 1 - name: aibrix-runtime image: aibrix/runtime:v0.3.0 command: - aibrix_runtime - --port - 8080 env: - name: INFERENCE_ENGINE value: vllm - name: INFERENCE_ENGINE_ENDPOINT value: http://localhost:8000 - name: PYTORCH_CUDA_ALLOC_CONF value: expandable_segments:True ports: - containerPort: 8080 protocol: TCP livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 3 periodSeconds: 2 readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 5 periodSeconds: 10 resources: limits: cpu: 1 requests: cpu: 1 workerGroupSpecs: - groupName: small-group replicas: 1 minReplicas: 1 maxReplicas: 5 rayStartParams: {} template: metadata: labels: model.aibrix.ai/name: qwen-coder-7b-instruct spec: containers: - name: ray-worker image: vllm/vllm-openai:v0.7.1 env: - name: MY_POD_IP valueFrom: fieldRef: fieldPath: status.podIP command: [ /bin/bash, -c ] args: - ulimit -n 65536 eval $KUBERAY_GEN_RAY_START_CMD --node-ip-address$MY_POD_IP tail -f /dev/null lifecycle: preStop: exec: command: [ /bin/sh, -c, ray stop ] resources: limits: cpu: 4 nvidia.com/gpu: 1 requests: cpu: 4 nvidia.com/gpu: 1 --- apiVersion: v1 kind: Service metadata: name: qwen-coder-7b-instruct labels: model.aibrix.ai/name: qwen-coder-7b-instruct prometheus-discovery: true annotations: prometheus.io/scrape: true prometheus.io/port: 8080 spec: selector: model.aibrix.ai/name: qwen-coder-7b-instruct ports: - name: serve port: 8000 protocol: TCP targetPort: 8000 - name: http port: 8080 protocol: TCP targetPort: 8080 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: qwen-coder-7b-instruct-router namespace: aibrix-system spec: parentRefs: - group: gateway.networking.k8s.io kind: Gateway name: aibrix-eg namespace: aibrix-system rules: - backendRefs: - group: kind: Service name: qwen-coder-7b-instruct namespace: default port: 8000 # or 8000 if youre not using the runtime sidecar weight: 1 matches: - headers: - name: model type: Exact value: qwen-coder-7b-instruct path: type: PathPrefix value: /v1/completions - headers: - name: model type: Exact value: qwen-coder-7b-instruct path: type: PathPrefix value: /v1/chat/completions timeouts: request: 120s逐段解读这个示例head 容器先调高文件描述符上限安装 Ray dashboard 依赖在后台执行 KubeRay 生成的ray start命令轮询等待 8265 端口的 Ray dashboard 应答然后才启动vllm serve带--distributed-executor-backend ray。等待 dashboard 至关重要——vLLM 启动时会连接 Ray 集群head 未就绪则直接失败。worker 容器用自身 Pod IP 执行生成的ray start命令然后用tail -f /dev/null阻塞保活preStop钩子调用ray stop让节点干净地离开集群。AI Runtime sidecarhead Pod 上在 8080 端口暴露标准化指标并提供 Pod 的存活与就绪探针/healthz与/ready详见 runtime。Service按model.aibrix.ai/name选择 Pod带prometheus-discovery: true标签以便指标被采集。HTTPRoute通过匹配model请求头把模型挂到 AIBrix 网关与单 Pod 部署的路由形态一致详见 网关生产配置。验证部署# Fleet、它的 ReplicaSet以及它创建的 KubeRay 集群 kubectl get rayclusterfleet kubectl get rayclusterreplicaset kubectl get raycluster # head 与 worker Pod kubectl get pods -l ray.io/node-typehead kubectl get pods -l ray.io/node-typeworkerfleet 的 CRD 没有额外的打印列直接对比计数即可kubectl get rayclusterfleet qwen-coder-7b-instruct \ -o jsonpath{.status.readyReplicas}/{.spec.replicas}{\n}两个数字相等即 fleet 健康。然后像单 Pod 模型一样通过网关发请求kubectl -n envoy-gateway-system port-forward service/envoy-aibrix-system-aibrix-eg-903790dc 8888:80 curl http://localhost:8888/v1/chat/completions \ -H Content-Type: application/json \ -H model: qwen-coder-7b-instruct \ -d {model: qwen-coder-7b-instruct, messages: [{role: user, content: hello}]}故障排查Fleet 从不报告 ready 副本。执行kubectl describe raycluster name查看Status.Conditions。AIBrix 要求RayClusterProvisioned与HeadPodReady均为True。如果这两个 condition 完全缺失说明 KubeRay operator 安装时没有开启RayClusterStatusConditionsfeature gate请按安装指南重装。Head Pod 反复重启或 vLLM 报 Ray 连接错误。引擎在 Ray head 就绪前启动了。保留示例中vllm serve前面的 dashboard 等待循环同时确认模板里的rayVersion与镜像内的 Ray 版本一致版本不匹配会导致 worker 无法加入。Worker Pod 一直 Pending。每个 worker 都申请 GPU。用kubectl describe node检查节点容量确认workerGroupSpecs里的nvidia.com/gpu请求可被满足。Pod 已 Running 但网关对模型返回错误。网关只路由给带model.aibrix.ai/name且 Ready 的 head Pod。检查标签是否在 head Pod 模板上而不只是 fleet 上以及 runtime sidecar8080 端口/ready的就绪探针是否通过。原生 PodSet 编排StormServicepodGroupSize 与确定性分布式环境变量对于不运行 KubeRay 的部署或需要显式角色分离如独立的 Prefill 与 Decode 角色的分离式架构AIBrix 提供原生的多节点分组能力StormService。它的核心机制是在角色模板里设置podGroupSize让StormService为每个副本实例分配一组同步的 Pod并注入确定性的分布式环境变量如$POD_GROUP_INDEX与$PODSET_NAME从而支持跨节点的引擎原生张量并行TP。关键能力零外部依赖直接跑在 Kubernetes 上无需安装 KubeRay多角色与分离式支持在单个服务定义里声明多个角色如 routing、prefill、decode每个角色可有独立的资源画像与 pod 组大小确定性的 rank 与发现组内 Pod 通过可预测的 headless Service DNS 发现对端例如${PODSET_NAME}-0.${STORM_SERVICE_NAME}。从源码看podGroupSize的最小值为 2、最大值为 100见 podset_types.go当podGroupSize 1时RoleSet 控制器会创建内部的PodSet资源该资源在 podset_types.go 中明确标注为internal API由 RoleSet controller 在 podGroupSize 1 时使用以原子组的形式协同管理这批 Pod并通过PodSetStatus的ReadyPods/TotalPods/Phase呈现整组状态。此外StormService还支持Replica与Pooled两种部署模式stormservice_types.go显式spec.mode优先否则按spec.replicas兼容推断replicas 1 为 Replica 模式否则为 Pooled 模式并支持RollingUpdate与InPlaceUpdate两种更新策略类型定义。StormService 多节点 TP 示例PD 分离下面是一个完整的 Prefill/Decode 分离多节点张量并行示例prefill 2 节点、decode 2 节点podGroupSize: 2对应--nnodes 2 --tp-size 2源文件见 samples/disaggregation/sglang/tp-1p1d.yamlapiVersion: orchestration.aibrix.ai/v1alpha1 kind: StormService metadata: name: tp-1p1d spec: replicas: 1 updateStrategy: type: InPlaceUpdate stateful: true selector: matchLabels: app: tp-1p1d template: metadata: labels: app: tp-1p1d spec: roles: - name: routing replicas: 1 stateful: true template: spec: containers: - name: mini-lb image: aibrix/sglang-router:v0.1.6 command: [ sh, -c ] args: - | python3 -m sglang_router.launch_router \ --pd-disaggregation \ --policy random \ --service-discovery \ --service-discovery-port 30000 \ --prefill-selector storm-service-name$STORM_SERVICE_NAME role-nameprefill stormservice.orchestration.aibrix.ai/pod-group-index0 \ --decode-selector storm-service-name$STORM_SERVICE_NAME role-namedecode stormservice.orchestration.aibrix.ai/pod-group-index0 \ --service-discovery-namespace default - name: prefill replicas: 1 podGroupSize: 2 stateful: true template: metadata: annotations: k8s.volcengine.com/pod-networks: | [ { cniConf:{ name:rdma } } ] labels: model.aibrix.ai/name: qwen3-8B model.aibrix.ai/port: 30000 model.aibrix.ai/engine: sglang spec: containers: - name: prefill image: aibrix/sglang:v0.4.9.post3-cu126-nixl-v0.4.1 command: [sh, -c] args: - | python3 -m sglang.launch_server \ --model-path /models/Qwen3-8B \ --served-model-name qwen3-8B \ --host 0.0.0.0 \ --port 30000 \ --disaggregation-mode prefill \ --disaggregation-transfer-backendnixl \ --trust-remote-code \ --dist-init-addr ${PODSET_NAME}-0.${STORM_SERVICE_NAME}.default.svc.cluster.local:5000 \ --nnodes 2 \ --node-rank $POD_GROUP_INDEX \ --tp-size 2 \ --mem-fraction-static 0.8 \ --log-level debug env: - name: GLOO_SOCKET_IFNAME value: eth0 - name: NCCL_SOCKET_IFNAME value: eth0 - name: NCCL_IB_DISABLE value: 0 - name: NCCL_IB_GID_INDEX value: 7 - name: NCCL_DEBUG value: INFO - name: UCX_TLS value: ^gga volumeMounts: - name: model-vol mountPath: /models - mountPath: /dev/shm name: shared-mem resources: limits: nvidia.com/gpu: 1 vke.volcengine.com/rdma: 1 securityContext: capabilities: add: - IPC_LOCK volumes: - name: model-vol hostPath: path: /root/models type: Directory - emptyDir: medium: Memory name: shared-mem - name: decode replicas: 1 podGroupSize: 2 stateful: true template: metadata: annotations: k8s.volcengine.com/pod-networks: | [ { cniConf:{ name:rdma } } ] labels: model.aibrix.ai/name: qwen3-8B model.aibrix.ai/port: 30000 model.aibrix.ai/engine: sglang spec: containers: - name: decode image: aibrix/sglang:v0.4.9.post3-cu126-nixl-v0.4.1 command: [sh, -c] args: - | python3 -m sglang.launch_server \ --model-path /models/Qwen3-8B \ --served-model-name qwen3-8B \ --host 0.0.0.0 \ --port 30000 \ --disaggregation-mode decode \ --disaggregation-transfer-backendnixl \ --trust-remote-code \ --dist-init-addr ${PODSET_NAME}-0.${STORM_SERVICE_NAME}.default.svc.cluster.local:5000 \ --nnodes 2 \ --node-rank $POD_GROUP_INDEX \ --tp-size 2 \ --mem-fraction-static 0.8 \ --log-level debug env: - name: GLOO_SOCKET_IFNAME value: eth0 - name: NCCL_SOCKET_IFNAME value: eth0 - name: NCCL_IB_DISABLE value: 0 - name: NCCL_IB_GID_INDEX value: 7 - name: NCCL_DEBUG value: INFO - name: UCX_TLS value: ^gga volumeMounts: - name: model-vol mountPath: /models - mountPath: /dev/shm name: shared-mem resources: limits: nvidia.com/gpu: 1 vke.volcengine.com/rdma: 1 securityContext: capabilities: add: - IPC_LOCK volumes: - name: model-vol hostPath: path: /root/models type: Directory - emptyDir: medium: Memory name: shared-mem要点拆解routing 角色使用aibrix/sglang-router:v0.1.6运行sglang_router.launch_router开启--pd-disaggregation与--service-discovery端口 30000通过--prefill-selector/--decode-selector分别按storm-service-name、role-name与pod-group-index0发现对应的 prefill/decode Podprefill / decode 角色各自podGroupSize: 2、stateful: true两个节点通过--dist-init-addr ${PODSET_NAME}-0.${STORM_SERVICE_NAME}.default.svc.cluster.local:5000确定性地互相发现--node-rank $POD_GROUP_INDEX提供每个节点的 rank配合--nnodes 2 --tp-size 2完成跨节点张量并行环境变量部分配置了 RDMA/InfiniBand 相关的 NCCL 参数NCCL_IB_DISABLE0、NCCL_IB_GID_INDEX7、NCCL_DEBUGINFO、UCX_TLS^gga等并在 Pod 网络注解中声明rdmaCNI 网络体现引擎原生分布式后端 RDMA的典型形态两个角色共享model-volhostPath/root/models与内存型/dev/shm卷。更完整的 Prefill/Decode 分离指南见 pd-disaggregation。容器镜像要求注意从v0.6.6起官方 vLLM 容器镜像发行版已内置运行分布式推理所需的必要包开箱即用更早版本请按下面的指引构建兼容镜像。如果你使用更早的 vLLM 版本有两个选择直接使用 AIBrix 构建好的镜像aibrix/vllm-openai:v0.6.1.post2-distributed按以下步骤自行构建FROM vllm/vllm-openai:v0.6.1.post2 RUN apt update apt install -y wget RUN pip3 install ray[default] ENTRYPOINT []docker build -t aibrix/vllm-openai:v0.6.1.post2-distributed .小结AIBrix 的多节点推理能力本质上是选择适合你拓扑的编排层需要 Ray 提供进程级协调与标准 vLLM 部署时选RayClusterFleet配 KubeRay开启RayClusterStatusConditionsfeature gate用model.aibrix.ai/name与ray.io/overwrite-container-cmd等标签/注解完成发现与启动需要 PD 分离、多角色架构或纯 K8s 环境时选StormService用podGroupSize实现多节点分组靠$POD_GROUP_INDEX/$PODSET_NAME注入确定性 rank 与发现地址。两条路径共享同一套网关路由与指标体系可将请求统一收敛到 head Pod或路由角色实现多节点与单节点部署的无缝衔接。延伸阅读分布式推理示例目录fleet-two-node.yaml两节点 RayClusterFleet 完整清单PD 分离示例目录tp-1p1d.yamlStormService 多节点 TP 示例PodAutoscaler 文档以 RayClusterFleet 为scaleTargetRef的自动扩缩容安装指南KubeRay operator 的可选安装PD 分离指南基于 StormService 的 Prefill/Decode 分离完整指南运行时 sidecar 文档head Pod 上的 AI Runtime 指标与探针【免费下载链接】aibrixCost-efficient and pluggable Infrastructure components for GenAI inference项目地址: https://gitcode.com/GitHub_Trending/ai/aibrix创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →