在 Kubernetes 上部署#
本文档介绍如何在 Kubernetes (K8S) 集群上部署基于 RoCE 网络的 SGLang 双节点推理服务。
LeaderWorkerSet (LWS) 是一个 Kubernetes API,旨在解决 AI/ML 推理工作负载的常见部署模式。一个主要用例是多主机/多节点的分布式推理。
SGLang 也可以与 LWS 一起部署在 Kubernetes 上,用于分布式模型服务。
有关使用 LWS 在 Kubernetes 上部署 SGLang 的更多详细信息,请参阅本指南。
这里我们以 DeepSeek-R1 的部署为例。
前提条件#
至少需要两个 Kubernetes 节点,每个节点配备两个 H20 系统和八个 GPU。
确保你的 K8S 集群已正确安装 LWS。如果尚未设置,请按照安装说明进行操作。注意:对于 LWS 版本 ≤0.5.x,你必须使用 Downward API 来获取
LWS_WORKER_INDEX
,因为此功能的原生支持是在 v0.6.0 中引入的。
基本示例#
有关基本示例文档,请参阅使用 SGLang 和 LWS 在 GPU 上部署分布式推理服务。
然而,该文档仅涵盖基本的 NCCL socket 模式。
在本节中,我们将进行一些简单的修改,以使设置适应 RDMA 场景。
RDMA RoCE 示例#
检查你的环境
[root@node1 ~]# ibstatus
Infiniband device 'mlx5_bond_0' port 1 status:
default gid: fe80:0000:0000:0000:0225:9dff:fe64:c79a
base lid: 0x0
sm lid: 0x0
state: 4: ACTIVE
phys state: 5: LinkUp
rate: 200 Gb/sec (2X NDR)
link_layer: Ethernet
Infiniband device 'mlx5_bond_1' port 1 status:
default gid: fe80:0000:0000:0000:0225:9dff:fe6e:c3ec
base lid: 0x0
sm lid: 0x0
state: 4: ACTIVE
phys state: 5: LinkUp
rate: 200 Gb/sec (2X NDR)
link_layer: Ethernet
Infiniband device 'mlx5_bond_2' port 1 status:
default gid: fe80:0000:0000:0000:0225:9dff:fe73:0dd7
base lid: 0x0
sm lid: 0x0
state: 4: ACTIVE
phys state: 5: LinkUp
rate: 200 Gb/sec (2X NDR)
link_layer: Ethernet
Infiniband device 'mlx5_bond_3' port 1 status:
default gid: fe80:0000:0000:0000:0225:9dff:fe36:f7ff
base lid: 0x0
sm lid: 0x0
state: 4: ACTIVE
phys state: 5: LinkUp
rate: 200 Gb/sec (2X NDR)
link_layer: Ethernet
准备用于在 k8s 上部署的
lws.yaml
文件。
apiVersion: leaderworkerset.x-k8s.io/v1
kind: LeaderWorkerSet
metadata:
name: sglang
spec:
replicas: 1
leaderWorkerTemplate:
size: 2
restartPolicy: RecreateGroupOnPodRestart
leaderTemplate:
metadata:
labels:
role: leader
spec:
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true
hostIPC: true
containers:
- name: sglang-leader
image: sglang:latest
securityContext:
privileged: true
env:
- name: NCCL_IB_GID_INDEX
value: "3"
command:
- python3
- -m
- sglang.launch_server
- --model-path
- /work/models
- --mem-fraction-static
- "0.93"
- --torch-compile-max-bs
- "8"
- --max-running-requests
- "20"
- --tp
- "16" # Size of Tensor Parallelism
- --dist-init-addr
- $(LWS_LEADER_ADDRESS):20000
- --nnodes
- $(LWS_GROUP_SIZE)
- --node-rank
- $(LWS_WORKER_INDEX)
- --trust-remote-code
- --host
- "0.0.0.0"
- --port
- "40000"
resources:
limits:
nvidia.com/gpu: "8"
ports:
- containerPort: 40000
readinessProbe:
tcpSocket:
port: 40000
initialDelaySeconds: 15
periodSeconds: 10
volumeMounts:
- mountPath: /dev/shm
name: dshm
- name: model
mountPath: /work/models
- name: ib
mountPath: /dev/infiniband
volumes:
- name: dshm
emptyDir:
medium: Memory
- name: model
hostPath:
path: '< your models dir >' # modify it according your models dir
- name: ib
hostPath:
path: /dev/infiniband
workerTemplate:
spec:
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true
hostIPC: true
containers:
- name: sglang-worker
image: sglang:latest
securityContext:
privileged: true
env:
- name: NCCL_IB_GID_INDEX
value: "3"
command:
- python3
- -m
- sglang.launch_server
- --model-path
- /work/models
- --mem-fraction-static
- "0.93"
- --torch-compile-max-bs
- "8"
- --max-running-requests
- "20"
- --tp
- "16" # Size of Tensor Parallelism
- --dist-init-addr
- $(LWS_LEADER_ADDRESS):20000
- --nnodes
- $(LWS_GROUP_SIZE)
- --node-rank
- $(LWS_WORKER_INDEX)
- --trust-remote-code
resources:
limits:
nvidia.com/gpu: "8"
volumeMounts:
- mountPath: /dev/shm
name: dshm
- name: model
mountPath: /work/models
- name: ib
mountPath: /dev/infiniband
volumes:
- name: dshm
emptyDir:
medium: Memory
- name: ib
hostPath:
path: /dev/infiniband
- name: model
hostPath:
path: /data1/models/deepseek_v3_moe
---
apiVersion: v1
kind: Service
metadata:
name: sglang-leader
spec:
selector:
leaderworkerset.sigs.k8s.io/name: sglang
role: leader
ports:
- protocol: TCP
port: 40000
targetPort: 40000
然后使用
kubectl apply -f lws.yaml
,你将获得此输出。
NAME READY STATUS RESTARTS AGE
sglang-0 0/1 Running 0 9s
sglang-0-1 1/1 Running 0 9s
等待 sglang leader (sglang-0
) 的状态变为 1/1,这表明它已 Ready
。
你可以使用命令 kubectl logs -f sglang-0
来查看 leader 节点的日志。
成功后,你应该看到类似这样的输出
[2025-02-17 05:27:24 TP1] Capture cuda graph end. Time elapsed: 84.89 s
[2025-02-17 05:27:24 TP6] max_total_num_tokens=712400, chunked_prefill_size=8192, max_prefill_tokens=16384, max_running_requests=50, context_len=163840
[2025-02-17 05:27:24 TP0] max_total_num_tokens=712400, chunked_prefill_size=8192, max_prefill_tokens=16384, max_running_requests=50, context_len=163840
[2025-02-17 05:27:24 TP7] max_total_num_tokens=712400, chunked_prefill_size=8192, max_prefill_tokens=16384, max_running_requests=50, context_len=163840
[2025-02-17 05:27:24 TP3] max_total_num_tokens=712400, chunked_prefill_size=8192, max_prefill_tokens=16384, max_running_requests=50, context_len=163840
[2025-02-17 05:27:24 TP2] max_total_num_tokens=712400, chunked_prefill_size=8192, max_prefill_tokens=16384, max_running_requests=50, context_len=163840
[2025-02-17 05:27:24 TP4] max_total_num_tokens=712400, chunked_prefill_size=8192, max_prefill_tokens=16384, max_running_requests=50, context_len=163840
[2025-02-17 05:27:24 TP1] max_total_num_tokens=712400, chunked_prefill_size=8192, max_prefill_tokens=16384, max_running_requests=50, context_len=163840
[2025-02-17 05:27:24 TP5] max_total_num_tokens=712400, chunked_prefill_size=8192, max_prefill_tokens=16384, max_running_requests=50, context_len=163840
[2025-02-17 05:27:24] INFO: Started server process [1]
[2025-02-17 05:27:24] INFO: Waiting for application startup.
[2025-02-17 05:27:24] INFO: Application startup complete.
[2025-02-17 05:27:24] INFO: Uvicorn running on http://0.0.0.0:40000 (Press CTRL+C to quit)
[2025-02-17 05:27:25] INFO: 127.0.0.1:48908 - "GET /get_model_info HTTP/1.1" 200 OK
[2025-02-17 05:27:25 TP0] Prefill batch. #new-seq: 1, #new-token: 7, #cached-token: 0, cache hit rate: 0.00%, token usage: 0.00, #running-req: 0, #queue-req: 0
[2025-02-17 05:27:32] INFO: 127.0.0.1:48924 - "POST /generate HTTP/1.1" 200 OK
[2025-02-17 05:27:32] The server is fired up and ready to roll!
如果它未能成功启动,请按照以下步骤检查任何遗留问题。谢谢!
调试#
设置
NCCL_DEBUG=TRACE
来检查是否是 NCCL 通信问题。
这应该能解决大多数与 NCCL 相关的问题。
注意:如果你发现在容器环境中设置 NCCL_DEBUG=TRACE 无效,但进程卡住或遇到难以诊断的问题,请尝试切换到不同的容器镜像。有些镜像可能无法正确处理标准错误输出。
RoCE 场景#
请确保集群环境中 RDMA 设备可用。
请确保集群中的节点具有支持 RoCE 的 Mellanox 网卡。在此示例中,我们使用 Mellanox ConnectX 5 型号的网卡,并且已安装适当的 OFED 驱动程序。如果尚未安装,请参阅文档安装 OFED 驱动程序来安装驱动程序。
检查你的环境
$ lspci -nn | grep Eth | grep Mellanox 0000:7f:00.0 Ethernet controller [0200]: Mellanox Technologies MT43244 BlueField-3 integrated ConnectX-7 network controller [15b3:a2dc] (rev 01) 0000:7f:00.1 Ethernet controller [0200]: Mellanox Technologies MT43244 BlueField-3 integrated ConnectX-7 network controller [15b3:a2dc] (rev 01) 0000:c7:00.0 Ethernet controller [0200]: Mellanox Technologies MT43244 BlueField-3 integrated ConnectX-7 network controller [15b3:a2dc] (rev 01) 0000:c7:00.1 Ethernet controller [0200]: Mellanox Technologies MT43244 BlueField-3 integrated ConnectX-7 network controller [15b3:a2dc] (rev 01) 0001:08:00.0 Ethernet controller [0200]: Mellanox Technologies MT43244 BlueField-3 integrated ConnectX-7 network controller [15b3:a2dc] (rev 01) 0001:08:00.1 Ethernet controller [0200]: Mellanox Technologies MT43244 BlueField-3 integrated ConnectX-7 network controller [15b3:a2dc] (rev 01) 0001:a2:00.0 Ethernet controller [0200]: Mellanox Technologies MT43244 BlueField-3 integrated ConnectX-7 network controller [15b3:a2dc] (rev 01) 0001:a2:00.1 Ethernet controller [0200]: Mellanox Technologies MT43244 BlueField-3 integrated ConnectX-7 network controller [15b3:a2dc] (rev 01)
检查 OFED 驱动程序
ofed_info -s OFED-internal-23.07-0.5.0:
显示 RDMA 链路状态并检查 IB 设备
$ rdma link show 8/1: mlx5_bond_0/1: state ACTIVE physical_state LINK_UP netdev reth0 9/1: mlx5_bond_1/1: state ACTIVE physical_state LINK_UP netdev reth2 10/1: mlx5_bond_2/1: state ACTIVE physical_state LINK_UP netdev reth4 11/1: mlx5_bond_3/1: state ACTIVE physical_state LINK_UP netdev reth6 $ ibdev2netdev 8/1: mlx5_bond_0/1: state ACTIVE physical_state LINK_UP netdev reth0 9/1: mlx5_bond_1/1: state ACTIVE physical_state LINK_UP netdev reth2 10/1: mlx5_bond_2/1: state ACTIVE physical_state LINK_UP netdev reth4 11/1: mlx5_bond_3/1: state ACTIVE physical_state LINK_UP netdev reth6
在主机上测试 RoCE 网络速度
yum install qperf # for server: execute qperf # for client qperf -t 60 -cm1 <server_ip> rc_rdma_write_bw
检查你的容器中 RDMA 是否可访问
# ibv_devices # ibv_devinfo
成功要点#
在上面的 YAML 配置中,请注意 NCCL 环境变量。对于旧版本的 NCCL,你应该检查 NCCL_IB_GID_INDEX 环境变量设置。
NCCL_SOCKET_IFNAME 也至关重要,但在容器化环境中,这通常不是问题。
在某些情况下,需要正确配置 GLOO_SOCKET_IFNAME。
NCCL_DEBUG 对于故障排除至关重要,但我发现有时它在容器内不显示错误日志。这可能与你使用的 Docker 镜像有关。如果需要,你可能需要尝试切换镜像。
避免使用基于 Ubuntu 18.04 的 Docker 镜像,因为它们往往存在兼容性问题。
遗留问题#
在 Kubernetes、Docker 或 Containerd 环境中,我们使用 hostNetwork 来防止性能下降。
我们使用了特权模式,这不安全。此外,在容器化环境中无法实现完全的 GPU 隔离。