FastAPI 部署实战:使用 uv + Docker 构建含 PyTorch (CUDA) 的极简镜像
本文总阅读量次

最近一段时间把 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 阶段作为最终上线产物,环境一致性问题也顺手解决了。