跳到内容

在 Docker 中使用 uv

快速入门

提示

查看 uv-docker-example 项目,了解在使用 uv 在 Docker 中构建应用程序时的最佳实践示例。

uv 提供了 distroless Docker 镜像,可用于将 uv 二进制文件复制到您自己的镜像构建中,以及从流行的基础镜像派生的镜像,可用于在容器中使用 uv。distroless 镜像除了 uv 二进制文件外不包含任何内容。相比之下,派生的镜像包含预装 uv 的操作系统。

例如,要在基于 Debian 的镜像中使用 uv 运行容器

$ docker run --rm -it ghcr.io/astral-sh/uv:debian uv --help

可用的镜像

以下 distroless 镜像可用

  • ghcr.io/astral-sh/uv:latest
  • ghcr.io/astral-sh/uv:{major}.{minor}.{patch}, 例如,ghcr.io/astral-sh/uv:0.8.0
  • ghcr.io/astral-sh/uv:{major}.{minor}, 例如,ghcr.io/astral-sh/uv:0.8 (最新的补丁版本)

以下派生的镜像可用

  • 基于 alpine:3.21
    • ghcr.io/astral-sh/uv:alpine
    • ghcr.io/astral-sh/uv:alpine3.21
  • 基于 debian:bookworm-slim
    • ghcr.io/astral-sh/uv:debian-slim
    • ghcr.io/astral-sh/uv:bookworm-slim
  • 基于 buildpack-deps:bookworm
    • ghcr.io/astral-sh/uv:debian
    • ghcr.io/astral-sh/uv:bookworm
  • 基于 python3.x-alpine
    • ghcr.io/astral-sh/uv:python3.14-rc-alpine
    • ghcr.io/astral-sh/uv:python3.13-alpine
    • ghcr.io/astral-sh/uv:python3.12-alpine
    • ghcr.io/astral-sh/uv:python3.11-alpine
    • ghcr.io/astral-sh/uv:python3.10-alpine
    • ghcr.io/astral-sh/uv:python3.9-alpine
    • ghcr.io/astral-sh/uv:python3.8-alpine
  • 基于 python3.x-bookworm
    • ghcr.io/astral-sh/uv:python3.14-rc-bookworm
    • ghcr.io/astral-sh/uv:python3.13-bookworm
    • ghcr.io/astral-sh/uv:python3.12-bookworm
    • ghcr.io/astral-sh/uv:python3.11-bookworm
    • ghcr.io/astral-sh/uv:python3.10-bookworm
    • ghcr.io/astral-sh/uv:python3.9-bookworm
    • ghcr.io/astral-sh/uv:python3.8-bookworm
  • 基于 python3.x-slim-bookworm
    • ghcr.io/astral-sh/uv:python3.14-rc-bookworm-slim
    • ghcr.io/astral-sh/uv:python3.13-bookworm-slim
    • ghcr.io/astral-sh/uv:python3.12-bookworm-slim
    • ghcr.io/astral-sh/uv:python3.11-bookworm-slim
    • ghcr.io/astral-sh/uv:python3.10-bookworm-slim
    • ghcr.io/astral-sh/uv:python3.9-bookworm-slim
    • ghcr.io/astral-sh/uv:python3.8-bookworm-slim

与 distroless 镜像一样,每个派生的镜像都以 uv 版本标签发布为 ghcr.io/astral-sh/uv:{major}.{minor}.{patch}-{base}ghcr.io/astral-sh/uv:{major}.{minor}-{base},例如,ghcr.io/astral-sh/uv:0.8.0-alpine

此外,从 0.8 开始,每个派生的镜像还将 UV_TOOL_BIN_DIR 设置为 /usr/local/bin,以允许 uv tool install 与默认用户一起按预期工作。

有关更多详细信息,请参阅 GitHub Container 页面。

安装 uv

使用上面其中一个预装 uv 的镜像,或者通过从官方 distroless Docker 镜像复制二进制文件来安装 uv

Dockerfile
FROM python:3.12-slim-bookworm
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

或者,使用安装程序

Dockerfile
FROM python:3.12-slim-bookworm

# The installer requires curl (and certificates) to download the release archive
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates

# Download the latest installer
ADD https://astral.ac.cn/uv/install.sh /uv-installer.sh

# Run the installer then remove it
RUN sh /uv-installer.sh && rm /uv-installer.sh

# Ensure the installed binary is on the `PATH`
ENV PATH="/root/.local/bin/:$PATH"

请注意,这需要 curl 可用。

无论哪种情况,最佳实践是固定到特定的 uv 版本,例如,使用

COPY --from=ghcr.io/astral-sh/uv:0.8.0 /uv /uvx /bin/

提示

虽然上面的 Dockerfile 示例固定到特定的标签,但也可以固定特定的 SHA256。在需要可重现构建的环境中,固定特定的 SHA256 被认为是最佳实践,因为标签可以在不同的提交 SHA 之间移动。

# e.g., using a hash from a previous release
COPY --from=ghcr.io/astral-sh/uv@sha256:2381d6aa60c326b71fd40023f921a0a3b8f91b14d5db6b90402e65a635053709 /uv /uvx /bin/

或者,使用安装程序

ADD https://astral.ac.cn/uv/0.8.0/install.sh /uv-installer.sh

安装项目

如果您使用 uv 来管理您的项目,您可以将其复制到镜像中并安装它

Dockerfile
# Copy the project into the image
ADD . /app

# Sync the project into a new environment, asserting the lockfile is up to date
WORKDIR /app
RUN uv sync --locked

重要

最佳实践是将 .venv 添加到存储库中的 .dockerignore 文件中,以防止其包含在镜像构建中。项目虚拟环境依赖于您的本地平台,应该在镜像中从头开始创建。

然后,默认启动您的应用程序

Dockerfile
# Presuming there is a `my_app` command provided by the project
CMD ["uv", "run", "my_app"]

提示

最佳实践是使用中间层,将依赖项的安装与项目本身分开,以缩短 Docker 镜像构建时间。

请参阅 uv-docker-example 项目中的完整示例。

使用环境

安装项目后,您可以通过将其二进制文件目录放在路径的前面来激活项目虚拟环境

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

或者,您可以将 uv run 用于任何需要环境的命令

Dockerfile
RUN uv run some_script.py

提示

或者,可以在同步之前设置UV_PROJECT_ENVIRONMENT 设置,以安装到系统 Python 环境并完全跳过环境激活。

使用已安装的工具

要使用已安装的工具,请确保工具 bin 目录位于路径上

Dockerfile
ENV PATH=/root/.local/bin:$PATH
RUN uv tool install cowsay
$ docker run -it $(docker build -q .) /bin/bash -c "cowsay -t hello"
  _____
| hello |
  =====
     \
      \
        ^__^
        (oo)\_______
        (__)\       )\/\
            ||----w |
            ||     ||

注意

工具 bin 目录的位置可以通过在容器中运行 uv tool dir --bin 命令来确定。

或者,可以将其设置为常量位置

Dockerfile
ENV UV_TOOL_BIN_DIR=/opt/uv-bin/

在 ARM musl 镜像中安装 Python

虽然 uv 会尝试安装兼容的 Python 版本如果镜像中没有此类版本可用,但 uv 尚不支持在 ARM 上为 musl Linux 安装 Python。例如,如果您在 ARM 机器上使用 Alpine Linux 基础镜像,您可能需要使用系统包管理器添加它

apk add --no-cache python3~=3.12

在容器中开发

在开发时,将项目目录挂载到容器中很有用。使用此设置,项目中的更改可以立即反映在容器化服务中,而无需重建镜像。但是,重要的是不要在挂载中包含项目虚拟环境 (.venv),因为虚拟环境是特定于平台的,应该保留为镜像构建的虚拟环境。

使用 docker run 挂载项目

将项目(在工作目录中)绑定挂载到 /app,同时使用匿名卷保留 .venv 目录

$ docker run --rm --volume .:/app --volume /app/.venv [...]

提示

包含 --rm 标志是为了确保在容器退出时清理容器和匿名卷。

请参阅 uv-docker-example 项目中的完整示例。

使用 docker compose 配置 watch

使用 Docker compose 时,可以使用更复杂的工具进行容器开发。watch 选项允许比绑定挂载更细粒度,并且支持在文件更改时触发对容器化服务的更新。

注意

此功能需要 Compose 2.22.0,它与 Docker Desktop 4.24 打包在一起。

在您的Docker compose 文件中配置 watch,以挂载项目目录而不同步项目虚拟环境,并在配置更改时重建镜像

compose.yaml
services:
  example:
    build: .

    # ...

    develop:
      # Create a `watch` configuration to update the app
      #
      watch:
        # Sync the working directory with the `/app` directory in the container
        - action: sync
          path: .
          target: /app
          # Exclude the project virtual environment
          ignore:
            - .venv/

        # Rebuild the image on changes to the `pyproject.toml`
        - action: rebuild
          path: ./pyproject.toml

然后,运行 docker compose watch 以使用开发设置运行容器。

请参阅 uv-docker-example 项目中的完整示例。

优化

编译字节码

将 Python 源文件编译为字节码通常对于生产镜像来说是理想的,因为它往往会缩短启动时间(以增加安装时间为代价)。

要启用字节码编译,请使用 --compile-bytecode 标志

Dockerfile
RUN uv sync --compile-bytecode

或者,您可以设置 UV_COMPILE_BYTECODE 环境变量,以确保 Dockerfile 中的所有命令都编译字节码

Dockerfile
ENV UV_COMPILE_BYTECODE=1

缓存

可以使用 缓存挂载来提高跨构建的性能

Dockerfile
ENV UV_LINK_MODE=copy

RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync

更改默认的UV_LINK_MODE会消除有关无法使用硬链接的警告,因为缓存和同步目标位于单独的文件系统上。

如果您不挂载缓存,则可以使用 --no-cache 标志或设置 UV_NO_CACHE 来减小镜像大小。

注意

缓存目录的位置可以通过在容器中运行 uv cache dir 命令来确定。

或者,可以将缓存设置为常量位置

Dockerfile
ENV UV_CACHE_DIR=/opt/uv-cache/

中间层

如果您使用 uv 来管理您的项目,您可以通过 --no-install 选项将您的传递依赖项安装移动到其自己的层中来缩短构建时间。

uv sync --no-install-project 将安装项目的依赖项,但不安装项目本身。由于项目经常更改,但其依赖项通常是静态的,因此这可以节省大量时间。

Dockerfile
# Install uv
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# Change the working directory to the `app` directory
WORKDIR /app

# Install dependencies
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 --locked --no-install-project

# Copy the project into the image
ADD . /app

# Sync the project
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --locked

请注意,需要 pyproject.toml 来标识项目根目录和名称,但在最终的 uv sync 命令之前,项目内容不会复制到镜像中。

提示

如果您使用的是工作区,则使用 --no-install-workspace 标志,该标志会排除项目任何工作区成员。

如果您想从同步中删除特定的包,请使用 --no-install-package <name>

非可编辑安装

默认情况下,uv 以可编辑模式安装项目和工作区成员,这样对源代码的更改会立即反映在环境中。

uv syncuv run 都接受 --no-editable 标志,该标志指示 uv 以非可编辑模式安装项目,从而消除对源代码的任何依赖。

在多阶段 Docker 镜像的上下文中,可以使用 --no-editable 将项目包含在来自一个阶段的已同步虚拟环境中,然后仅将虚拟环境(而不是源代码)复制到最终镜像中。

例如

Dockerfile
# Install uv
FROM python:3.12-slim AS builder
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# Change the working directory to the `app` directory
WORKDIR /app

# Install dependencies
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 --locked --no-install-project --no-editable

# Copy the project into the intermediate image
ADD . /app

# Sync the project
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --locked --no-editable

FROM python:3.12-slim

# Copy the environment, but not the source code
COPY --from=builder --chown=app:app /app/.venv /app/.venv

# Run the application
CMD ["/app/.venv/bin/hello"]

临时使用 uv

如果最终镜像中不需要 uv,则可以在每次调用中挂载二进制文件

Dockerfile
RUN --mount=from=ghcr.io/astral-sh/uv,source=/uv,target=/bin/uv \
    uv sync

使用 pip 接口

安装包

系统 Python 环境可以安全地用于此上下文,因为容器已经隔离。可以使用 --system 标志安装在系统环境中

Dockerfile
RUN uv pip install --system ruff

要默认使用系统 Python 环境,请设置 UV_SYSTEM_PYTHON 变量

Dockerfile
ENV UV_SYSTEM_PYTHON=1

或者,可以创建和激活虚拟环境

Dockerfile
RUN uv venv /opt/venv
# Use the virtual environment automatically
ENV VIRTUAL_ENV=/opt/venv
# Place entry points in the environment at the front of the path
ENV PATH="/opt/venv/bin:$PATH"

使用虚拟环境时,应从 uv 调用中省略 --system 标志

Dockerfile
RUN uv pip install ruff

安装 requirements

要安装 requirements 文件,请将其复制到容器中

Dockerfile
COPY requirements.txt .
RUN uv pip install -r requirements.txt

安装项目

在 requirements 文件旁边安装项目时,最佳实践是将复制 requirements 与源代码的其余部分分开。这允许项目的依赖项(不经常更改)与项目本身(经常更改)分开缓存。

Dockerfile
COPY pyproject.toml .
RUN uv pip install -r pyproject.toml
COPY . .
RUN uv pip install -e .

验证镜像来源

Docker 镜像在构建过程中进行签名,以提供其来源的证明。这些证明可用于验证镜像是否来自官方渠道。

例如,您可以使用 GitHub CLI 工具 gh 验证证明

$ gh attestation verify --owner astral-sh oci://ghcr.io/astral-sh/uv:latest
Loaded digest sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx for oci://ghcr.io/astral-sh/uv:latest
Loaded 1 attestation from GitHub API

The following policy criteria will be enforced:
- OIDC Issuer must match:................... https://token.actions.githubusercontent.com
- Source Repository Owner URI must match:... https://github.com/astral-sh
- Predicate type must match:................ https://slsa.dev/provenance/v1
- Subject Alternative Name must match regex: (?i)^https://github.com/astral-sh/

✓ Verification succeeded!

sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx was attested by:
REPO          PREDICATE_TYPE                  WORKFLOW
astral-sh/uv  https://slsa.dev/provenance/v1  .github/workflows/build-docker.yml@refs/heads/main

这告诉您特定的 Docker 镜像是由官方 uv GitHub 发布工作流程构建的,并且自那时以来没有被篡改。

GitHub 证明基于 sigstore.dev 基础设施构建。因此,您还可以使用 cosign 命令针对 uv 的(多平台)清单验证证明 blob

$ REPO=astral-sh/uv
$ gh attestation download --repo $REPO oci://ghcr.io/${REPO}:latest
Wrote attestations to file sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.jsonl.
Any previous content has been overwritten

The trusted metadata is now available at sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.jsonl
$ docker buildx imagetools inspect ghcr.io/${REPO}:latest --format "{{json .Manifest}}" > manifest.json
$ cosign verify-blob-attestation \
    --new-bundle-format \
    --bundle "$(jq -r .digest manifest.json).jsonl"  \
    --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
    --certificate-identity-regexp="^https://github\.com/${REPO}/.*" \
    <(jq -j '.|del(.digest,.size)' manifest.json)
Verified OK

提示

这些示例使用 latest,但最佳实践是验证特定版本标签的证明,例如 ghcr.io/astral-sh/uv:0.8.0,或者(更好的是)特定镜像摘要,例如 ghcr.io/astral-sh/uv:0.5.27@sha256:5adf09a5a526f380237408032a9308000d14d5947eafa687ad6c6a2476787b4f