# ============================================================================= # 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 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} && \ cd /opt/vllm && ${VENV}/bin/pip install -e . --no-build-isolation && \ ${VENV}/bin/pip install regex && \ ${VENV}/bin/python -c "import torch; v=torch.__version__; assert 'rocm' in v, f'PyTorch overwritten: {v}'; print('PyTorch OK:', v)" && \ ${VENV}/bin/pip uninstall -y triton triton-rocm 2>/dev/null; \ ${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 vllm; print('vllm import OK:', vllm.__version__)" && \ # 锁定所有 ROCm 关键包版本,防止 mineru 安装时覆盖 ${VENV}/bin/pip freeze | grep -iE "^(torch|vllm|triton|pytorch.triton|setuptools|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 && \ ${VENV}/bin/python -c "import torch; import vllm; import mineru; import click; import gradio; import mineru.cli.gradio_app; print('MinerU + Gradio CLI 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; import vllm; 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"]