预计阅读 6 分钟

生产 1:Docker 部署

谁该读这一篇? 准备把 SGLang 跑进 Docker(生产 / CI / 多环境隔离)的运维 / SRE。 前置阅读: 01-overview/05-quickstart.md耗时: 25 分钟 学完能: 1. 用官方镜像起一个 SGLang 容器; 2. 自建镜像,控制每一层; 3. 知道 GPU 驱动 / CUDA / 镜像版本的兼容矩阵; 4. 处理模型缓存 / 多 GPU / 网络配置; 5. 上线 checklist。


1. 官方镜像

SGLang 官方镜像:

lmsysorg/sglang:latest                       # 最新稳定
lmsysorg/sglang:v0.x.y                       # 固定版本
lmsysorg/sglang:dev                          # 开发版
lmsysorg/sglang:v0.x.y-cu124                 # 指定 CUDA 版本

镜像里包含:CUDA toolkit、PyTorch、FlashInfer、Triton、SGLang、常用依赖。

跑一下:

docker run --rm -it --gpus all --ipc=host \
    -p 30000:30000 \
    -v ~/.cache/huggingface:/root/.cache/huggingface \
    lmsysorg/sglang:latest \
    python -m sglang.launch_server \
        --model-path Qwen/Qwen2.5-7B-Instruct \
        --host 0.0.0.0 \
        --port 30000

关键 flag:

  • --gpus all:把宿主机所有 GPU 暴露给容器。
  • --ipc=host:让容器用宿主机 shared memory(PyTorch dataloader 需要)。
  • -v ~/.cache/huggingface:/root/.cache/huggingface:模型缓存挂出来,重启不重新下。

2. 自建镜像

照抄官方 Dockerfile 一份,自己改:

# Dockerfile.sglang
ARG CUDA_VERSION=12.4.1
FROM nvidia/cuda:${CUDA_VERSION}-cudnn-devel-ubuntu22.04

ENV DEBIAN_FRONTEND=noninteractive \
    PIP_NO_CACHE_DIR=1 \
    PYTHONUNBUFFERED=1

# 系统依赖
RUN apt-get update && apt-get install -y \
    python3.11 python3.11-venv python3-pip \
    git curl ca-certificates \
    libnuma-dev \
    && rm -rf /var/lib/apt/lists/*

RUN ln -sf /usr/bin/python3.11 /usr/bin/python

# 装 sglang
ARG SGLANG_VERSION=0.5.0
RUN pip install --upgrade pip && \
    pip install "sglang[all]==${SGLANG_VERSION}"

# 校验
RUN python -m sglang.check_env || true

WORKDIR /workspace
EXPOSE 30000

ENTRYPOINT ["python", "-m", "sglang.launch_server"]
CMD ["--help"]

build:

docker build -t mycompany/sglang:0.5.0-cu124 -f Dockerfile.sglang .

3. 多阶段构建(减小镜像)

# Stage 1: 构建
FROM nvidia/cuda:12.4.1-cudnn-devel-ubuntu22.04 AS builder
RUN apt-get update && apt-get install -y python3.11 python3-pip
RUN pip install --user "sglang[all]==0.5.0"

# Stage 2: 运行(不带 devel)
FROM nvidia/cuda:12.4.1-cudnn-runtime-ubuntu22.04
RUN apt-get update && apt-get install -y python3.11
COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH

EXPOSE 30000
ENTRYPOINT ["python", "-m", "sglang.launch_server"]

效果:镜像从 ~20 GB → ~8 GB。


4. CUDA / 驱动兼容矩阵

Host 驱动 容器 CUDA 备注
535+ 12.4 / 12.6 / 12.8
525-534 最多 12.2 可能不支持新 GPU 特性
470+ 11.8 老服务器,性能差

宿主机驱动版本必须 ≥ 容器 CUDA。nvidia-smi 第一行看驱动。


5. 模型缓存策略

模型 7-700 GB 不等,下载慢。三种方案:

5.1 挂宿主机目录(开发)

-v ~/.cache/huggingface:/root/.cache/huggingface

简单,但容器迁移要重下。

5.2 NFS / 共享存储

集群多节点共享一个 NFS:

-v /mnt/nfs/hf_cache:/root/.cache/huggingface

首次任一节点下载,后续所有节点直接用。

5.3 模型烤进镜像

RUN huggingface-cli download Qwen/Qwen2.5-7B-Instruct \
    --local-dir /models/qwen2.5-7b
ENV MODEL_PATH=/models/qwen2.5-7b
CMD ["--model-path", "/models/qwen2.5-7b", ...]

启动最快,但镜像变大(10+ GB),并且模型版本固定。 适合:生产稳定版本、CI 测试镜像。


6. 多 GPU / TP

docker run --gpus all --ipc=host --shm-size=64g \
    -p 30000:30000 \
    -v ~/.cache/huggingface:/root/.cache/huggingface \
    lmsysorg/sglang:latest \
    python -m sglang.launch_server \
        --model-path meta-llama/Llama-3.1-70B-Instruct \
        --tp 4 \
        --port 30000

--shm-size=64g:NCCL 之间共享内存通信,默认 64 MB 不够,要调大。 某些主机 P2P 需要:--privileged--ulimit memlock=-1


7. 网络配置

7.1 端口暴露

-p 30000:30000                    # HTTP API
-p 31000:31000                    # metrics(独立端口可选)
-p 5000:5000                      # disagg bootstrap

7.2 跨容器(多副本)

用 docker-compose:

version: "3"
services:
  sglang-1:
    image: lmsysorg/sglang:latest
    ports: ["30001:30000"]
    deploy:
      resources:
        reservations:
          devices: [{ driver: nvidia, device_ids: ["0","1"], capabilities: [gpu] }]
    command:
      - python
      - -m
      - sglang.launch_server
      - --model-path
      - Qwen/Qwen2.5-72B-Instruct
      - --tp
      - "2"

  sglang-2:
    image: lmsysorg/sglang:latest
    ports: ["30002:30000"]
    deploy:
      resources:
        reservations:
          devices: [{ driver: nvidia, device_ids: ["2","3"], capabilities: [gpu] }]
    command: [..., --tp, "2"]

  router:
    image: lmsysorg/sglang-router:latest
    ports: ["30000:30000"]
    depends_on: [sglang-1, sglang-2]
    command:
      - --worker-urls
      - http://sglang-1:30000
      - http://sglang-2:30000
      - --port
      - "30000"

8. 健康检查

# 容器内部
curl localhost:30000/health             # 200 = OK

# 等 model ready:
curl localhost:30000/health_generate    # 跑一个小请求验证

# Prometheus metrics:
curl localhost:30000/metrics

Docker healthcheck:

HEALTHCHECK --interval=30s --timeout=10s --start-period=5m --retries=3 \
    CMD curl -f http://localhost:30000/health || exit 1

start-period=5m 给模型加载预留时间。


9. 资源限制

docker run \
    --gpus all \
    --memory=64g \
    --cpus=8 \
    --shm-size=32g \
    --ipc=host \
    ...

注意:

  • CPU / 内存限制对推理性能影响不大(GPU 是瓶颈)。
  • shm-size 务必给够。
  • 不要限制 GPU 显存(驱动层级做不到)。

10. 安全建议

实践 说明
Non-root 运行 USER 1000,避免容器 escape 是 root
私有镜像仓库 别 push lmsysorg 到 docker hub 公仓
模型权重不打进公开镜像 私有模型走 secrets / NFS
API key 不写镜像 用环境变量 / secrets
HTTPS 终结在 ingress 容器内 plain HTTP,外层 LB 加 TLS

11. 上线 checklist

  • [ ] 固定镜像版本(不用 :latest
  • [ ] 模型路径稳定(NFS / 烤镜像)
  • [ ] --ipc=host + --shm-size=64g
  • [ ] 健康检查 / start-period 给够
  • [ ] Metrics 端口暴露给监控
  • [ ] 日志输出到 stdout(Docker 自动收)
  • [ ] 优雅退出 hook(SIGTERM 等请求处理完)
  • [ ] 资源 reservation(GPU device_ids 明确)

12. 小结

  • 官方镜像 + 挂载模型 cache 是最快上手方式。
  • 自建镜像可控版本和体积;多阶段构建省 60% 大小。
  • 多 GPU 必须 --ipc=host --shm-size 调大。
  • 健康检查 start-period 给 5+ 分钟。
  • 安全:non-root、私仓、不打权重进镜像。

13. 自检

  1. --ipc=host 干什么?不加会发生什么?
答案 让容器**共享宿主机的 IPC namespace**——主要是 `/dev/shm`(共享内存段)和 System V IPC。 PyTorch 用 shared memory 做进程间张量传递(DataLoader、TP NCCL 内部 buffer 等)。容器默认 `/dev/shm` 只有 64 MB,多 GPU TP 启动时 NCCL 分配 buffer 立刻就会爆,启动卡死或报 "Bus error" / "shared memory exhausted"。 `--ipc=host` 直接用宿主机的 `/dev/shm`(通常几十 GB),干净利落。 替代方案:`--shm-size=64g`(独立 namespace 但调大),更隔离但占机器内存。 生产推荐 `--shm-size`,开发用 `--ipc=host` 方便。
  1. 怎么减小自建镜像体积一半?
答案 多阶段构建: ```dockerfile FROM nvidia/cuda:12.4.1-devel AS builder RUN pip install --user "sglang[all]" FROM nvidia/cuda:12.4.1-runtime COPY --from=builder /root/.local /root/.local ``` 差异: - `devel` 镜像含 CUDA toolchain(nvcc / 头文件 / cuDNN devel),20 GB。 - `runtime` 镜像只含运行时库,8 GB。 - 把 pip 装的依赖从 builder 拷过来,得 runtime 8 GB + 依赖 5 GB ≈ 13 GB(vs 单阶段 20+ GB)。 再砍: - 删 pip cache(`PIP_NO_CACHE_DIR=1`)。 - 不装 dev / docs 依赖。 - 用 distroless 或 alpine 基础(但 GPU 镜像兼容性差,慎用)。
  1. 模型烤进镜像 vs NFS 各自的取舍?
答案 **烤进镜像**: - 优势:启动最快(无网络下载);版本严格绑定;不可变;适合 CI 测试 / 私有模型上线。 - 劣势:镜像巨大(70B fp8 ~70 GB),镜像仓库 / pull 慢;切换模型要重新 build;难以多模型共用。 **NFS / 共享存储**: - 优势:所有节点共享一份;切模型只改 path;镜像本身小。 - 劣势:NFS 故障是全集群单点;首次冷启读 NFS 慢(如果不预热);权限管理复杂。 规则: - 单一稳定模型 + 严格版本 → 烤镜像。 - 多模型 / 频繁切换 / 大集群 → NFS + local SSD 二级缓存。 - K8s 上常用 PV + initContainer 预热到 local SSD。
  1. 多 GPU TP 启动卡住,可能跟 docker 哪个参数有关?
答案 关键参数排查: (1) **`--shm-size` / `--ipc=host`**:NCCL 共享内存 buffer 不够,最常见。 (2) **`--gpus all` 或 `--gpus '"device=0,1,2,3"'`**:GPU device 没正确暴露,nvidia-smi 在容器里看不到 4 张卡。 (3) **`--ulimit memlock=-1`**:NCCL 用 pinned memory,被 ulimit 限制时分配失败。 (4) **`--privileged` 或 cap_add SYS_PTRACE**:某些 P2P 拓扑探测需要权限。 (5) **network=host** 或 IB 设备暴露:跨节点 TP 需要 NCCL 走 IB,容器默认 bridge 网络 IB 看不到。 定位:进容器跑 `nvidia-smi`、`ls /dev/nvidia*`、`ipcs -m`,看缺哪样。
  1. Healthcheck 没设 start-period 会怎样?
答案 K8s / Docker healthcheck 默认从容器启动那一刻就开始 ping `/health`,连续 N 次失败就标记 unhealthy 重启容器。 SGLang 模型加载 + CUDA Graph capture 可能要 1-5 分钟,期间 `/health` 还没就绪。没 start-period 时 healthcheck 一直失败,容器在永远启动 → 永远健康检查失败 → 永远重启的循环。 `start-period 300s`(5 分钟宽限期):这段时间内的 healthcheck 失败不计入失败次数,等服务就绪后再开始严格检查。 建议:start-period 设到 模型加载时间 × 2;70B 给 5 分钟;large MoE 给 10 分钟。 配合 `readinessProbe` 用 `/health_generate`(真跑一次请求)比 `/health`(只 ping)更准。

14. 下一步

上游源码:sglang/docker/