14 KiB
Docker 构建问题汇总
目标:Ubuntu 24.04 + ROCm 7.2.1 + vllm + MinerU Docker 镜像
环境:原生 Linux + RX 9070 (gfx1201) + Privoxy (127.0.0.1:8118)
1. 网络类
1.1 Docker Hub 拉基础镜像超时
现象:dial tcp [2a03:2880:...]:443 i/o timeout
原因:docker.io 被墙,IPv6 直连超时
解决:Docker daemon 配置代理 + 国内镜像加速器
# /etc/systemd/system/docker.service.d/http-proxy.conf
Environment="HTTP_PROXY=http://127.0.0.1:8118"
Environment="HTTPS_PROXY=http://127.0.0.1:8118"
# /etc/docker/daemon.json
{
"registry-mirrors": ["https://docker.1panel.live", ...],
"ipv6": false
}
1.2 容器内无法访问国内镜像
现象:Could not resolve 'mirrors.tuna.tsinghua.edu.cn'
原因:Docker 默认 bridge 网络无法路由到外网
解决:docker-compose.yml 构建时加 network: host(非代理,只是共享宿主机网络栈)
1.3 GitHub 直连失败
现象:git clone github.com → GnuTLS recv error / TLS connection non-properly terminated
原因:GitHub 在国内不通,无可靠国内镜像
解决:git/wget 通过 Privoxy 代理访问 GitHub(仅 GitHub,其他源用国内镜像)
ARG GIT_PROXY=http://127.0.0.1:8118
git config --global http.proxy ${GIT_PROXY}
# wget: export http_proxy=${GIT_PROXY}
1.4 git clone 代理断连
现象:RPC failed; curl 92 HTTP/2 stream 5 was not closed cleanly: CANCEL
原因:HTTP/2 通过代理传大仓库不稳定
解决:禁用 HTTP/2 + 加大 buffer
git config --global http.version HTTP/1.1
git config --global http.postBuffer 524288000
1.5 PyTorch ROCm wheels 下载中断
现象:IncompleteRead (pip 下载 .whl 到一半断开)
原因:PyTorch 官方 CDN (download.pytorch.org) 在国内直连不稳定
解决:下载 PyTorch 时设环境变量走代理
export http_proxy=http://127.0.0.1:8118 https_proxy=http://127.0.0.1:8118
pip install ... --pre torch==2.11.0+rocm7.2 ...
1.6 flash-attention 子模块代理递归断连
现象:--recursive 克隆 flash-attention 时子模块 cutlass (~200MB) 下载失败:RPC failed; curl 56 GnuTLS recv error
原因:3 个子模块(composable_kernel + cutlass + aiter)挤在一条代理链路上,大文件容易丢包
解决(可选):宿主机预克隆后 COPY 入镜像。或用 --depth 1 + 逐个 git submodule update --init --depth 1(断了一个可单独重试)
2. Dockerfile 语法类
2.1 ENV 行内注释导致解析失败
现象:Syntax error - can't find = in "\ ",行号为 HSA_ENABLE_SDMA=1 \ # 注释
原因:Docker ENV 不允许行内 # 注释
解决:删除行内注释,或移到单独 # 行
2.2 多行 python -c "..." 被误解析
现象:dockerfile parse error: unknown instruction: import / unknown instruction: from
原因:Docker 解析器把 Python -c 的多行字符串当作 Dockerfile 指令(from x import y → 误认为 FROM;import x → 误认为未知指令)
解决:复杂 Python 代码写成独立脚本,用 COPY 进入镜像后 python /opt/xxx.py 执行
涉及的文件:
scripts/apply_mineru_patches.py— MinerU RDNA 适配补丁scripts/patch_vllm_platform.py— vllm 平台检测补丁
3. ROCm 兼容性类
3.1 版本号锁定失效
现象:Version '1.0.0.70201-38~24.04' for 'rocminfo' was not found
原因:AMD 仓库更新后精确版本号过期
解决:改用 apt pinning 策略,不锁死版本号
# /etc/apt/preferences.d/rocm-pin-600
Package: *
Pin: release o=repo.radeon.com
Pin-Priority: 600
3.2 hipcc.pl 符号链接创建损坏链接
现象:cmake 报 Can't find CUDA or HIP installation(PyTorch 的 LoadHIP.cmake:179)
原因:ln -sf /usr/bin/hipcc.pl /opt/rocm/bin/hipcc,/usr/bin/hipcc.pl 在原生 Linux 上不存在,创建了损坏的符号链接
解决:条件创建,源文件不存在时跳过
([ -f /usr/bin/hipcc.pl ] && ln -sf /usr/bin/hipcc.pl /opt/rocm/bin/hipcc) || echo "hipcc.pl not found"
3.3 缺 rocm-cmake 导致 find_package(HIP) 失败
现象:PyTorch LoadHIP.cmake:179 调用 find_package_and_print_version 找不到 HIP
原因:未安装 rocm-cmake 包,缺少 HIP cmake 发现模块
解决:在阶段 6 加装 rocm-cmake
3.4 vllm mamba operator+ 补丁失效
现象:sed: can't read csrc/mamba/mamba_ssm/selective_scan.h: No such file or directory
原因:vllm 上游已移除 mamba 模块
解决:改为条件判断,文件不存在就跳过
if [ -f csrc/mamba/mamba_ssm/selective_scan.h ]; then sed ...; else echo "skipping"; fi
3.5 原生 Linux 需要 amdsmi + 平台检测补丁
现象(社区反馈):ModuleNotFoundError: amdsmi → current_platform = UnspecifiedPlatform → Device string must not be empty
原因:amdsmi 未安装,且 logger.warning_once() 触发 vllm 循环导入
解决:
- 安装 amdsmi(原生 Linux 上可用,WSL2 不需要)
- 补丁 6:
platforms/__init__.py加torch.version.hip兜底 - 补丁 7:
platforms/rocm.py中logger.warning_once()→sys.stderr.write()
3.6 缺 hip_version.h 头文件
现象:Could not find hip/hip_version.h or rocm-core/rocm_version.h
原因:ROCm 7.2.1 的 apt 安装已将 hip_version.h 从默认路径移除,且 rocm-core 包未安装
解决:
- 安装
rocm-core包(提供rocm_version.h) - 手动创建
/opt/rocm/include/hip/hip_version.h兼容头文件
apt-get install -y rocm-core
# 兜底:手动生成 hip_version.h
printf '#define HIP_VERSION_MAJOR 7\n#define HIP_VERSION_MINOR 2\n...'
3.7 cmake 需显式设 HIP 编译器路径
现象:仅设 PATH + HIP_ROOT_DIR + ROCM_PATH 不足以让 cmake 发现 HIP
解决:显式指定
-DCMAKE_HIP_COMPILER=/opt/rocm/llvm/bin/clang++ # (非 hipcc,CMake 4.0 拒绝)
-DHIP_COMPILER=/opt/rocm/llvm/bin/clang++ # PyTorch LoadHIP 也需要
-DHIP_PATH=/opt/rocm
-DCMAKE_PREFIX_PATH="/opt/rocm;..."
3.8 PyTorch Caffe2Targets 缺失 cmake target(Docker 容器特有)
现象:cmake 反复报 hip::amdhip64 / hiprtc::hiprtc / roc::hipblas / roc::hipblaslt 等 target 未找到
原因:裸机部署时 ROCm 的 cmake 配置通过 /opt/rocm 完整安装,cmake 能自动发现所有 target。但 Docker 容器内 apt 安装的 dev 包缺少部分 cmake config 文件,PyTorch 的 Caffe2Targets.cmake 硬编码引用了这些 target
涉及 target 及修复:
| 报错 target | 命名空间问题 | 最终 alias |
|---|---|---|
hip::amdhip64 |
普通 target | SHARED IMPORTED → libamdhip64.so |
hiprtc::hiprtc |
需双冒号命名空间 | hiprtc::hiprtc ALIAS hip::hiprtc |
roc::hipblas |
roc:: 而非 hip:: | roc::hipblas ALIAS roc::rocblas |
roc::hipblaslt |
同上 | roc::hipblaslt ALIAS hip::hipblaslt |
roc::hiprand / roc::hipsolver 等 |
同上 | 各指向对应 roc::roc* target |
注意:roc::hip* → 应直接指向底层 roc::roc*(不能通过 hip::hip* 中转,因为后者本身是 ALIAS,CMake 不允许链式 ALIAS)
3.9 rocm-core-dev → rocm-core 包名错误
现象:E: Unable to locate package rocm-core-dev
原因:ROCm 7.2.1 仓库中的包名为 rocm-core(无 -dev 后缀)
解决:s/rocm-core-dev/rocm-core/
3.10 -lMIOpen 链接失败
现象:/usr/bin/ld: cannot find -lMIOpen
原因:miopen cmake config 使用了 INTERFACE IMPORTED(无实际 .so 路径),链接器找不到 libMIOpen.so
解决:改为 SHARED IMPORTED + 指定 IMPORTED_LOCATION,并检查版本化目录的符号链接
# 错误
add_library(miopen INTERFACE IMPORTED)
# 正确
add_library(miopen SHARED IMPORTED)
set_target_properties(miopen PROPERTIES
IMPORTED_LOCATION "/opt/rocm/lib/libMIOpen.so"
INTERFACE_INCLUDE_DIRECTORIES "/opt/rocm/include")
3.11 printf 参数计数错误
现象:cmake 报 add_library 在第 11 行语法错误(hiprtc-config.cmake:11)
原因:生成 cmake config 的 shell printf 格式串含 13 个 %s,但只传了 12 个参数,最后一行 hip::%s 未替换
解决:减少单行 printf 参数,复杂结构拆成独立循环
4. Docker 缓存策略
4.1 vllm 编译+验证同层导致缓存丢失
现象:ninja 编译 30 分钟成功后被后面验证失败拖垮,全部重来
解决:拆为 8a(编译)和 8b(安装+验证)
| 层 | 内容 | 缓存行为 |
|---|---|---|
| 8a | git clone + cmake + ninja | 编译成功即缓存,永不丢失 |
| 8b | pip install + PyTorch 修复 + 平台补丁 | 失败可重试,不影响 8a |
4.2 缓存失效条件
任一 RUN 层的指令或上下文变化都会导致该层及之后所有层重建。修改 ARG、ENV、COPY 文件内容均会触发。
4.3 COPY 脚本在 RUN 引用之后
现象:阶段 8b 执行 python /opt/patch_vllm_platform.py → 文件不存在
原因:COPY scripts/patch_vllm_platform.py 在阶段 8.5(原序号),但阶段 8b 已引用该脚本——Dockerfile 中 COPY 位于引用它的 RUN 之后
解决:将 COPY 指令移到所有需要脚本的 RUN 之前(阶段 7.5)。规则:COPY 必须在引用它的 RUN 之前
5. 网络策略总览
| 资源 | 访问方式 |
|---|---|
| Docker Hub | daemon 代理 + 国内镜像加速器 |
| Ubuntu apt | 清华镜像 mirrors.tuna.tsinghua.edu.cn |
| PyPI pip | 清华镜像 pypi.tuna.tsinghua.edu.cn/simple |
| AMD ROCm apt | repo.radeon.com 直连 |
| PyTorch ROCm wheels | download.pytorch.org 直连 |
| GitHub (git/wget) | Privoxy 代理 127.0.0.1:8118(唯一例外) |
6. 构建阶段类
6.1 阶段 8b pip install -e . 触发 cmake 配置失败
现象:阶段 8a(cmake + ninja 手动编译)成功,但阶段 8b 执行 pip install -e . --no-build-isolation --no-deps 时报错:
TorchConfig.cmake:62 (find_package)
→ CMakeLists.txt:95 (find_package)
→ Configuring incomplete, errors occurred!
error: failed-wheel-build-for-install
× Failed to build installable wheels for some pyproject.toml based projects
╰─> vllm
排查过程:
Dockerfile 设计为阶段 8a 手动执行 cmake -S ... -B ... -G Ninja(携带完整 -D 参数)编译 vllm C++ 扩展并复制 .abi3.so 文件,阶段 8b 再用 pip install -e . 注册 Python 包。但 pip install -e . 通过 vllm 的 setuptools 构建扩展再次触发 cmake,且 vllm 内部的 cmake 调用与手动 cmake 在以下方面不可控:
- 尝试一(ENV 透传):在 Dockerfile
ENV块中添加CMAKE_PREFIX_PATH、CMAKE_HIP_COMPILER、ROCM_PATH等 8 个 cmake 环境变量,期望 pip 触发的 cmake 继承这些值。无效——vllm 的cmake_build_ext内部会独立构造 cmake 参数,不完全依赖环境变量。 - 错误始终出现在
TorchConfig.cmake:62调用find_package(Caffe2)时,Caffe2 targets 引用的 ROCm cmake 目标无法被 pip 触发的 cmake 解析。
结论:pip install -e . 触发的 cmake 构建过程与阶段 8a 的手动 cmake 不在同一个可控环境中,且阶段 8b 的 pip install -e . 本质上是冗余的——C++ 扩展已在阶段 8a 编译完成。
最终解决:跳过 pip install -e .,手动创建 vllm editable package 元数据。
核心思路:阶段 8a 负责所有 C++ 编译(.abi3.so),阶段 8b 只负责 Python 包注册(不触发 cmake)。
具体改动(Dockerfile 阶段 8b):
# 替换前(会触发 cmake,失败):
cd /opt/vllm && \
${VENV}/bin/pip install -e . --no-build-isolation --no-deps && \
# 替换后(手动创建 egg-info,不触发 cmake):
cd /opt/vllm && \
mkdir -p vllm.egg-info && \
cat > vllm.egg-info/PKG-INFO << 'VLLM_EOF' && \
Metadata-Version: 2.1
Name: vllm
Version: 0.0.0
Summary: A high-throughput and memory-efficient inference and serving engine for LLMs
VLLM_EOF
echo "vllm" > vllm.egg-info/top_level.txt && \
touch vllm.egg-info/dependency_links.txt && \
touch vllm.egg-info/requires.txt && \
find vllm -name "*.py" -type f 2>/dev/null | sort > vllm.egg-info/SOURCES.txt && \
echo "vllm egg-info created (cmake build skipped, C++ extensions from stage 8a)" && \
手动创建的 egg-info 包含以下文件:
| 文件 | 内容 | 用途 |
|---|---|---|
PKG-INFO |
Name: vllm + Version: 0.0.0 |
pip freeze / importlib.metadata 识别 |
top_level.txt |
vllm |
声明顶层包名 |
SOURCES.txt |
所有 .py 文件列表 |
包文件索引 |
dependency_links.txt |
空文件 | 依赖链接(无) |
requires.txt |
空文件 | 运行依赖(由后续 pip install -r 安装) |
import vllm 的路径解析由现有的 .pth 文件保证:
echo "/opt/vllm" > ${VENV}/lib/python${PYTHON_VER}/site-packages/vllm.pth
附:ENV 块新增的 cmake 变量(保留,对阶段 8a 和其他 cmake 调用有益):
ENV ... \
CMAKE_PREFIX_PATH=/opt/rocm \
CMAKE_HIP_COMPILER=/opt/rocm/llvm/bin/clang++ \
HIP_COMPILER=/opt/rocm/llvm/bin/clang++ \
HIP_PATH=/opt/rocm \
HIP_ROOT_DIR=/opt/rocm \
HIP_INCLUDE_DIR=/opt/rocm/include \
HIP_PLATFORM=amd \
ROCM_PATH=/opt/rocm
效果:
- 阶段 8b 不再触发 cmake,消除了冗余编译(节省约 30 分钟)
- C++ 扩展只在阶段 8a 编译一次,职责清晰
pip list/pip freeze正常显示 vllmimport vllm在所有 Python 进程中正常工作
最后更新: 2026-06-17