docker-only部署单容器PD指南

特性介绍

本文档描述在不使用 Kubernetes deployer、仅用 Docker 容器 + 宿主机挂载配置 的方式部署单容器 MindIE Motor PD 推理服务的端到端流程,同时适用于 PD 混部和 PD 分离。

部署模式 Engine 实例 跨角色 KV 传输 单容器内拉起进程
PD 分离 Prefill 和 Decode 实例 需要 Coordinator、Controller、Prefill/Decode NodeManager
PD 混部 union 实例 不需要 Coordinator、Controller、union NodeManager

部署流程

/mnt/motor作为根路径,目录结构如下:

/mnt/motor/
├── prepare.sh
├── start_motor.sh
├── start_docker.sh
├── user_config.json
├── env.json
├── examples/
└── configmap/ # 该目录下的文件都是自动生成的
    ├── boot.sh
    ├── common.sh
    ├── hccl_tools.py
    ├── all_combine_in_single_container.sh
    ├── controller.sh
    ├── coordinator.sh
    ├── engine.sh
    ├── kv_conductor.sh
    ├── kv_cache_store.sh
    ├── kv_store_backends.mooncake.mooncake.sh
    ├── kv_store_backends.mooncake.mooncake_config.py
    ├── kv_store_backends.memcache.memcache.sh
    ├── kv_store_backends.memcache.memcache_meta_service.py
    ├── kv_store_backends.memcache.mmc-local-inprocess.conf
    ├── mf_store.sh
    ├── user_config.json
    └── env.json

准备 examples

examples 获取方式见快速入门的“服务部署”章节。从镜像拷贝至宿主机后,将后续 prepare.sh 中的 EXAMPLES_PATH 设置为该目录的绝对路径。

准备user_config.json和env.json配置文件

根据部署模式准备 user_config.jsonenv.json。配置字段的完整说明请参考 user_config 全量参数说明

两种模式均须配置:

  • motor_deploy_config.deploy_mode:必须设置为 single_container
  • Coordinator 推理、管理和可观测端口分别推荐使用 102510261027
  • Controller 管理和可观测端口推荐使用 20262027,避免与 Coordinator 冲突。
  • NodeManager 端口须配置在对应 engine section 的 motor_nodemanger_config.api_config 下。

PD 分离配置

{
  "motor_deploy_config": {
    ...
    "deploy_mode": "single_container",
    "p_instances_num": 1,
    "d_instances_num": 1
  },
  "motor_controller_config": {
    ...
    "api_config": {
      "controller_api_port": 2026,
      "observability_api_port": 2027
    }
  },
  "motor_coordinator_config": {
    ...
    "api_config": {
      "coordinator_api_infer_port": 1025,
      "coordinator_api_mgmt_port": 1026,
      "coordinator_obs_port": 1027
    }
  },
  "motor_engine_prefill_config": {
    ...
    "motor_nodemanger_config": {
      "api_config": {
        "node_manager_port": 3026
      }
    }
  },
  "motor_engine_decode_config": {
    ...
    "motor_nodemanger_config": {
      "api_config": {
        "node_manager_port": 4026
      }
    }
  },
  ...
}

env.json 分别使用 motor_engine_prefill_envmotor_engine_decode_env。同时须在 P/D engine 配置中正确设置 kv_transfer_config;启用 KV Cache Store 时,还需准备对应环境变量。

PD 混部配置

{
  "motor_deploy_config": {
    ...
    "deploy_mode": "single_container",
    "hybrid_instances_num": 1,
    "single_hybrid_instance_pod_num": 1,
    "hybrid_pod_npu_num": 2
  },
  "motor_controller_config": {
    ...
    "api_config": {
      "controller_api_port": 2026,
      "observability_api_port": 2027
    }
  },
  "motor_coordinator_config": {
    ...
    "api_config": {
      "coordinator_api_infer_port": 1025,
      "coordinator_api_mgmt_port": 1026,
      "coordinator_obs_port": 1027
    }
  },
  "motor_engine_union_config": {
    "engine_type": "vllm",
    ...
    "motor_nodemanger_config": {
      "api_config": {
        "node_manager_port": 3026
      }
    }
  },
  ...
}

env.json 使用 motor_engine_union_env 配置 union 实例环境变量。PD 混部不需要 kv_transfer_config

端口规划

组件 推荐端口 说明
Coordinator 推理 1025 通过 -p 31015:1025 暴露到宿主机
Coordinator 管理 1026 容器内部管理接口
Coordinator 可观测 1027 可按需通过 -p 31017:1027 暴露
Controller 管理 2026 避开 Coordinator 管理端口
Controller 可观测 2027 避开 Coordinator 可观测端口
union / Prefill NodeManager 3026 起 按实例规划
Decode NodeManager 4026 起 与 Prefill 区分

若修改 coordinator_api_infer_portdocker run 端口映射的容器侧端口须同步修改。

准备configmap

准备阶段需将配置文件、启动脚本拷贝到环境变量CONFIGMAP_PATH对应目录下,并通过set_env_docker.py加载环境变量。准备阶段脚本prepare.sh示例(EXAMPLES_PATHCONFIGMAP_PATHUSER_CONFIG_PATHENV_PATH需修改为实际路径):

以下以/mnt/motor作为根路径为例

EXAMPLES_PATH="/mnt/motor/examples/"
CONFIGMAP_PATH="/mnt/motor/configmap/"
USER_CONFIG_PATH="/mnt/motor/user_config.json"
ENV_PATH="/mnt/motor/env.json"

mkdir -p $CONFIGMAP_PATH

# 容器启动脚本boot.sh,其运行时会调用startup目录下其他脚本,需要将其统一拷贝到$CONFIGMAP_PATH目录下。
cp -f $EXAMPLES_PATH/deployer/startup/boot.sh $CONFIGMAP_PATH/boot.sh
cp -f $EXAMPLES_PATH/deployer/startup/common.sh $CONFIGMAP_PATH/common.sh
cp -f $EXAMPLES_PATH/deployer/startup/hccl_tools.py $CONFIGMAP_PATH/hccl_tools.py
cp -f $EXAMPLES_PATH/deployer/startup/roles/*.sh $CONFIGMAP_PATH/
cp -f $EXAMPLES_PATH/deployer/startup/roles/kv_store_backends/mooncake/mooncake.sh $CONFIGMAP_PATH/kv_store_backends.mooncake.mooncake.sh
cp -f $EXAMPLES_PATH/deployer/startup/roles/kv_store_backends/mooncake/mooncake_config.py $CONFIGMAP_PATH/kv_store_backends.mooncake.mooncake_config.py
cp -f $EXAMPLES_PATH/deployer/startup/roles/kv_store_backends/memcache/memcache.sh $CONFIGMAP_PATH/kv_store_backends.memcache.memcache.sh
cp -f $EXAMPLES_PATH/deployer/startup/roles/kv_store_backends/memcache/memcache_meta_service.py $CONFIGMAP_PATH/kv_store_backends.memcache.memcache_meta_service.py
cp -f $EXAMPLES_PATH/deployer/startup/roles/kv_store_backends/memcache/mmc-local-inprocess.conf $CONFIGMAP_PATH/kv_store_backends.memcache.mmc-local-inprocess.conf

# 将准备好的user_config.json和env.json配置文件拷贝到$CONFIGMAP_PATH目录下
cp -f $USER_CONFIG_PATH $CONFIGMAP_PATH/user_config.json
cp -f $ENV_PATH $CONFIGMAP_PATH/env.json

# 若环境变量已加载,但发生改动,需先清理旧的环境变量。
sed -i '/^function set_controller_env()/,/^}/d' $CONFIGMAP_PATH/controller.sh
sed -i '/^function set_coordinator_env()/,/^}/d' $CONFIGMAP_PATH/coordinator.sh
sed -i '/^function set_prefill_env()/,/^}/d' $CONFIGMAP_PATH/engine.sh
sed -i '/^function set_decode_env()/,/^}/d' $CONFIGMAP_PATH/engine.sh
sed -i '/^function set_union_env()/,/^}/d' $CONFIGMAP_PATH/engine.sh
sed -i '/^function set_common_env()/,/^}/d' $CONFIGMAP_PATH/common.sh
sed -i '/^function set_kv_store_env()/,/^}/d' $CONFIGMAP_PATH/kv_cache_store.sh
sed -i '/^function set_kv_conductor_env()/,/^}/d' $CONFIGMAP_PATH/kv_conductor.sh
sed -i '/^function set_controller_env()/,/^}/d' $CONFIGMAP_PATH/all_combine_in_single_container.sh
sed -i '/^function set_coordinator_env()/,/^}/d' $CONFIGMAP_PATH/all_combine_in_single_container.sh
sed -i '/^function set_prefill_env()/,/^}/d' $CONFIGMAP_PATH/all_combine_in_single_container.sh
sed -i '/^function set_decode_env()/,/^}/d' $CONFIGMAP_PATH/all_combine_in_single_container.sh
sed -i '/^function set_union_env()/,/^}/d' $CONFIGMAP_PATH/all_combine_in_single_container.sh
sed -i '/^function set_kv_store_env()/,/^}/d' $CONFIGMAP_PATH/all_combine_in_single_container.sh
sed -i '/^function set_kv_conductor_env()/,/^}/d' $CONFIGMAP_PATH/all_combine_in_single_container.sh
sed -i '/./,$!d' $CONFIGMAP_PATH/common.sh

# 加载user_config.json和env.json中的环境变量,并作用于容器启动脚本。
python $EXAMPLES_PATH/deployer/startup/set_env_docker.py --configmap_path $CONFIGMAP_PATH

执行方式:

sh prepare.sh

执行完成后,在/mnt/motor/configmap/目录下会生成一些脚本

准备Motor启动脚本

准备 start_motor.sh 脚本。两种模式共用该脚本;PD 混部不启用 KV Cache Store,将 KVS_MASTER_SERVICE 保持为空。PD 分离按需配置 KV Cache Store。

CONFIGMAP_PATH="/mnt/motor/configmap" # CONFIGMAP_PATH需与prepare.sh保持一致,且必须使用绝对路径
CONFIG_PATH=/usr/local/Ascend/pyMotor/conf

ROLE=SINGLE_CONTAINER

# mooncake池化配置
# PD 分离启用 Mooncake KV Cache Store 时,将 KV_STORE_BACKEND 设为 mooncake,
# KVS_MASTER_SERVICE 设为任意非空字符串;不启用或使用 PD 混部时均设置为空。
KV_STORE_BACKEND=""
KVS_MASTER_SERVICE=""
KV_CACHE_STORE_PORT=50088
KV_STORE_EVICTION_HIGH_WATERMARK_RATIO=0.9
KV_STORE_EVICTION_RATIO=0.1
DEFAULT_KV_LEASE_TTL=11000

source $CONFIGMAP_PATH/boot.sh

环境变量说明:

变量名 含义 取值
KV_STORE_BACKEND KV Cache Store 后端 PD 分离启用 Mooncake 时设置为 mooncake;不启用或使用 PD 混部时设置为空
KVS_MASTER_SERVICE Mooncake KV Cache Store 地址 PD 分离启用时设置任意非空字符串,启动脚本会适配为容器 IP;不启用或使用 PD 混部时设置为空
KV_CACHE_STORE_PORT Mooncake KV Cache Store 端口 启用时设置有效端口,如 50088
KV_STORE_EVICTION_HIGH_WATERMARK_RATIO KV Cache Store 高水位比例 启用时取值 0~1
KV_STORE_EVICTION_RATIO KV Cache Store 逐出比例 启用时取值 0~1
DEFAULT_KV_LEASE_TTL KV 对象默认租约 TTL(毫秒) 配置值须大于 env.json 中的 ASCEND_CONNECT_TIMEOUTASCEND_TRANSFER_TIMEOUT,默认 11000

准备Docker启动脚本

准备启动脚本start_docker.sh,脚本示例(CONFIGMAP_PATHWEIGHT_MOUNT_PATH需修改为实际绝对路径,IMAGE_NAME需修改为实际镜像名)。WEIGHT_MOUNT_PATH需与user_config.jsonweight_mount_path及模型路径保持一致:

# 默认不开启特权容器,如需开启,将--privileged=false改为--privileged=true
CONFIGMAP_PATH="/mnt/motor/configmap" # CONFIGMAP_PATH需与prepare.sh保持一致,且必须使用绝对路径
IMAGE_NAME="xxx" # 镜像名
WEIGHT_MOUNT_PATH="xxx" # 宿主机权重目录,必须使用绝对路径

ASCEND_DEVICES="--device=/dev/davinci_manager --device=/dev/devmm_svm --device=/dev/hisi_hdc"

docker run -u root --rm --name single_container \
-e ASCEND_RUNTIME_OPTIONS=NODRV --privileged=false \
$ASCEND_DEVICES \
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
-v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \
-v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \
-v /usr/local/sbin:/usr/local/sbin \
-v /var/log/npu/:/usr/slog \
-v /mnt:/mnt \
-v $CONFIGMAP_PATH:$CONFIGMAP_PATH \
-v $WEIGHT_MOUNT_PATH:$WEIGHT_MOUNT_PATH:ro \
-p 31015:1025 \
-p 31017:1027 \
$IMAGE_NAME \
bash -c "export POD_IP=\$(grep \$(hostname) /etc/hosts | cut -f1) && source /mnt/motor/start_motor.sh"

注意:挂载路径要包含/mnt

启动Docker

脚本会根据 user_config.json 自动拉起 union 实例或 Prefill/Decode 实例。

PD 分离启动示例(1P1D):

ASCEND_VISIBLE_DEVICES=0,1 sh start_docker.sh

PD 混部启动示例(1 个 union 实例):

ASCEND_VISIBLE_DEVICES=0,1 sh start_docker.sh

服务验证

服务就绪后,在宿主机执行以下命令。将 <IP> 替换为宿主机 IP 或 127.0.0.1,将 model 替换为 user_config.json 中配置的模型名称。

curl -X POST http://<IP>:31015/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3-8B",
    "messages": [
      {
        "role": "user",
        "content": "who are you?"
      }
    ],
    "max_tokens": 36,
    "stream": true
  }'

若返回 {"detail":"Service is not available"},表示服务尚未就绪,可稍后重试并查看 docker logs single_container。若返回流式 JSON,则说明推理正常。

说明

HTTP 协议存在安全风险,生产环境建议开启 HTTPS。接口和 TLS 配置请参考业务接口

Atlas 850 超节点服务器 环境额外修改内容

Atlas 850 超节点服务器创建容器时,需做如下调整:

网络:使用 --network host,替代 -p 端口映射。此时服务验证使用 http://<IP>:1025/v1/chat/completions

额外挂载路径

宿主机路径 容器路径 说明
/dev/ummu /dev/ummu Atlas 850 超节点服务器 卡间 UB 互联内存设备,UB 内存池访问依赖此通路
/dev/uburma /dev/uburma 服务器间 UB RDMA 通信设备节点
/usr/lib64 /usr/lib64 提供 liburma 等 UB 用户态通信库
/etc/hixlep /etc/hixlep UB 链路拓扑结构
/etc/hccl_rootinfo.json /etc/hccl_rootinfo.json HCCL 集群建链配置文件
/usr/local/bin/npu-smi /usr/local/bin/npu-smi NPU 管理工具
/usr/local/dcmi /usr/local/dcmi DCMI 库目录

Atlas 850 超节点服务器 启动示例片段:

ASCEND_DEVICES="--device=/dev/davinci_manager --device=/dev/hisi_hdc"

docker run -u root --rm --name single_container \
  --network host \
  ... \
  -v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
  -v /usr/lib64:/usr/lib64 \
  -v /etc/hixlep:/etc/hixlep \
  -v /etc/hccl_rootinfo.json:/etc/hccl_rootinfo.json \
  -v /usr/local/dcmi:/usr/local/dcmi \
  -v /dev/ummu:/dev/ummu \
  -v /dev/uburma:/dev/uburma \
  ... \