# Real Worker Dockerfile — 自帶 prebuild toolchain,可實際把 BIE→NEF 真實轉檔 # # 與 Dockerfile.stub 的差異:本 image 內含 ktc/ 真實轉檔素材 + toolchain/prebuild # 的 x86-64 編譯 binaries(batch_compile / kneron_nef_utils / model_converter), # 並設好 USE_PREBUILD/LD_LIBRARY_PATH/PYTHONPATH,讓 import ktc + ktc.compile 走 # repo 自帶 prebuild 路徑(不抓系統 libs/compiler、libs/dynasty)。 # # Build(從專案根目錄、本機 Docker daemon): # docker build -f services/workers/Dockerfile.real -t kneron-worker-real:verify . # # 注意:build context 含 toolchain/prebuild (~2GB)。搭配「專案根 .dockerignore」 # (docker build 以專案根為 context,只讀 context 根目錄的 .dockerignore;不存在 # services/workers/.dockerignore)排除 libs/dynasty + libs/compiler(被 USE_PREBUILD # 取代,省 ~3.2GB)。 # python:3.9 對齊既有 worker;bullseye(Debian 11, glibc 2.31) 對舊 toolchain # (prebuild ELF 最低需求 GNU/Linux 3.2.0)相容性最佳。 FROM python:3.9-slim-bullseye WORKDIR /app # --- System libraries --------------------------------------------------------- # opencv-python runtime: libgl1 / libglib2.0-0 # OpenMP / OpenBLAS(compiler binary 會用): libgomp1 # gfortran runtime(prebuild/lib 雖自帶 libgfortran.so.5,仍裝保險): libgfortran5 # 其餘缺的 .so 靠 image 內 `ldd toolchain/prebuild/batch_compile` 的 "not found" 補。 RUN apt-get update && apt-get install -y --no-install-recommends \ libgl1 \ libglib2.0-0 \ libgomp1 \ libgfortran5 \ ca-certificates \ procps \ file \ && rm -rf /var/lib/apt/lists/* # --- Python dependencies ------------------------------------------------------ # 1) queue / storage(consumer.py 需要) # 2) worker 既有 requirements(fastapi/onnx/opencv…) # 3) ktc → sys_flow / sys_flow_v2 + extract_bie_info + kneronnxopt module-load 額外 # 需要(全部由本機實跑 `import ktc` 逐個盤出): # pandas blinker docopt snoop pyzipper dict_recursive_update beautifulsoup4 # jinja2 matplotlib tabulate commentjson IPython adjustText onnx_tool onnxsim # # 特別注意的版本鎖: # - onnx==1.14.1:與 root requirements 一致;ktc/toolchain.py 對 onnx==1.7.0 會 # 關閉 730 支援,必須避開 1.7.0。 # - onnx_tool==0.7.0:未鎖時裝到的新版在 import 期會踩 # "unsupported operand type(s) for |: MessageMeta and type"(protobuf 衝突); # 0.7.0 import 乾淨。 # - onnxsim==0.4.36(--only-binary):py3.9/bullseye 上新版 onnxsim 無 wheel、需 # cmake 從源碼編;0.4.36 有 prebuilt wheel,避免裝 build toolchain。 # 4) tflite 輸入格式轉檔(tflite→onnx,第一步 ktc.onnx_optimizer.tflite2onnx_flow) # 需要 tensorflow + python-igraph(converter: libs/ONNX_Convertor/tflite-onnx): # - tensorflow-cpu==2.13.1:挑此版的三重理由—— # (a) Python 3.9 相容:2.13.x 支援 py3.8–3.11;再新的 TF(2.16+)drop py3.9。 # (b) numpy<2 相容(最關鍵):TF 2.13.1 要求 numpy>=1.22,<=1.24.3(全 1.x), # 與既有 prebuild 鏈的「numpy 1.x」硬需求一致;再新的 TF(2.16+)會拉 # numpy>=2 → 直接撞爆 prebuild 的 "numpy.core.multiarray failed to import"。 # (c) ktc 需求:ktc/onnx_optimizer_1_13.py 的 _get_tensor_details_compat patch # 是為「較新 TF(tf.lite.Interpreter._get_tensor_details 需 subgraph_index, # TF 2.5+ 引入)」寫的 → TF 2.13.1 落在此範圍、patch 正常生效。 # 選 -cpu 版:不需 GPU、省下 CUDA 相關 ~1.5GB。 # - igraph==1.0.0:converter 的 tree_structure.py:13 `from igraph import Graph` 硬 # import 需要(不裝→tflite→onnx 第一步 ModuleNotFoundError)。pin 死是為了 # reproducible build——igraph 是 tflite 鏈的硬依賴、裸裝 latest 未來重 build 可能 # 裝到行為改變的新版;1.0.0 是本次 build 實裝並驗證可跑的版本。 # - typing-extensions>=4.8.0:TF 2.13.1 會把 typing-extensions 降到 4.5.0 # (其 pin 是 <4.6),導致 fastapi 0.104.1 `import fastapi` 掛 # `cannot import name 'TypeAliasType'`。TF 對 typing-extensions 的上限只是 # *soft warning*(實測升到 4.15 後 tf 2.13.1 + tf.lite.Interpreter 仍正常), # 故在 TF 之後把 typing-extensions 補回 >=4.8.0,修復 fastapi/pydantic。 # 5) numpy==1.23.5 最後裝並「釘死」:prebuild 鏈的 C-extension 以 numpy 1.x 編譯, # numpy 2.x 會出 "numpy.core.multiarray failed to import"。1.23.5 同時滿足 # TF 2.13.1 的 numpy>=1.22,<=1.24.3 窗口 + 既有 prebuild/onnx 的 1.x 需求。 # 最後安裝確保不被 TF/其他套件連帶升級。 COPY services/workers/nef/requirements.txt /tmp/worker-requirements.txt RUN pip install --no-cache-dir \ redis>=5.0 boto3>=1.28 \ && pip install --no-cache-dir -r /tmp/worker-requirements.txt \ && pip install --no-cache-dir \ "onnx==1.14.1" \ scipy \ pandas blinker docopt snoop \ pyzipper dict_recursive_update beautifulsoup4 jinja2 matplotlib tabulate \ commentjson IPython adjustText "onnx_tool==0.7.0" \ && pip install --no-cache-dir --only-binary :all: "onnxsim==0.4.36" \ && pip install --no-cache-dir "tensorflow-cpu==2.13.1" "igraph==1.0.0" \ && pip install --no-cache-dir "typing-extensions>=4.8.0" \ && pip install --no-cache-dir "numpy==1.23.5" # --- Application + toolchain source ------------------------------------------ # 精準 COPY,避免把 libs/dynasty(2.0G) + libs/compiler(1.2G) 帶進來。 COPY ktc/ /app/ktc/ COPY vendor/ /app/vendor/ COPY services/ /app/services/ COPY toolchain/prebuild/ /app/toolchain/prebuild/ COPY libs/kneronnxopt/ /app/libs/kneronnxopt/ COPY libs/ONNX_Convertor/ /app/libs/ONNX_Convertor/ COPY libs/fpAnalyser/ /app/libs/fpAnalyser/ COPY E2E_Simulator/python_flow/ /app/E2E_Simulator/python_flow/ # 驗證用 fixtures + conftest(production 部署可拿掉,這裡為了在 image 內端到端跑) COPY tests/ /app/tests/ RUN mkdir -p /data/jobs # --- Toolchain / runtime environment(即 tests/conftest.py 的 production 化版本)--- ENV USE_PREBUILD=/app/toolchain/prebuild ENV LD_LIBRARY_PATH=/app/toolchain/prebuild/lib ENV PYTHONPATH=/app:/app/vendor:/app/libs:/app/libs/kneronnxopt:/app/E2E_Simulator/python_flow ENV KTC_DISABLE_MP=1 # --- Worker runtime config ---------------------------------------------------- ENV WORKER_MODE=real ENV REDIS_URL=redis://redis:6379 ENV JOB_DATA_DIR=/data/jobs # STORAGE_BACKEND 刻意「不」在此 image 設預設值。 # # 為什麼:consumer.py 第 52 行 `os.environ.get("STORAGE_BACKEND", "local")` 本身 # 已會 fall back 到 local。若這支真實版 image 又寫死 ENV STORAGE_BACKEND=local,會給 # 部署者「image 預設就能上雲」的錯覺;一旦 staging compose 漏設 STORAGE_BACKEND=minio, # worker 會 *安靜* 走 local(產出寫 container 本機磁碟、不上 MinIO)→ 轉檔成功但 # visionA poll 拿不到結果(即 commit b8457dd / cbd1b9d 修過的同類隱患)。 # # 處理姿態: # - 本 image 不設預設 → 由 compose / 部署環境「顯式」提供。 # - staging(用 MinIO)必設 `STORAGE_BACKEND=minio`(見部署 checklist 硬性項)。 # - 本機 / dev 不設時,consumer.py 仍 fall back local,stub/local 開發流程不受影響。 # - 註:要根除 silent fallback 的最穩做法是在 consumer.py 對 WORKER_MODE=real 做 # fail-fast(漏設 minio 即報錯),但那屬 application code、需 backend 處理, # 不在本 Dockerfile 範圍。 # STAGE: onnx / bie / nef(三個 worker 共用此 image,差在 entrypoint) ENV STAGE=nef # 用 shell form 以便 ${STAGE} 變數展開(三個 worker 共用 image、差在此變數)。 CMD ["sh", "-c", "python -m services.workers.${STAGE}.worker"]