fix: 優化 Dockerfile 中模型下載與快取清理邏輯,減少層差異與空間使用

This commit is contained in:
Your Name 2026-01-22 19:20:56 +08:00
parent 11dc51890c
commit 37b56aed56

View file

@ -233,18 +233,27 @@ RUN apt-get update --fix-missing && apt-get install -y --no-install-recommends \
# 階段 12安裝 Python 工具pipx+ huggingface_hub用於模型下載
# 注意Debian bookworm 使用 PEP 668需要 --break-system-packages 來安裝系統級套件
# 注意markitdown[all] 可能依賴 transformers 或其他 HuggingFace 套件,需清理 cache
RUN pipx install "markitdown[all]" \
&& pip3 install --no-cache-dir --break-system-packages huggingface_hub
&& pip3 install --no-cache-dir --break-system-packages huggingface_hub \
&& rm -rf /root/.cache/huggingface /root/.cache/pip /tmp/*
# 階段 12-A安裝 pdf2zhPDFMathTranslate 引擎)
RUN pipx install "pdf2zh"
# 注意pipx install 可能觸發依賴套件的隱式下載,結尾必須清理 cache
RUN pipx install "pdf2zh" \
&& rm -rf /root/.cache/huggingface /root/.cache/pip /tmp/*
# 階段 12-B安裝 babeldocBabelDOC 引擎)
# BabelDOC 是一個 PDF 翻譯工具,與 pdf2zh 類似但使用不同的翻譯方式
RUN pipx install "babeldoc" || echo "⚠️ babeldoc 安裝失敗,跳過..."
# 注意babeldoc 依賴 transformers安裝時可能觸發模型 cache
RUN (pipx install "babeldoc" || echo "⚠️ babeldoc 安裝失敗,跳過...") \
&& rm -rf /root/.cache/huggingface /root/.cache/pip /tmp/*
# 階段 13安裝 mineru可能在 arm64 上有問題,加入錯誤處理)
RUN pipx install "mineru[all]" || echo "⚠️ mineru 安裝失敗(可能是 arm64 相容性問題),跳過..."
# 🔴 關鍵mineru[all] 依賴大量 HuggingFace 套件,安裝過程可能觸發模型下載
# 必須在同一 RUN 內清理 cache否則會在 layer diff 中產生數 GB 的重複資料
RUN (pipx install "mineru[all]" || echo "⚠️ mineru 安裝失敗(可能是 arm64 相容性問題),跳過...") \
&& rm -rf /root/.cache/huggingface /root/.cache/pip /root/.cache/torch /tmp/*
# 最終清理(延後到模型下載完成後)
@ -273,76 +282,97 @@ ENV PATH="/root/.local/bin:${PATH}"
# - SLANet / UNet表格辨識
#
# ==============================================================================
# 🔧 BuildKit 優化說明:
# ==============================================================================
# 解決 "no space left on device" 的核心策略:
#
# 1. 【單一 RUN 原則】
# 所有模型下載 + cache 清理必須在同一個 RUN 中完成
# 這樣 BuildKit 在計算 layer diff 時,只會看到「最終狀態」
# 而不是「下載的 blob cache + 複製的模型」兩份資料
#
# 2. 【HuggingFace cache 必須刪除】
# snapshot_download 會在 ~/.cache/huggingface/hub 下建立:
# - blobs/:實際的模型檔案(用 SHA256 命名)
# - snapshots/:指向 blobs 的 symlink 或複製
# 當 local_dir_use_symlinks=False 時,檔案會被「複製」到目標目錄
# 如果不刪除 cache同一份模型會以兩份大小進入 layer diff
#
# 3. 【避免 overlayfs 重複壓縮】
# exporting layers 時BuildKit 會:
# - 計算每層的 diff新增/修改的檔案)
# - 壓縮 diff 並寫入 /var/lib/buildkit/runc-overlayfs/
# 如果 cache 沒刪diff 會包含 cache + 目標目錄,壓縮時空間翻倍
#
# ==============================================================================
# ------------------------------------------------------------------------------
# 階段 14-APDFMathTranslate 模型預下載
# 階段 14-UNIFIED所有模型下載 + 快取清理(單一 RUN 避免 layer 爆炸)
# ------------------------------------------------------------------------------
# 模型DocLayout-YOLO ONNX
# 來源HuggingFace - wybxc/DocLayout-YOLO-DocStructBench-onnx
# 用途PDF 頁面佈局分析(識別文字區塊、公式、圖表等)
# 注意:使用 snapshot_download + allow_patterns 避免硬編碼檔名
# 這樣即使上游改檔名(只要是 .onnx也不會 build 失敗
# 🔑 關鍵:這個 RUN 必須包含所有下載操作,並在結尾清理所有 cache
# 這樣 overlayfs 的 diff 只包含「最終需要的模型檔案」
# 而不是「cache 結構 + 模型副本」
# ------------------------------------------------------------------------------
RUN mkdir -p /models/pdfmathtranslate && \
echo "📥 [1/6] 下載 DocLayout-YOLO ONNX 模型..." && \
python3 -c "from huggingface_hub import snapshot_download; \
RUN set -eux && \
echo "===========================================================" && \
echo "🚀 開始統一模型下載(單一 RUN 優化 BuildKit layer" && \
echo "===========================================================" && \
\
# ========================================
# [1/5] PDFMathTranslate DocLayout-YOLO ONNX 模型
# ========================================
echo "" && \
echo "📥 [1/5] 下載 DocLayout-YOLO ONNX 模型..." && \
mkdir -p /models/pdfmathtranslate && \
python3 -c " \
from huggingface_hub import snapshot_download; \
snapshot_download( \
repo_id='wybxc/DocLayout-YOLO-DocStructBench-onnx', \
local_dir='/models/pdfmathtranslate', \
allow_patterns=['*.onnx'], \
local_dir_use_symlinks=False \
)" && \
echo "✅ DocLayout-YOLO ONNX 模型下載完成" && \
echo "📋 下載的模型檔案:" && \
ls -lh /models/pdfmathtranslate/*.onnx 2>/dev/null || ls -lh /models/pdfmathtranslate/
# ------------------------------------------------------------------------------
# 階段 14-BBabelDOC Warmup預載入所有資源
# ------------------------------------------------------------------------------
# 說明babeldoc --warmup 會下載所有必要的字型和模型資源
# 這確保 BabelDOC 執行時不會有任何隱式下載
# 注意:分開執行以避免記憶體壓力
# ------------------------------------------------------------------------------
RUN echo "📥 [2/6] 執行 BabelDOC warmup..." && \
echo "✅ DocLayout-YOLO ONNX 下載完成" && \
ls -lh /models/pdfmathtranslate/*.onnx 2>/dev/null || ls -lh /models/pdfmathtranslate/ && \
\
# 🔥 立即清理 HuggingFace cache關鍵避免 blob 重複)
rm -rf /root/.cache/huggingface && \
\
# ========================================
# [2/5] BabelDOC Warmup
# ========================================
echo "" && \
echo "📥 [2/5] 執行 BabelDOC warmup..." && \
if command -v babeldoc >/dev/null 2>&1; then \
babeldoc --warmup 2>&1 || echo "⚠️ BabelDOC warmup 失敗或無需 warmup"; \
else \
echo "⚠️ babeldoc 命令不存在,跳過 warmup"; \
fi && \
echo "✅ BabelDOC warmup 步驟完成"
# ------------------------------------------------------------------------------
# 階段 14-CPDFMathTranslate 字型下載
# ------------------------------------------------------------------------------
# 下載多語言字型,用於翻譯後的 PDF 渲染
# ------------------------------------------------------------------------------
RUN mkdir -p /app && \
echo "📥 [3/6] 下載 PDFMathTranslate 多語言字型..." && \
curl -L -o /app/GoNotoKurrent-Regular.ttf \
echo "✅ BabelDOC warmup 步驟完成" && \
\
# ========================================
# [3/5] PDFMathTranslate 多語言字型
# ========================================
echo "" && \
echo "📥 [3/5] 下載 PDFMathTranslate 多語言字型..." && \
mkdir -p /app && \
curl -fSL -o /app/GoNotoKurrent-Regular.ttf \
"https://github.com/satbyy/go-noto-universal/releases/download/v7.0/GoNotoKurrent-Regular.ttf" && \
curl -L -o /app/SourceHanSerifCN-Regular.ttf \
curl -fSL -o /app/SourceHanSerifCN-Regular.ttf \
"https://github.com/timelic/source-han-serif/releases/download/main/SourceHanSerifCN-Regular.ttf" && \
curl -L -o /app/SourceHanSerifTW-Regular.ttf \
curl -fSL -o /app/SourceHanSerifTW-Regular.ttf \
"https://github.com/timelic/source-han-serif/releases/download/main/SourceHanSerifTW-Regular.ttf" && \
curl -L -o /app/SourceHanSerifJP-Regular.ttf \
curl -fSL -o /app/SourceHanSerifJP-Regular.ttf \
"https://github.com/timelic/source-han-serif/releases/download/main/SourceHanSerifJP-Regular.ttf" && \
curl -L -o /app/SourceHanSerifKR-Regular.ttf \
curl -fSL -o /app/SourceHanSerifKR-Regular.ttf \
"https://github.com/timelic/source-han-serif/releases/download/main/SourceHanSerifKR-Regular.ttf" && \
echo "✅ 字型下載完成"
# ------------------------------------------------------------------------------
# 階段 14-DMinerU 模型預下載Pipeline 模式)
# ------------------------------------------------------------------------------
# 來源HuggingFace - opendatalab/PDF-Extract-Kit-1.0
# 包含模型:
# - DocLayout-YOLO佈局分析
# - YOLOv8 MFD公式偵測
# - UniMERNet公式辨識
# - PaddleOCROCR
# - LayoutReader閱讀順序
# - SLANet表格辨識
# ------------------------------------------------------------------------------
RUN echo "📥 [4/6] 下載 MinerU Pipeline 模型..." && \
echo "✅ 字型下載完成" && \
\
# ========================================
# [4/5] MinerU Pipeline 模型
# ========================================
echo "" && \
echo "📥 [4/5] 下載 MinerU Pipeline 模型..." && \
ARCH=$(uname -m) && \
if [ "$ARCH" = "aarch64" ]; then \
echo "⚠️ ARM64 架構MinerU 可能不完全支援,嘗試下載模型..."; \
@ -355,14 +385,16 @@ RUN echo "📥 [4/6] 下載 MinerU Pipeline 模型..." && \
else \
echo "mineru-models-download 不可用,跳過 MinerU 模型下載"; \
fi && \
echo "✅ MinerU 模型下載步驟完成"
# ------------------------------------------------------------------------------
# 階段 14-E驗證/補充 MinerU 設定檔
# ------------------------------------------------------------------------------
# mineru-models-download 會自動生成 mineru.json這裡只做驗證和補充
# ------------------------------------------------------------------------------
RUN echo "📥 [5/6] 驗證 MinerU 設定檔..." && \
echo "✅ MinerU 模型下載步驟完成" && \
\
# 🔥 再次清理 HuggingFace cacheMinerU 也會產生)
rm -rf /root/.cache/huggingface && \
\
# ========================================
# [5/5] 驗證 + mineru.json 補充
# ========================================
echo "" && \
echo "📥 [5/5] 驗證 MinerU 設定檔..." && \
mkdir -p /root && \
if [ -f /root/mineru.json ]; then \
echo "✅ mineru.json 已由 mineru-models-download 生成"; \
@ -371,15 +403,33 @@ RUN echo "📥 [5/6] 驗證 MinerU 設定檔..." && \
echo "⚠️ mineru.json 不存在,建立預設設定..."; \
echo '{"models-dir":{"pipeline":"","vlm":""},"model-source":"huggingface","latex-delimiter-config":{"display":{"left":"$$","right":"$$"},"inline":{"left":"$","right":"$"}}}' > /root/mineru.json; \
fi && \
echo "✅ MinerU 設定檔驗證完成"
# ------------------------------------------------------------------------------
# 階段 14-F模型驗證與快取清理
# ------------------------------------------------------------------------------
RUN echo "📥 [6/6] 驗證模型並清理快取..." && \
echo "" && \
echo "📋 模型檔案驗證:" && \
echo "========================================" && \
\
# ========================================
# 🔥 最終 Cache 清理(關鍵!避免 overlayfs diff 爆炸)
# ========================================
echo "===========================================================" && \
echo "🧹 清理所有下載快取(降低 layer diff 大小)" && \
echo "===========================================================" && \
# HuggingFace Hub cache最大宗包含所有 blob
rm -rf /root/.cache/huggingface && \
# pip / Python build cache
rm -rf /root/.cache/pip && \
rm -rf /root/.cache/uv && \
# pipx cache
rm -rf /root/.local/pipx/.cache && \
# 通用 cache 目錄
rm -rf /tmp/* && \
rm -rf /var/tmp/* && \
# Python bytecode cache可選節省少量空間
find /root/.local -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true && \
find /usr -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true && \
\
echo "" && \
echo "===========================================================" && \
echo "📋 模型檔案驗證" && \
echo "===========================================================" && \
echo "" && \
echo "🔹 PDFMathTranslate 模型:" && \
ONNX_COUNT=$(find /models/pdfmathtranslate -name "*.onnx" 2>/dev/null | wc -l) && \
if [ "$ONNX_COUNT" -gt 0 ]; then \
@ -407,16 +457,24 @@ RUN echo "📥 [6/6] 驗證模型並清理快取..." && \
echo " ✅ MinerU Pipeline 模型目錄存在: $MINERU_PIPELINE_DIR"; \
du -sh "$MINERU_PIPELINE_DIR" 2>/dev/null || true; \
else \
echo " ⚠️ MinerU Pipeline 模型目錄不存在或未設定(將在 runtime 下載)"; \
echo " ⚠️ MinerU Pipeline 模型目錄不存在或未設定"; \
echo " 設定路徑: ${MINERU_PIPELINE_DIR:-'(未設定)'}"; \
fi; \
else \
echo " ⚠️ mineru.json 不存在MinerU 未正確安裝)"; \
fi && \
echo "========================================" && \
# 清理 pip 快取(保留模型)
rm -rf /root/.cache/pip && \
echo "✅ 模型驗證完成"
echo "" && \
echo "🔹 確認 HuggingFace cache 已清除:" && \
if [ -d "/root/.cache/huggingface" ]; then \
echo " ❌ 警告HuggingFace cache 仍存在!"; \
du -sh /root/.cache/huggingface 2>/dev/null || true; \
else \
echo " ✅ HuggingFace cache 已清除"; \
fi && \
echo "" && \
echo "===========================================================" && \
echo "✅ 模型下載完成,所有快取已清理" && \
echo "==========================================================="
# PDFMathTranslate 環境變數
ENV PDFMATHTRANSLATE_MODELS_PATH="/models/pdfmathtranslate"