FastAPI 部署实战:使用 uv + Docker 构建含 PyTorch (CUDA) 的极简镜像


本文总阅读量

fastapi-uv-docker-optimization.png


最近一段时间把 FastAPI 项目的依赖管理全换成了 uv,不得不说,一旦习惯了这种秒级响应,就再也回不去 pip 了。

分享一套我目前在用的 Docker 构建方案,主要解决两个痛点:PyTorch 的 CUDA 版本依赖,以及怎么压榨镜像体积和构建时间。

搞定 PyTorch 的 CUDA 版本

uv 快归快,但处理 PyTorch 这种不在 PyPI 默认源里的库时,逻辑和 pip 还是有点出入。

如果你只是临时用命令行装个包,体验倒是差不多:

uv pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126

但在项目配置里(pyproject.toml),你得显式地告诉 uv 去哪找这些特定版本的包,可以参考如下配置:

[[tool.uv.index]]
name = "pytorch-cu126"
url = "https://download.pytorch.org/whl/cu126"
explicit = true

[tool.uv.sources]
torch = [
  { index = "pytorch-cu126", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
]
torchvision = [
  { index = "pytorch-cu126", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
]

Docker 构建方案

在 Docker 里用 uv,核心就两点:多阶段构建剥离环境,配合 Cache Mount 加速。

这是我现在用的 Dockerfile

# === 第一阶段:构建环境 ===
FROM python:3.12-slim-bookworm AS builder

# 直接拷贝 uv 二进制文件,不依赖系统 pip,更干净
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv

# 启用预编译和强制复制,禁用自动下载 python
ENV UV_COMPILE_BYTECODE=1 \
    UV_LINK_MODE=copy \
    UV_PYTHON_DOWNLOADS=never

WORKDIR /app

# 先拷贝锁文件,利用缓存机制
COPY pyproject.toml uv.lock ./

# 核心步骤:只安装依赖,不安装项目本身
# --mount=type=cache 挂载缓存目录,进一步加速
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --frozen --no-install-project --no-dev

# 最后再拷贝代码并安装项目
COPY . .
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --frozen --no-dev

# === 第二阶段:运行环境 ===
FROM python:3.12-slim-bookworm AS runner

# 生产环境标准操作:非 root 用户
RUN groupadd -r app && useradd -r -d /app -g app app
WORKDIR /app

# 只拷贝构建好的虚拟环境,体积最小化
COPY --from=builder --chown=app:app /app/.venv /app/.venv
COPY --from=builder --chown=app:app /app/src /app/src

ENV PATH="/app/.venv/bin:$PATH"
USER app

CMD ["gunicorn", "src.app.main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000"]

顺带一提:配合 docker-compose,你可以直接复用 builder 阶段作为开发环境,而 runner 阶段作为最终上线产物,环境一致性问题也顺手解决了。


本站总访问量