Files
mineru-rocm/docker/Dockerfile
T
2026-06-18 10:31:22 +08:00

347 lines
21 KiB
Docker
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# MinerU on ROCm 7.2.1 Docker Image(HK 云服务器 / 海外版)
# 原生 Linux + Ubuntu 24.04 + ROCm 7.2.1 + PyTorch 2.11.0 + vllm + MinerU 3.2.0
# =============================================================================
FROM ubuntu:24.04
# -- 构建参数 ---------------------------------------------------------------
ARG ARCH=gfx1201
ARG PYTHON_VER=3.12
ARG VENV=/opt/mineru_venv
ARG TORCH_INDEX=https://download.pytorch.org/whl/rocm7.2
# -- GitHub 访问(国内无镜像,需代理)----------------------------------------
ARG GIT_PROXY=http://127.0.0.1:8118
# -- 国内镜像 ----------------------------------------------------------------
ARG PIP_INDEX=https://mirrors.aliyun.com/pypi/simple
# -- 环境变量 ---------------------------------------------------------------
ENV DEBIAN_FRONTEND=noninteractive \
PATH=/opt/rocm/bin:/opt/rocm/llvm/bin:${VENV}/bin:${PATH} \
PYTORCH_ROCM_ARCH=${ARCH} \
FLASH_ATTENTION_TRITON_AMD_ENABLE=TRUE \
MINERU_MODEL_SOURCE=huggingface \
TORCH_ROCM_AOTRITON_ENABLE_EXPERIMENTAL=1 \
HSA_ENABLE_SDMA=1 \
VLLM_TARGET_DEVICE=rocm \
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
WORKDIR /opt
# ===========================================================================
# 阶段 1:换国内源 + 安装 ROCm 7.2.1
# ===========================================================================
RUN sed -i 's|http://.*archive.ubuntu.com|http://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list.d/ubuntu.sources && \
sed -i 's|http://.*security.ubuntu.com|http://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list.d/ubuntu.sources && \
export http_proxy=${GIT_PROXY} https_proxy=${GIT_PROXY} && \
apt-get update && apt-get install -y --no-install-recommends \
wget curl ca-certificates gnupg software-properties-common && \
wget -q https://repo.radeon.com/rocm/rocm.gpg.key -O - | \
gpg --dearmor | tee /etc/apt/trusted.gpg.d/rocm.gpg > /dev/null && \
echo 'deb [arch=amd64] https://repo.radeon.com/rocm/apt/7.2.1 noble main' \
> /etc/apt/sources.list.d/rocm.list && \
printf 'Package: *\nPin: release o=repo.radeon.com\nPin-Priority: 600\n' \
> /etc/apt/preferences.d/rocm-pin-600 && \
apt-get update && \
apt-get install -y --no-install-recommends \
rocminfo rocm-device-libs hip-dev miopen-hip && \
apt-get clean && rm -rf /var/lib/apt/lists/*
# ===========================================================================
# 阶段 2:ROCm 头文件补丁
# ===========================================================================
RUN set -ex && \
# 补丁 1: hipcc/clang 符号链接
ln -sf /usr/bin/hipvars.pm /usr/share/perl5/hipvars.pm && \
([ -f /usr/bin/hipcc.pl ] && ln -sf /usr/bin/hipcc.pl /opt/rocm/bin/hipcc) || echo "hipcc.pl not found, keeping apt-installed hipcc" && \
ln -sf /opt/rocm/llvm/bin/clang-22 /opt/rocm/llvm/bin/clang-17 && \
ln -sf /opt/rocm/llvm/bin/clang++ /opt/rocm/llvm/bin/clang++-17 && \
# 补丁 2: __hip_internal::conditional → std::conditional
find /opt/rocm/include/hip -name "*.h" \
-exec sed -i 's/__hip_internal::conditional/std::conditional/g' {} + && \
# 补丁 3: warpSize 常量
find /opt/rocm/include/hip -name "amd_warp_functions.h" \
-exec sed -i 's/static constexpr int warpSize = __AMDGCN_WAVEFRONT_SIZE;/constexpr int warpSize = 32;/g' {} + && \
# 补丁 4: __activemask() → __builtin_amdgcn_read_exec()
sed -i 's/__activemask()/__builtin_amdgcn_read_exec()/g' \
/opt/rocm/include/hip/amd_detail/amd_warp_sync_functions.h && \
echo "ROCm 7.2.1 header patches applied."
# ===========================================================================
# 阶段 3:系统依赖 + Python 3.12
# ===========================================================================
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential git ninja-build pkg-config \
python${PYTHON_VER} python${PYTHON_VER}-venv python${PYTHON_VER}-dev \
libnuma-dev libdrm2 libhwloc-dev libgl1 \
libgomp1 libopenblas0 && \
apt-get clean && rm -rf /var/lib/apt/lists/*
# ===========================================================================
# 阶段 4:CMake 4.0(通过代理下载加速)
# ===========================================================================
RUN export http_proxy=${GIT_PROXY} https_proxy=${GIT_PROXY} && \
cd /tmp && \
wget -q https://github.com/Kitware/CMake/releases/download/v4.0.0/cmake-4.0.0-linux-x86_64.tar.gz && \
tar -xzf cmake-4.0.0-linux-x86_64.tar.gz && \
cp -r cmake-4.0.0-linux-x86_64/bin/* /usr/local/bin/ && \
cp -r cmake-4.0.0-linux-x86_64/share/* /usr/local/share/ && \
rm -rf cmake-4.0.0-linux-x86_64* && \
cmake --version
# ===========================================================================
# 阶段 5:Python 虚拟环境 + PyTorch ROCm
# ===========================================================================
RUN python${PYTHON_VER} -m venv ${VENV} && \
mkdir -p /root/.pip && \
touch ${VENV}/torch-constraint.txt && \
echo "[global]" > /root/.pip/pip.conf && \
echo "index-url = ${PIP_INDEX}" >> /root/.pip/pip.conf && \
echo "[install]" >> /root/.pip/pip.conf && \
echo "constraint = ${VENV}/torch-constraint.txt" >> /root/.pip/pip.conf && \
${VENV}/bin/pip install -U pip setuptools wheel && \
# PyTorch ROCm wheels 在海外 CDN,通过代理下载
export http_proxy=${GIT_PROXY} https_proxy=${GIT_PROXY} && \
${VENV}/bin/pip install --pre \
torch==2.11.0+rocm7.2 \
torchvision \
pytorch-triton-rocm \
--index-url ${TORCH_INDEX} && \
# 锁定 torch 版本,防止后续 pip install 解析到 CUDA 版
echo "torch==2.11.0+rocm7.2" > ${VENV}/torch-constraint.txt && \
${VENV}/bin/python -c "import torch; print('PyTorch:', torch.__version__); assert torch.version.hip is not None"
# ===========================================================================
# 阶段 6:ROCm 开发包
# ===========================================================================
RUN export http_proxy=${GIT_PROXY} https_proxy=${GIT_PROXY} && \
apt-get update && apt-get install -y --no-install-recommends \
hipblas-dev hiprand-dev hipsparse-dev hipsparselt-dev \
hipsolver-dev hipcub-dev rocprim-dev rocthrust-dev \
rocblas-dev rocrand-dev hipfft-dev hipblaslt-dev \
rocsolver-dev rocfft-dev rocsparse-dev rocm-cmake rocm-core && \
apt-get clean && rm -rf /var/lib/apt/lists/*
# ===========================================================================
# 阶段 6.5:安装 amdsmi
# ===========================================================================
RUN if [ -d /opt/rocm/share/amd_smi ]; then \
cp -r /opt/rocm/share/amd_smi /opt/amd_smi && \
cd /opt/amd_smi && ${VENV}/bin/pip install . --no-build-isolation && \
echo "amdsmi installed."; \
else \
echo "amdsmi source not found, skipping."; \
fi
# ===========================================================================
# 阶段 7:复制预克隆仓库 + 安装 aiter + flash_attn
# ===========================================================================
COPY aiter/ /opt/aiter/
COPY flash-attention/ /opt/flash-attention/
RUN set -ex && \
${VENV}/bin/pip install -e /opt/aiter && \
${VENV}/bin/pip install --no-build-isolation -e /opt/flash-attention && \
${VENV}/bin/python -c "import torch; v=torch.__version__; assert 'rocm' in v, f'PyTorch overwritten: {v}'; print('PyTorch OK:', v)"
# ===========================================================================
# 阶段 8a:编译 vllm(cmake + ninja,最耗时,单独缓存)
# ===========================================================================
COPY vllm/ /opt/vllm/
RUN set -ex && \
${VENV}/bin/pip install -U \
"setuptools>=77.0.3,<82" setuptools_scm setuptools_rust wheel && \
cd /opt/vllm && \
if [ -f csrc/mamba/mamba_ssm/selective_scan.h ]; then \
sed -i '109,121s/^/\/\/ /' csrc/mamba/mamba_ssm/selective_scan.h && \
echo "vllm mamba operator+ patch applied."; \
else \
echo "vllm mamba selective_scan.h not found (upstream removed), skipping patch."; \
fi && \
mkdir -p /opt/rocm/lib/cmake/hiprand && \
printf 'include(/opt/rocm/lib/cmake/rocrand/rocrand-config.cmake)\nif(TARGET roc::rocrand AND NOT TARGET hip::hiprand)\n add_library(hip::hiprand ALIAS roc::rocrand)\nendif()\n' \
> /opt/rocm/lib/cmake/hiprand/hiprand-config.cmake && \
mkdir -p /opt/rocm/lib/cmake/hipblas && \
printf 'include(/opt/rocm/lib/cmake/rocblas/rocblas-config.cmake)\nif(TARGET roc::rocblas AND NOT TARGET hip::hipblas)\n add_library(hip::hipblas ALIAS roc::rocblas)\nendif()\nif(TARGET roc::rocblas AND NOT TARGET roc::hipblas)\n add_library(roc::hipblas ALIAS roc::rocblas)\nendif()\n' \
> /opt/rocm/lib/cmake/hipblas/hipblas-config.cmake && \
# 批量创建 hip→roc 别名 cmake config(仅原生 config 缺失时创建)
for pair in "hipcub:rocprim" "hipsolver:rocsolver" "hipsparse:rocsparse" "hipfft:rocfft"; do \
hip_pkg="${pair%%:*}"; roc_pkg="${pair#*:}"; \
cfg_dir="/opt/rocm/lib/cmake/${hip_pkg}"; \
if [ ! -f "${cfg_dir}/${hip_pkg}-config.cmake" ]; then \
mkdir -p "${cfg_dir}" && \
printf 'include(/opt/rocm/lib/cmake/%s/%s-config.cmake)\nif(TARGET roc::%s AND NOT TARGET hip::%s)\n add_library(hip::%s ALIAS roc::%s)\nendif()\n' \
"${roc_pkg}" "${roc_pkg}" "${roc_pkg}" "${hip_pkg}" "${hip_pkg}" "${roc_pkg}" \
> "${cfg_dir}/${hip_pkg}-config.cmake" && \
echo "${hip_pkg}-config.cmake created (alias to ${roc_pkg})."; \
else \
echo "${hip_pkg}-config.cmake already exists, skipping."; \
fi; \
done && \
# 无 roc 对应物的 hip 包,创建 minimal cmake config(强制覆盖)
for pkg in hipblaslt hiprtc; do \
cfg_dir="/opt/rocm/lib/cmake/${pkg}"; \
mkdir -p "${cfg_dir}" && \
printf 'set(%s_FOUND TRUE)\nset(%s_VERSION "7.2.1")\nif(NOT TARGET hip::%s)\n add_library(hip::%s INTERFACE IMPORTED)\n set_target_properties(hip::%s PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "/opt/rocm/include")\nendif()\nif(NOT TARGET %s::%s)\n add_library(%s::%s ALIAS hip::%s)\nendif()\n' \
"${pkg}" "${pkg}" "${pkg}" "${pkg}" "${pkg}" \
"${pkg}" "${pkg}" "${pkg}" "${pkg}" "${pkg}" \
> "${cfg_dir}/${pkg}-config.cmake" && \
echo "${pkg}-config.cmake created (hip:: + ${pkg}:: aliases)."; \
done && \
# roc::* 别名(PyTorch Caffe2Targets 直接引用 roc:: 命名空间的 hip 包名)
for pair in \
"hipblas:rocblas" "hiprand:rocrand" "hipsolver:rocsolver" \
"hipsparse:rocsparse" "hipfft:rocfft" "hipcub:rocprim"; \
do \
hip_pkg="${pair%%:*}"; roc_pkg="${pair#*:}"; \
cfg_dir="/opt/rocm/lib/cmake/${hip_pkg}"; \
if [ -f "${cfg_dir}/${hip_pkg}-config.cmake" ]; then \
if ! grep -q "roc::${hip_pkg}" "${cfg_dir}/${hip_pkg}-config.cmake" 2>/dev/null; then \
printf 'if(TARGET roc::%s AND NOT TARGET roc::%s)\n add_library(roc::%s ALIAS roc::%s)\nendif()\n' \
"${roc_pkg}" "${hip_pkg}" "${hip_pkg}" "${roc_pkg}" \
>> "${cfg_dir}/${hip_pkg}-config.cmake" && \
echo "roc::${hip_pkg} → roc::${roc_pkg}."; \
fi; \
fi; \
done && \
# hipblaslt / hiprtc:底层是 INTERFACE IMPORTED(非 ALIAS),roc:: 直接指 hip::
for pkg in hipblaslt hiprtc; do \
cfg_dir="/opt/rocm/lib/cmake/${pkg}"; \
if [ -f "${cfg_dir}/${pkg}-config.cmake" ]; then \
if ! grep -q "roc::${pkg}" "${cfg_dir}/${pkg}-config.cmake" 2>/dev/null; then \
printf 'if(TARGET hip::%s AND NOT TARGET roc::%s)\n add_library(roc::%s ALIAS hip::%s)\nendif()\n' \
"${pkg}" "${pkg}" "${pkg}" "${pkg}" \
>> "${cfg_dir}/${pkg}-config.cmake" && \
echo "roc::${pkg} → hip::${pkg}."; \
fi; \
fi; \
done && \
# miopen minimal config(强制覆盖,miopen-hip 可能不带 cmake config)
mkdir -p /opt/rocm/lib/cmake/miopen && \
# 诊断: MIOpen 库实际位置
echo "=== MIOpen diagnostic ===" && \
find /opt -name "libMIOpen*" -o -name "libmiopen*" 2>/dev/null | head -10 && \
# 创建符号链接,确保链接器能找到
for so in $(find /opt -name "libMIOpen.so*" -o -name "libmiopen.so*" 2>/dev/null | head -1); do \
ln -sf "$so" /opt/rocm/lib/libMIOpen.so && \
echo "libMIOpen.so → $so"; \
done && \
ls -la /opt/rocm/lib/libMIOpen* 2>/dev/null || echo "WARNING: libMIOpen.so not found!" && \
printf 'set(miopen_FOUND TRUE)\nset(miopen_VERSION "3.4.0")\nif(NOT TARGET miopen)\n add_library(miopen SHARED IMPORTED)\n set_target_properties(miopen PROPERTIES IMPORTED_LOCATION "/opt/rocm/lib/libMIOpen.so" INTERFACE_INCLUDE_DIRECTORIES "/opt/rocm/include")\nendif()\n' \
> /opt/rocm/lib/cmake/miopen/miopen-config.cmake && \
echo "miopen-config.cmake created (SHARED IMPORTED)." && \
# 兜底:确保 libMIOpen.so 链接可见
ls /opt/rocm/lib/libMIOpen* /opt/rocm-7.2.1/lib/libMIOpen* 2>/dev/null | head -3 && \
if [ ! -f /opt/rocm/lib/libMIOpen.so ] && [ -f /opt/rocm-7.2.1/lib/libMIOpen.so ]; then \
ln -sf /opt/rocm-7.2.1/lib/libMIOpen.so /opt/rocm/lib/libMIOpen.so && \
echo "libMIOpen.so symlinked."; \
fi && \
# amd_comgr minimal config(强制覆盖)
mkdir -p /opt/rocm/lib/cmake/amd_comgr && \
printf 'set(amd_comgr_FOUND TRUE)\nset(amd_comgr_VERSION "2.8.0")\nif(NOT TARGET amd_comgr)\n add_library(amd_comgr INTERFACE IMPORTED)\n set_target_properties(amd_comgr PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "/opt/rocm/include")\nendif()\n' \
> /opt/rocm/lib/cmake/amd_comgr/amd_comgr-config.cmake && \
echo "amd_comgr-config.cmake created (minimal)." && \
# 创建 HIP cmake config(apt 安装的 hip-dev 缺少 find_package 需要的配置)
mkdir -p /opt/rocm/lib/cmake/hip && \
printf 'set(HIP_FOUND TRUE)\nset(HIP_VERSION "7.2.1")\nset(HIP_PLATFORM amd)\nset(HIP_COMPILER /opt/rocm/llvm/bin/clang++)\nset(HIP_RUNTIME rocm)\nset(HIP_INCLUDE_DIRS /opt/rocm/include)\nset(HIP_LIBRARIES /opt/rocm/lib/libamdhip64.so)\nif(NOT TARGET hip::host)\n add_library(hip::host INTERFACE IMPORTED)\n set_target_properties(hip::host PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${HIP_INCLUDE_DIRS}")\nendif()\nif(NOT TARGET hip::device)\n add_library(hip::device INTERFACE IMPORTED)\n set_target_properties(hip::device PROPERTIES INTERFACE_COMPILE_OPTIONS "--offload-arch=${ARCH}")\nendif()\nif(NOT TARGET hip::amdhip64)\n add_library(hip::amdhip64 SHARED IMPORTED)\n set_target_properties(hip::amdhip64 PROPERTIES IMPORTED_LOCATION "/opt/rocm/lib/libamdhip64.so" INTERFACE_INCLUDE_DIRECTORIES "/opt/rocm/include")\nendif()\n' \
> /opt/rocm/lib/cmake/hip/hip-config.cmake && \
# 补丁: ROCm 7.2.1 中 hip_version.h 已移除, 创建兼容头文件供 PyTorch LoadHIP.cmake 使用
if [ ! -f /opt/rocm/include/hip/hip_version.h ]; then \
mkdir -p /opt/rocm/include/hip && \
printf '#pragma once\n#define HIP_VERSION_MAJOR 7\n#define HIP_VERSION_MINOR 2\n#define HIP_VERSION_PATCH 53211\n#define HIP_VERSION_GITDATE 0\n#define HIP_VERSION (HIP_VERSION_MAJOR * 10000000 + HIP_VERSION_MINOR * 100000 + HIP_VERSION_PATCH)\n' \
> /opt/rocm/include/hip/hip_version.h && \
echo "hip_version.h created."; \
fi && \
mkdir -p /opt/vllm_build && \
export HIP_PLATFORM=amd HIP_PATH=/opt/rocm ROCM_PATH=/opt/rocm && \
export http_proxy=${GIT_PROXY} https_proxy=${GIT_PROXY} && \
export LIBRARY_PATH=/opt/rocm/lib:$LIBRARY_PATH && \
cmake -S /opt/vllm -B /opt/vllm_build -G Ninja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DVLLM_TARGET_DEVICE=rocm \
-DVLLM_PYTHON_EXECUTABLE=${VENV}/bin/python \
-DHIP_ROOT_DIR=/opt/rocm \
-DROCM_PATH=/opt/rocm \
-DCMAKE_HIP_ARCHITECTURES=${ARCH} \
-DCMAKE_HIP_COMPILER=/opt/rocm/llvm/bin/clang++ \
-DHIP_COMPILER=/opt/rocm/llvm/bin/clang++ \
-DHIP_PATH=/opt/rocm \
-DHIP_INCLUDE_DIR=/opt/rocm/include \
-DCMAKE_PREFIX_PATH="/opt/rocm;${VENV}/lib/python${PYTHON_VER}/site-packages/torch/share/cmake" \
-DCMAKE_SHARED_LINKER_FLAGS="-L/opt/rocm/lib" \
-DCMAKE_EXE_LINKER_FLAGS="-L/opt/rocm/lib" && \
cd /opt/vllm_build && ninja -j8 && \
cp /opt/vllm_build/*.abi3.so /opt/vllm/vllm/ && \
echo "vllm C++ build complete (layer cached)."
# ===========================================================================
# 阶段 7.5:复制入口 + 辅助脚本
# ===========================================================================
COPY scripts/entrypoint.sh /opt/entrypoint.sh
RUN chmod +x /opt/entrypoint.sh
COPY scripts/cache_warmer.py /opt/scripts/cache_warmer.py
# ===========================================================================
# 阶段 8b:安装 vllm + 平台补丁 + 验证
# ===========================================================================
RUN set -ex && \
export http_proxy=${GIT_PROXY} https_proxy=${GIT_PROXY} && \
# 1) 安装构建工具(后续 pip install 需要)
${VENV}/bin/pip install -U "setuptools>=77.0.3" setuptools_scm setuptools_rust wheel && \
# 2) 手动注册 vllm 为 editable package(阶段 8a 已编译 C++ 扩展,此处不触发 cmake)
cd /opt/vllm && \
mkdir -p vllm.egg-info && \
printf 'Metadata-Version: 2.1\nName: vllm\nVersion: 0.11.0\nSummary: A high-throughput and memory-efficient inference and serving engine for LLMs\n' > vllm.egg-info/PKG-INFO && \
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 && \
# 2b) 写 vllm/_version.py(替代 setuptools_scm 生成),避免 vllm.__version__='dev' 触发
# mineru.backend.vlm.utils:88 中 packaging.version.parse 抛 InvalidVersion
printf '__version__ = "0.11.0"\n__version_tuple__ = (0, 11, 0)\n' > /opt/vllm/vllm/_version.py && \
echo "vllm egg-info created (cmake build skipped, C++ extensions from stage 8a)" && \
# 3) 安装 ROCm PyTorch(后续依赖解析用 ROCm 源补齐 triton-rocm)
(${VENV}/bin/pip uninstall -y triton triton-rocm 2>/dev/null || true) && \
${VENV}/bin/pip install --force-reinstall \
torch==2.11.0+rocm7.2 torchvision pytorch-triton-rocm \
--index-url ${TORCH_INDEX} && \
${VENV}/bin/python -c "import torch; v=torch.__version__; assert 'rocm' in v, f'PyTorch overwritten: {v}'; print('PyTorch OK:', v)" && \
# 4) 安装 vllm 运行时依赖;额外加入 ROCm PyTorch 源,避免传递依赖解析 triton-rocm 失败
grep -vE '^(torch|torchvision|torchaudio|triton|triton-rocm|pytorch-triton|setuptools)' requirements/common.txt > /tmp/vllm_deps.txt && \
${VENV}/bin/pip install -r /tmp/vllm_deps.txt --extra-index-url ${TORCH_INDEX} && \
# 5) 再次确认 PyTorch 仍是 ROCm 版
${VENV}/bin/python -c "import torch; v=torch.__version__; assert 'rocm' in v, f'PyTorch overwritten after vllm deps: {v}'; print('PyTorch still OK:', v)" && \
# 6) 深度验证 vllm(确保 AsyncEngineArgs、AsyncLLM 等关键模块可导入,缺包直接构建失败)
${VENV}/bin/python -c "from vllm.engine.arg_utils import AsyncEngineArgs; from vllm.v1.engine.async_llm import AsyncLLM; print('vllm deep import OK:', __import__('vllm').__version__)" && \
# 7) 确保 mineru-api 子进程不依赖 PYTHONPATH 也能导入 vllm
echo "/opt/vllm" > ${VENV}/lib/python${PYTHON_VER}/site-packages/vllm.pth && \
# 8) 锁定 ROCm 关键包版本(不含 setuptools,避免与 vllm/mineru 依赖冲突)
${VENV}/bin/pip freeze | grep -iE "^(torch|vllm|triton|pytorch.triton|torchvision|flash.attn|aiter)" >> ${VENV}/torch-constraint.txt && \
rm -rf /opt/vllm_build
# ===========================================================================
# 阶段 9:安装 MinerU(constraint 保护 ROCm 环境,正常安装其他依赖)
# ===========================================================================
RUN set -ex && \
export http_proxy=${GIT_PROXY} https_proxy=${GIT_PROXY} && \
${VENV}/bin/pip install 'mineru[core]' click gradio httpx cbor2 && \
${VENV}/bin/python -c "import torch; from vllm.engine.arg_utils import AsyncEngineArgs; import mineru; import click; import gradio; import httpx; import cbor2; print('MinerU + Gradio + vllm deep + httpx + cbor2 imports OK')" && \
${VENV}/bin/mineru-gradio --help >/dev/null
# ===========================================================================
# 阶段 10:入口与最终验证
# ===========================================================================
RUN echo 'source /opt/mineru_venv/bin/activate' >> /etc/bash.bashrc && \
${VENV}/bin/python -c "import torch; from vllm.engine.arg_utils import AsyncEngineArgs; import mineru; import gradio; import mineru.cli.gradio_app; print('MinerU ROCm Docker Image Ready'); print(f'PyTorch {torch.__version__} OK')"
ENTRYPOINT ["/opt/entrypoint.sh"]
CMD ["bash"]