From cbe5388e575f706a15e7042be7e6876b17a68ff5 Mon Sep 17 00:00:00 2001 From: chenjw28 <792430652@qq.com> Date: Mon, 15 Jun 2026 10:48:31 +0800 Subject: [PATCH] x --- .idea/MarsCodeWorkspaceAppSettings.xml | 6 ++ docker/Dockerfile | 29 ++---- docker/README.md | 53 ---------- docker/docker-compose.yml | 49 +++------- .../patch_vllm_platform.cpython-312.pyc | Bin 0 -> 9402 bytes docker/scripts/entrypoint.sh | 5 + docker/scripts/patch_vllm_platform.py | 91 ++++++++++++++++-- 7 files changed, 116 insertions(+), 117 deletions(-) create mode 100644 .idea/MarsCodeWorkspaceAppSettings.xml create mode 100644 docker/scripts/__pycache__/patch_vllm_platform.cpython-312.pyc diff --git a/.idea/MarsCodeWorkspaceAppSettings.xml b/.idea/MarsCodeWorkspaceAppSettings.xml new file mode 100644 index 0000000..e2a065b --- /dev/null +++ b/.idea/MarsCodeWorkspaceAppSettings.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile index 4294106..5b0d86e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -11,8 +11,8 @@ ARG PYTHON_VER=3.12 ARG VENV=/opt/mineru_venv ARG TORCH_INDEX=https://download.pytorch.org/whl/rocm7.2 -# -- GitHub 访问(国内无镜像,需代理;默认不走代理)----------------------------- -ARG GIT_PROXY= +# -- GitHub 访问(国内无镜像,需代理)---------------------------------------- +ARG GIT_PROXY=http://127.0.0.1:8118 # -- 国内镜像 ---------------------------------------------------------------- ARG PIP_INDEX=https://mirrors.aliyun.com/pypi/simple @@ -20,7 +20,6 @@ ARG PIP_INDEX=https://mirrors.aliyun.com/pypi/simple # -- 环境变量 --------------------------------------------------------------- ENV DEBIAN_FRONTEND=noninteractive \ PATH=/opt/rocm/bin:/opt/rocm/llvm/bin:${VENV}/bin:${PATH} \ - PYTHONPATH=/opt/vllm:${PYTHONPATH} \ PYTORCH_ROCM_ARCH=${ARCH} \ FLASH_ATTENTION_TRITON_AMD_ENABLE=TRUE \ MINERU_MODEL_SOURCE=huggingface \ @@ -82,25 +81,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ # =========================================================================== # 阶段 4:CMake 4.0(通过代理下载加速) # =========================================================================== -RUN set -ex && \ - CMAKE_TGZ=cmake-4.0.0-linux-x86_64.tar.gz && \ - CMAKE_DIR=cmake-4.0.0-linux-x86_64 && \ - CMAKE_URLS="https://github.com/Kitware/CMake/releases/download/v4.0.0/${CMAKE_TGZ} https://ghproxy.com/https://github.com/Kitware/CMake/releases/download/v4.0.0/${CMAKE_TGZ}" && \ - if [ -n "${GIT_PROXY}" ]; then export http_proxy=${GIT_PROXY} https_proxy=${GIT_PROXY}; fi && \ +RUN export http_proxy=${GIT_PROXY} https_proxy=${GIT_PROXY} && \ cd /tmp && \ - ok=0; \ - for url in ${CMAKE_URLS}; do \ - echo "Downloading CMake from: ${url}"; \ - if curl -fL --retry 5 --retry-delay 3 --connect-timeout 20 -o ${CMAKE_TGZ} "${url}"; then \ - ok=1; \ - break; \ - fi; \ - done; \ - [ "${ok}" = "1" ] || (echo "Failed to download ${CMAKE_TGZ} from all mirrors" && exit 4) && \ - tar -xzf ${CMAKE_TGZ} && \ - cp -r ${CMAKE_DIR}/bin/* /usr/local/bin/ && \ - cp -r ${CMAKE_DIR}/share/* /usr/local/share/ && \ - rm -rf ${CMAKE_TGZ} ${CMAKE_DIR} && \ + 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 # =========================================================================== diff --git a/docker/README.md b/docker/README.md index cd4b629..c1013f1 100644 --- a/docker/README.md +++ b/docker/README.md @@ -163,7 +163,6 @@ cp env.example .env # 方式一:docker build(直接指定 ARCH) docker build \ --build-arg ARCH=gfx1201 \ - --build-arg GIT_PROXY= \ -t mineru-rocm:7.2.1 \ -f Dockerfile . @@ -187,7 +186,6 @@ docker compose build | `PYTHON_VER` | `3.12` | Python 版本 | | `VENV` | `/opt/mineru_venv` | 虚拟环境路径 | | `TORCH_INDEX` | `https://download.pytorch.org/whl/rocm7.2` | PyTorch wheel 源 | -| `GIT_PROXY` | 空 | 仅构建时访问 GitHub 用;例如 `http://host.docker.internal:8118` | --- @@ -408,61 +406,10 @@ docker compose build --no-cache gradio docker compose up -d --force-recreate ``` -**Q: 任务失败并提示 `Please install vllm to use the vllm-async-engine backend`** - -这通常不是简单的“没安装 vllm”,而是任务进程里 `import vllm` 或 `from vllm.platforms import current_platform` 失败,MinerU 将真实异常包装成了这句提示。先在容器内直接诊断: - -```bash -docker compose exec gradio bash -lc '/opt/mineru_venv/bin/python - <<"PY" -import traceback -try: - import torch - import vllm - from vllm.platforms import current_platform - print("torch:", torch.__version__, "hip:", torch.version.hip) - print("vllm:", vllm.__version__) - print("platform:", type(current_platform).__name__, "is_rocm:", current_platform.is_rocm()) -except Exception: - traceback.print_exc() - raise -PY' -``` - -当前入口脚本会在服务启动前执行同样的 vLLM 导入验证;如果验证失败,容器会直接退出并在 `docker compose logs gradio` 中显示真实 traceback,而不是等任务执行时才报泛化错误。 - -如果日志明确显示 `ModuleNotFoundError: No module named 'vllm'`,常见原因是 vLLM 分发元数据不可见,但 `/opt/vllm` 源码仍在。当前镜像已通过 `PYTHONPATH=/opt/vllm` 和入口脚本兜底保证可导入,避免 editable 安装触发 `pyproject.toml` 元数据校验失败。 - -```bash -export PYTHONPATH=/opt/vllm:${PYTHONPATH} -/opt/mineru_venv/bin/python -c "import vllm; print(vllm.__version__)" -``` - -入口脚本也会在启动时自动尝试这个修复。你也可以在旧容器里手动验证/修复一次: - -```bash -docker compose exec gradio bash -lc 'export PYTHONPATH=/opt/vllm:${PYTHONPATH}; /opt/mineru_venv/bin/python -c "import vllm; print(vllm.__version__)"' -docker compose restart gradio -``` - **Q: 构建时 `ninja` 被 kill(exit 137)** 内存不足。将 Dockerfile 中 `ninja -j4` 改为 `ninja -j2` 或 `ninja -j1`,或给 Docker 分配更多内存。 -**Q: 构建在 CMake 下载阶段失败(`wget/curl exit code 4`)** - -这通常是构建容器无法访问 GitHub,或把 `GIT_PROXY` 设成了容器内不可达地址(例如 `127.0.0.1:8118` 在多数 Docker 场景下指向容器自己,不是宿主机代理)。建议: - -1. 不需要代理时,显式传空:`--build-arg GIT_PROXY=` -2. 需要宿主机代理时,优先用:`http://host.docker.internal:8118` -3. 先单独测试下载连通性,再完整构建 - -```bash -docker build --build-arg GIT_PROXY= -t mineru-rocm:7.2.1 -f Dockerfile . - -# 或(宿主机代理) -docker build --build-arg GIT_PROXY=http://host.docker.internal:8118 -t mineru-rocm:7.2.1 -f Dockerfile . -``` - **Q: 构建时 cmake 报 `Failed to find ROCm root directory`** `/opt/rocm/bin` 不在 PATH 中。检查 Dockerfile 中 `ENV PATH` 是否正确设置。 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 65f5bfb..f0df181 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -7,30 +7,15 @@ services: # --- WebUI 前端 --- gradio: image: mineru-rocm:7.2.1 - build: - context: . - dockerfile: Dockerfile - network: host - args: - ARCH: ${ARCH:-gfx1201} - GIT_PROXY: ${GIT_PROXY:-} + profiles: ["gradio"] container_name: mineru-gradio stdin_open: true tty: true ipc: host - restart: on-failure:3 - devices: - - /dev/kfd - - /dev/dri - security_opt: - - seccomp=unconfined - group_add: - - video ports: - "10002:7860" environment: - GRADIO_SERVER_NAME=0.0.0.0 - - HIP_VISIBLE_DEVICES=${HIP_VISIBLE_DEVICES:-0} - MINERU_MODEL_SOURCE=${MINERU_MODEL_SOURCE:-huggingface} - HF_HUB_CACHE=${HF_HUB_CACHE:-/opt/models/huggingface} - MODELSCOPE_CACHE=${MODELSCOPE_CACHE:-/opt/models/modelscope} @@ -38,32 +23,31 @@ services: - ${INPUT_DIR:-./data/input}:/data/input:ro - ${OUTPUT_DIR:-./data/output}:/data/output - ${MODEL_DIR:-./data/models}:/opt/models - - ${MIOPEN_CACHE:-./data/miopen}:/root/.cache/miopen - ./scripts:/opt/scripts:ro command: [ "mineru-gradio", "--server-name", "0.0.0.0", "--server-port", "7860", + "--api-url", "http://mineru-router:8000", ] - healthcheck: - test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:7860/ >/dev/null || exit 1"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 60s + depends_on: + - router - # --- 可选:多 Worker API Router 模式(默认不启动)--- - # 启用方式:docker compose --profile router-api up -d - # 单卡默认请使用上面的 gradio 服务;双卡时可在 .env 中设置 ROUTER_API_URLS。 + # --- 双卡 Worker(GPU 算力,无 profile,始终可用)--- worker0: image: mineru-rocm:7.2.1 - profiles: ["router-api"] + build: + context: . + dockerfile: Dockerfile + network: host + args: + ARCH: ${ARCH:-gfx1201} + GIT_PROXY: ${GIT_PROXY:-} container_name: mineru-worker0 stdin_open: true tty: true ipc: host - restart: on-failure:3 devices: - /dev/kfd - /dev/dri @@ -73,6 +57,7 @@ services: - video environment: - HIP_VISIBLE_DEVICES=0 + - PYTHONPATH=/opt/vllm:${PYTHONPATH:-} - MINERU_MODEL_SOURCE=${MINERU_MODEL_SOURCE:-huggingface} - HF_HUB_CACHE=${HF_HUB_CACHE:-/opt/models/huggingface} - MODELSCOPE_CACHE=${MODELSCOPE_CACHE:-/opt/models/modelscope} @@ -86,12 +71,10 @@ services: worker1: image: mineru-rocm:7.2.1 - profiles: ["dual-gpu"] container_name: mineru-worker1 stdin_open: true tty: true ipc: host - restart: on-failure:3 devices: - /dev/kfd - /dev/dri @@ -101,6 +84,7 @@ services: - video environment: - HIP_VISIBLE_DEVICES=1 + - PYTHONPATH=/opt/vllm:${PYTHONPATH:-} - MINERU_MODEL_SOURCE=${MINERU_MODEL_SOURCE:-huggingface} - HF_HUB_CACHE=${HF_HUB_CACHE:-/opt/models/huggingface} - MODELSCOPE_CACHE=${MODELSCOPE_CACHE:-/opt/models/modelscope} @@ -114,12 +98,10 @@ services: router: image: mineru-rocm:7.2.1 - profiles: ["router-api"] container_name: mineru-router stdin_open: true tty: true ipc: host - restart: on-failure:3 ports: - "8000:8000" environment: @@ -132,10 +114,11 @@ services: [ "mineru-router", "--api-urls", - "${ROUTER_API_URLS:-http://mineru-worker0:8001}", + "http://mineru-worker0:8001,http://mineru-worker1:8002", "--host", "0.0.0.0", "--port", "8000", "--allow-public-http-client", ] depends_on: - worker0 + - worker1 diff --git a/docker/scripts/__pycache__/patch_vllm_platform.cpython-312.pyc b/docker/scripts/__pycache__/patch_vllm_platform.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a21b074b4862e17af01a1a3ed80b8350693757d GIT binary patch literal 9402 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 literal 0 HcmV?d00001 diff --git a/docker/scripts/entrypoint.sh b/docker/scripts/entrypoint.sh index 275efe1..58a42a1 100644 --- a/docker/scripts/entrypoint.sh +++ b/docker/scripts/entrypoint.sh @@ -19,5 +19,10 @@ if [ -f ${SCRIPTS_DIR}/apply_mineru_patches.py ]; then ${VENV}/bin/python ${SCRIPTS_DIR}/apply_mineru_patches.py || echo "[entrypoint] apply_mineru_patches.py failed (non-fatal)" fi +# 确保 vllm 源码目录在 PYTHONPATH 中 +# patch_vllm_platform.py 中的 os.environ 修改不持久化到父进程 +# 这里无条件导出,防止 editable install 被破坏后 vllm 无法导入 +export PYTHONPATH="/opt/vllm:${PYTHONPATH}" + echo "[entrypoint] starting: $*" exec "$@" diff --git a/docker/scripts/patch_vllm_platform.py b/docker/scripts/patch_vllm_platform.py index adc8c8c..788a232 100644 --- a/docker/scripts/patch_vllm_platform.py +++ b/docker/scripts/patch_vllm_platform.py @@ -6,7 +6,9 @@ """ import os +import re import sys +import sysconfig import traceback VLLM_DIR = '/opt/vllm/vllm' @@ -38,26 +40,88 @@ def patch6_init_platform_fallback(): def patch7_rocm_break_import_cycle(): """补丁 7:platforms/rocm.py —— logger.warning_once → sys.stderr.write - 这个补丁会直接改写 vLLM 源码中的函数调用。部分 vLLM 版本里 - logger.warning_once(...) 参数不一定兼容 sys.stderr.write(...),改写后可能 - 导致 import vllm / import vllm.platforms.rocm 失败。MinerU 会把这种导入失败 - 包装成 "Please install vllm",因此默认禁用,只在显式设置环境变量时启用。 + 默认启用安全的“整段 except 块”替换,避免 logger.warning_once() 在平台检测 + 期间触发循环导入,导致 current_platform 落到 UnspecifiedPlatform。 + 如需禁用,设置 VLLM_PATCH_ROCM_WARNING_ONCE=0。 """ - if os.environ.get('VLLM_PATCH_ROCM_WARNING_ONCE') != '1': - print('Patch 7: skipped (set VLLM_PATCH_ROCM_WARNING_ONCE=1 to enable).') + if os.environ.get('VLLM_PATCH_ROCM_WARNING_ONCE') == '0': + print('Patch 7: skipped (VLLM_PATCH_ROCM_WARNING_ONCE=0).') return f = os.path.join(VLLM_DIR, 'platforms', 'rocm.py') c = open(f).read() - old = 'logger.warning_once(' - new = 'import sys as _sys\n _sys.stderr.write(' - c2 = c.replace(old, new) + if 'amdsmi unavailable, using torch.cuda fallback' in c: + print('Patch 7: already applied.') + return + pattern = re.compile( + r'(\n\s*except Exception as e:\n' + r'\s*logger\.debug\("Failed to get GCN arch via amdsmi: %s", e\)\n' + r'\s*logger\.warning_once\(\n' + r'(?:\s*"[^"]*"\n)+' + r'\s*\)\n)', + re.MULTILINE, + ) + + def repl(match): + indent = re.search(r'\n(\s*)except Exception as e:', match.group(1)).group(1) + body_indent = indent + ' ' + return ( + f'\n{indent}except Exception as e:\n' + f'{body_indent}import sys as _sys\n' + f'{body_indent}_sys.stderr.write(' + '"vLLM ROCm: amdsmi unavailable, using torch.cuda fallback for GPU detection\\n")\n' + ) + + c2, n = pattern.subn(repl, c, count=1) if c2 != c: open(f, 'w').write(c2) - print('Patch 7: rocm.py circular import broken.') + print('Patch 7: rocm.py logger.warning_once circular import patch applied.') else: print('Patch 7: already applied or pattern not found.') +def ensure_vllm_dist_info(): + """为 /opt/vllm 源码导入创建最小 dist-info。 + + vLLM 平台检测会通过 importlib.metadata 查询 vllm 分发元数据/entry points。 + 如果只靠 PYTHONPATH 导入源码,没有 dist-info,就会出现: + "The vLLM package was not found...",并可能得到 UnspecifiedPlatform。 + """ + try: + import vllm + except Exception: + return + + version = getattr(vllm, '__version__', '0.1.dev1') or '0.1.dev1' + site_packages = sysconfig.get_paths().get('purelib') + if not site_packages: + return + dist_info = os.path.join(site_packages, f'vllm-{version}.dist-info') + os.makedirs(dist_info, exist_ok=True) + + metadata = os.path.join(dist_info, 'METADATA') + if not os.path.exists(metadata): + with open(metadata, 'w') as fp: + fp.write( + 'Metadata-Version: 2.1\n' + 'Name: vllm\n' + f'Version: {version}\n' + 'Summary: vLLM source tree mounted at /opt/vllm\n' + ) + + with open(os.path.join(dist_info, 'top_level.txt'), 'w') as fp: + fp.write('vllm\n') + with open(os.path.join(dist_info, 'INSTALLER'), 'w') as fp: + fp.write('mineru-rocm-runtime\n') + with open(os.path.join(dist_info, 'entry_points.txt'), 'w') as fp: + fp.write( + '[vllm.platform_plugins]\n' + 'rocm = vllm.platforms.rocm:rocm_platform_plugin\n' + ) + with open(os.path.join(dist_info, 'RECORD'), 'w') as fp: + fp.write('') + print(f'vllm dist-info ensured: {dist_info}') + + def ensure_vllm_installed(): """确保 vLLM Python 包在当前虚拟环境中可导入。 @@ -94,9 +158,16 @@ def main(): patch7_rocm_break_import_cycle() try: ensure_vllm_installed() + ensure_vllm_dist_info() import vllm from vllm.platforms import current_platform print(f'vllm runtime import OK: {vllm.__version__}, platform={type(current_platform).__name__}') + if type(current_platform).__name__ == 'UnspecifiedPlatform': + raise RuntimeError( + 'vLLM platform detection returned UnspecifiedPlatform; ' + 'ROCm backend is not usable. Check amdsmi, /dev/kfd, /dev/dri, ' + 'and vllm.platform_plugins metadata.' + ) except Exception: print('ERROR: vllm runtime import failed after platform patches:') traceback.print_exc()