Chapter 10

CI/CD 与 Docker 部署

把 uv 的速度优势放大 10 倍——从 GitHub Actions 到生产 Docker 的完整方案

GitHub Actions 基础模板

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v3
        with:
          version: "latest"       # 或固定版本 "0.5.0"
          enable-cache: true      # 启用依赖缓存

      - name: Set up Python
        run: uv python install 3.13

      - name: Sync dependencies
        run: uv sync --locked --all-groups

      - name: Lint
        run: uv run ruff check .

      - name: Type check
        run: uv run mypy src

      - name: Test
        run: uv run pytest --cov=src
setup-uv@v3 的好处

① 缓存 ~/.cache/uv(全局 wheel 缓存),二次运行下载几乎为 0。② 以 uv.lock 哈希作为缓存 key,依赖变更时自动失效。③ 自动把 ~/.local/bin 加入 PATH。官方维护,比自己写 cache action 可靠得多。

矩阵测试

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        python: ["3.11", "3.12", "3.13"]
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v3
        with:
          enable-cache: true
      - run: uv python install ${{ matrix.python }}
      - run: uv sync --locked --python ${{ matrix.python }}
      - run: uv run pytest

uv 官方 Docker 镜像

Astral 提供了好几种 Docker 镜像,选择看需求:

镜像大小用途
ghcr.io/astral-sh/uv:latest~25MB只含 uv 二进制,当工具用
ghcr.io/astral-sh/uv:python3.13-bookworm-slim~50MBuv + 精简 Debian + 预装 Python
ghcr.io/astral-sh/uv:python3.13-alpine~40MB基于 Alpine,最小
ghcr.io/astral-sh/uv:debian-slim~45MBuv + Debian,自己装 Python

单阶段 Dockerfile(简单场景)

FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim

WORKDIR /app

# 复制依赖声明先
COPY pyproject.toml uv.lock ./

# 同步依赖(不装自身代码)
RUN uv sync --frozen --no-dev --no-install-project

# 再复制应用代码
COPY . .

# 最后装自身(editable,改代码不用重装依赖)
RUN uv sync --frozen --no-dev

# 运行
ENV PATH="/app/.venv/bin:$PATH"
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0"]
分层构建的关键

COPY pyproject.toml uv.lockCOPY .,利用 Docker 层缓存——只要依赖没变,代码改动不会触发重装依赖。这一个技巧能把构建时间从几十秒压到几秒。

多阶段构建(生产推荐)

# ---------- Build stage ----------
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS builder

WORKDIR /app
ENV UV_COMPILE_BYTECODE=1 \
    UV_LINK_MODE=copy \
    UV_PYTHON_DOWNLOADS=never

COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --frozen --no-dev --no-install-project

COPY . .
RUN uv sync --frozen --no-dev

# ---------- Runtime stage ----------
FROM python:3.13-slim-bookworm

WORKDIR /app
COPY --from=builder /app/.venv /app/.venv
COPY --from=builder /app /app

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

USER 1000:1000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0"]

关键环境变量:

更极致的瘦身:distroless

FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS builder
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev --no-install-project
COPY . .
RUN uv sync --frozen --no-dev

# Google distroless:只有 Python 运行时,没有 shell
FROM gcr.io/distroless/python3-debian12
COPY --from=builder /app /app
WORKDIR /app
ENV PATH="/app/.venv/bin:$PATH"
ENTRYPOINT ["/app/.venv/bin/python", "-m", "app"]

distroless 镜像没有 bashapt,不能 docker exec -it 调试,但攻击面小 10 倍,生产安全推荐。

uv export 兼容老工作流

如果你的 CI/部署系统只认 requirements.txt(比如某些云的 Python 运行时),可导出:

uv export --format requirements-txt --no-dev > requirements.txt
uv export --format requirements-txt --all-extras > requirements-full.txt
uv export --format pylock.toml > pylock.toml   # PEP 751 新格式

从 pip + requirements.txt 迁移

# 1. 初始化项目
cd existing-project
uv init --package .

# 2. 导入 requirements.txt 为依赖
uv add -r requirements.txt

# 3. 如果有 requirements-dev.txt
uv add --dev -r requirements-dev.txt

# 4. 删除老文件
rm requirements.txt requirements-dev.txt
rm -rf venv/  # 旧虚拟环境

# 5. 跑一遍 sync 验证
uv sync
uv run pytest

从 Poetry 迁移

# uv 不原生读取 poetry 配置,但 pyproject.toml 的 [project] 是标准的
# Poetry 的配置在 [tool.poetry],需要手动迁移

# 1. 把 [tool.poetry].dependencies 改写为 [project].dependencies
# 2. 把 [tool.poetry.dev-dependencies] 改为 [dependency-groups].dev
# 3. 删除 poetry.lock
rm poetry.lock
# 4. 生成新 lock
uv lock
uv sync

社区工具 migrate-to-uvuvx migrate-to-uv)可一键迁移 Poetry/PDM/Pipenv/Hatch 项目。

迁移对照表

原命令uv 等价
pip install pkguv add pkg
pip install -r requirements.txtuv sync
pip install -e .自动完成(uv sync)
pip listuv tree --depth 1uv pip list
pip freezeuv export --format requirements-txt
python -m venv .venvuv venv
source .venv/bin/activate + python x.pyuv run python x.py
pipx install blackuv tool install black
pipx run cowsayuvx cowsay
pyenv install 3.13uv python install 3.13
poetry add pkguv add pkg
poetry installuv sync
poetry run xuv run x
poetry builduv build
poetry publishuv publish

GitLab CI / Jenkins 模板

# .gitlab-ci.yml
image: ghcr.io/astral-sh/uv:python3.13-bookworm-slim

variables:
  UV_CACHE_DIR: ".uv-cache"

cache:
  key:
    files:
      - uv.lock
  paths:
    - .uv-cache/

test:
  script:
    - uv sync --locked
    - uv run pytest

监控 uv 自身版本

# 建议固定 uv 版本,避免自动升级引入不兼容
# setup-uv 里
- uses: astral-sh/setup-uv@v3
  with:
    version: "0.5.0"    # 精确到小版本
全书总结

十章走完,uv 的全部能力已覆盖:① 安装与对比 ② pyproject.toml 标准 ③ 依赖管理循环 ④ 锁文件原理 ⑤ Python 多版本 ⑥ uv run 免激活 ⑦ 全局工具 ⑧ Monorepo 工作区 ⑨ PyTorch 多索引 ⑩ CI/CD 部署。今天就把手头的项目从 pip/poetry 迁到 uv,节省下来的时间会让你惊讶。