官方使用
FastAPI 官方 Dockerfile 中用了兩次:
RUN --mount=type=cache,target=/root/.cache/uv \--mount=type=bind,source=uv.lock,target=uv.lock \--mount=type=bind,source=pyproject.toml,target=pyproject.toml \uv sync --frozen --no-install-project # ? 第一次RUN --mount=type=cache,target=/root/.cache/uv \uv sync # ? 第二次
這是 uv 官方推薦的優化構建流程,目的是 最大程度復用緩存,加快構建速度,同時支持源碼變化重裝依賴。
🔍 第一次 uv sync --frozen --no-install-project
📌 作用是:
? ? 只安裝依賴(不安裝你項目代碼)
? ? 使用 lock 文件精確控制版本
? ? 構建中間層緩存(intermediate layer)
?? 只要你沒改 pyproject.toml 或 uv.lock,這一層永遠不需要重建!
這是 Docker 構建中非常重要的一環 —— 利用文件不變來緩存 layer,加快構建速度。
🔄 第二次 uv sync
📌 作用是:
? ? 安裝你項目的源碼(也就是 app/ 本身)
? 因為第一次用了 --no-install-project,項目代碼沒有裝進去
🚨 如果你更新了項目源碼,但沒改 pyproject.toml,就只會觸發第二次構建。
你可以類比為:
# 第一次,只安裝依賴,不裝項目代碼
pip install --no-deps --require-hashes -r requirements.txt# 第二次,把你的項目當成 package 裝進環境里
pip install .
# 是 Python 項目中非常重要的一步,表示 將你當前目錄(.)下的項目當作一個 Package 安裝到當前 Python 環境中。
這樣你每次寫代碼改的是 .py 文件而不是依賴,Docker 就不會重新構建冗余層 ?
第一次 uv sync --frozen --no-install-project | 第二次 uv sync |
---|---|
安裝依賴項(構建緩存層) | 安裝項目本身 |
不會安裝你 app/ 源碼 | 會裝源碼到虛擬環境 |
對應 lock 文件(更可控) | 快速重建項目層 |
有利于構建性能 | 有利于熱更新和本地測試 |
可以,但你就會失去 中間層緩存優化的好處,每次改 .py 都會重新裝全部依賴 ?
? 為什么 FastAPI 官方不寫 COPY?
因為他們使用的是 BuildKit 的多階段構建 + bind mount 優化方案:
? 第一次 RUN uv sync --frozen --no-install-project 使用掛載的 pyproject.toml 和 uv.lock 安裝依賴(但不安裝項目)
? 最終會在后面階段,再使用 COPY . . 把項目代碼拷貝進來
步驟 | 是否合理 | 說明 |
---|---|---|
設置基礎鏡像 | ? | python:3.12-slim 節省體積 |
使用 uv 構建 | ? | 快速高效、現代依賴工具 |
緩存依賴安裝層 | ? | 加速構建、復用緩存 |
分階段 COPY + uv sync | ? | 減少變更觸發重裝 |
PYTHONPATH=. | ? | 適配 from app.xxx 導入 |
CMD 使用 uvicorn | ? | 適合線上部署、ASGI 原生 |
開箱即用的Dockfile
FROM python:3.12-slim AS builderWORKDIR /app# 設置時區為 UTC+8
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezoneCOPY --from=ghcr.io/astral-sh/uv:0.5.11 /uv /uvx /bin/ENV PATH="/app/.venv/bin:$PATH"
ENV UV_COMPILE_BYTECODE=1
ENV UV_LINK_MODE=copy# 復制項目文件到容器中
COPY . /app/RUN --mount=type=cache,target=/root/.cache/uv \--mount=type=bind,source=uv.lock,target=uv.lock \--mount=type=bind,source=pyproject.toml,target=pyproject.toml \uv sync --frozen --no-install-projectENV PYTHONPATH=.CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--log-level", "warning"]