# 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 配置代理 + 国内镜像加速器 ```bash # /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**,其他源用国内镜像) ```dockerfile 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 ```bash 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 时设环境变量走代理 ```bash 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 策略,不锁死版本号 ```bash # /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 上不存在,创建了损坏的符号链接 **解决**:条件创建,源文件不存在时跳过 ```bash ([ -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 模块 **解决**:改为条件判断,文件不存在就跳过 ```bash 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 循环导入 **解决**: 1. 安装 amdsmi(原生 Linux 上可用,WSL2 不需要) 2. 补丁 6:`platforms/__init__.py` 加 `torch.version.hip` 兜底 3. 补丁 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` 包未安装 **解决**: 1. 安装 `rocm-core` 包(提供 `rocm_version.h`) 2. 手动创建 `/opt/rocm/include/hip/hip_version.h` 兼容头文件 ```bash 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`,并检查版本化目录的符号链接 ```cmake # 错误 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 在以下方面不可控: 1. **尝试一(ENV 透传)**:在 Dockerfile `ENV` 块中添加 `CMAKE_PREFIX_PATH`、`CMAKE_HIP_COMPILER`、`ROCM_PATH` 等 8 个 cmake 环境变量,期望 pip 触发的 cmake 继承这些值。**无效**——vllm 的 `cmake_build_ext` 内部会独立构造 cmake 参数,不完全依赖环境变量。 2. 错误始终出现在 `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): ```bash # 替换前(会触发 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` 文件保证: ```bash echo "/opt/vllm" > ${VENV}/lib/python${PYTHON_VER}/site-packages/vllm.pth ``` **附:ENV 块新增的 cmake 变量(保留,对阶段 8a 和其他 cmake 调用有益)**: ```dockerfile 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` 正常显示 vllm - `import vllm` 在所有 Python 进程中正常工作 --- *最后更新: 2026-06-17*