# 使用 Docker 镜像

每个 Job 都在 Docker 镜像中运行，该镜像提供了其软件环境，包括系统工具和已安装的库。使用 `hf jobs run` 时，您需要提供一个镜像和一条命令。使用 `hf jobs uv run` 时，uv 会为脚本准备 Python 环境，除非您指定了镜像，否则 Jobs 会选择默认镜像。

## 选择运行工作负载的方式

当您的 Python 脚本的依赖项可以通过 uv 安装时，请从 `hf jobs uv run` 开始，如 [快速入门](./jobs-quickstart) 中所示。当您需要额外的系统工具或希望使用预配置的软件环境时，请选择一个镜像。

| 所需条件                                                           | 起点                           |
| ----------------------------------------------------------------------- | ---------------------------------------- |
| 使用其声明的依赖项运行 Python 脚本                      | `hf jobs uv run script.py`               |
| 使用镜像中已安装的工具或 Python 包              | `hf jobs run IMAGE COMMAND`              |
| 使用 uv 管理的依赖项和额外的系统工具运行脚本 | `hf jobs uv run --image IMAGE script.py` |

默认镜像包含 Python 和 uv。有关当前默认镜像和可用选项，请参阅 [UV Jobs 配置](./jobs-configuration#uv-jobs)。

您可以使用来自 Docker Hub 等注册表的现有镜像，或者[使用 Docker Space 构建并托管您自己的镜像](#build-your-own-image-with-a-docker-space)。

## 使用现成的图像

使用 `hf jobs run` 并指定镜像以及在镜像内运行的命令。可以使用来自 Docker Hub 或其他注册表的任何公共镜像，包括特定标签。从一个较小的镜像开始：

```bash
hf jobs run ubuntu echo 'Hello from the cloud!'
```

Job 会拉取镜像、运行命令并退出。若要使用镜像中已提供的软件，请选择包含该软件的镜像。例如，使用 PyTorch 镜像在 GPU 上创建张量并将其值翻倍：

```bash
hf jobs run --flavor t4-small --timeout 5m \
    pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel \
    -- python -c 'import torch; x = torch.ones(3, device="cuda"); print(x * 2)'
```

该镜像提供了 PyTorch 及其 CUDA 软件栈。`--flavor t4-small` 用于选择 GPU，`--timeout 5m` 限制 Job 的运行时间，而 Python 命令则使用镜像中已安装的 PyTorch 包。其输出内容会显示在 Job 的日志中。

> [!TIP]
> `--` 用于将 Jobs 选项与命令及其参数分隔开。例如，位于该分隔符之后的 `--help` 会被传递给你的命令。请参阅 [传递参数](./jobs-configuration#passing-arguments)。

### 使用输入和输出文件运行你自己的脚本

通过 `hf jobs run` 运行的脚本必须在 Job 内部可用。您可以使用镜像中包含的脚本，或者 [挂载本地目录](./jobs-configuration#local-directories)。

例如，假设您有一个推理脚本，它使用 `huggingface/trl` 镜像中的 Transformers 和 PyTorch 包。您的本地 `work` 目录包含 `inference.py` 和 `inputs.jsonl`，并且该脚本接受 `--input` 和 `--output` 路径。在创建用于存放结果的 [Storage Bucket](./storage-buckets) 后，使用以下命令运行它：

```bash
hf jobs run --flavor t4-small --timeout 10m \
    -v ./work:/work \
    -v hf://buckets/YOUR_USERNAME/results:/output \
    huggingface/trl \
    -- python /work/inference.py --input /work/inputs.jsonl --output /output/results.jsonl
```

将 `YOUR_USERNAME` 替换为存储桶所有者的命名空间。CLI 会上传本地目录并将其挂载到 `/work`。您的脚本将从该位置读取输入，并将结果写入挂载在 `/output` 的存储桶中，这些结果在 Job 结束后仍可供访问。请根据您的脚本调整命令的参数、硬件和超时设置；有关其他输入和输出选项，请参阅 [Volumes](./jobs-configuration#volumes)。

## 使用 uv 中的镜像

当您的脚本需要默认镜像之外的系统工具，同时希望保留 uv 的 Python 依赖工作流时，请使用 `hf jobs uv run --image`。所选镜像必须已安装 `uv`。

环境由三个部分组成：

- 镜像中的**系统工具和库**（例如 `ffmpeg` 或 CUDA 工具包）会根据镜像的配置供 Job 使用。
- 安装在镜像中的 **Python 包** 属于其现有的 Python 环境。
- **脚本依赖项。** 使用 [内联依赖项头](https://docs.astral.sh/uv/guides/scripts/#declaring-script-dependencies) 时，uv 会在隔离的环境中安装您的 Python 包。镜像中预装的包不会自动可用。

例如，vLLM 脚本可能需要一个包含 CUDA 工具链的镜像，同时使用 uv 来安装其自身声明的 Python 依赖项。系统工具链仍必须与 uv 安装的包保持兼容。

如果你想直接使用镜像中预装的 PyTorch、TRL 或 vLLM，请使用 `hf jobs run`。如果你还需要使用 uv 来安装额外的依赖项，请参阅 [复用镜像中的包并使用 uv 添加依赖项](#reuse-the-images-packages-and-add-dependencies-with-uv)。

## 使用 Docker Space 构建你自己的镜像

Docker Space 可以构建并托管包含工作负载所需工具（包括您自己的脚本）的镜像，并且无需注册表账户即可将镜像设为私有。例如，您可以在 Python 镜像中添加 FFmpeg，以准备用于处理音频或视频的环境。

创建一个 [Docker Space](./spaces-sdks-docker#setting-up-docker-spaces)，并在其仓库的根目录下添加此 `Dockerfile`：

```dockerfile
FROM python:3.12-slim-bookworm

# Install FFmpeg for audio and video processing.
RUN apt-get update \
    && apt-get install -y --no-install-recommends ffmpeg \
    && rm -rf /var/lib/apt/lists/*

# Match the non-root user ID used by Docker Spaces.
RUN useradd --create-home --uid 1000 user
USER user

# Check that FFmpeg is available.
CMD ["ffmpeg", "-version"]
```

`FROM` 提供 Python 环境。该基础镜像不包含 FFmpeg，因此 `RUN` 在构建时安装它。`useradd` 创建一个具有主目录和 UID `1000` 的用户，与 [Docker Spaces](./spaces-sdks-docker#permissions) 保持一致；`USER` 以该用户身份运行命令。`CMD` 设置默认命令，此处用于检查 FFmpeg 的安装情况。

提交该文件，并等待 Space 的构建日志显示镜像已推送。然后，在通常填写镜像名称的位置传入 Space URL，将 `YOUR_USERNAME/video-tools` 替换为您的 Space ID：

```bash
hf jobs run --flavor cpu-basic --timeout 5m \
    hf.co/spaces/YOUR_USERNAME/video-tools -- ffmpeg -version
```

该版本会显示在 Job 的日志中。在 Space URL 后提供不同的命令，即可使用 FFmpeg 或 Python 来处理您的工作负载。若要在镜像中包含您自己的脚本，请在 Dockerfile 中添加一行，例如 `COPY --chown=user:user process.py /app/process.py`，然后运行 `python /app/process.py`。有关挂载数据和保存结果，请参阅 [输入和输出文件](#run-your-own-script-with-input-and-output-files)。

> [!NOTE]
> 此示例会打印版本号并退出，因此 Space 在构建后会显示运行时错误。这没有问题：Jobs 只需要构建好的镜像，而不需要一个正在运行的 Space。

> [!TIP]
> Space 的构建镜像不保证始终可拉取。它可能因注册表维护或区域迁移而丢失。如果 Job 报告未找到镜像，请通过 factory 重启 Space 以重新构建。Job 始终使用最新构建，因此新的 commit 也会替换该镜像。

## 示例图像

Registry 镜像由其发布者维护，并且可以固定到特定的标签。

| 图像                                         | 它提供的功能                                                                  |
| --------------------------------------------- | --------------------------------------------------------------------------------- |
| `pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel` | PyTorch 和 CUDA 开发环境，用于上述示例。            |
| `huggingface/trl`                             | 用于后训练及相关 Python 工作负载的 TRL、Transformers、PyTorch 和 uv。 |
| `vllm/vllm-openai`                            | 用于 LLM 推理的 vLLM、uv 和 CUDA 工具。                                      |

使用 `hf jobs run` 来运行命令，并使用镜像中已安装的包。对于 `hf jobs uv run`，请检查镜像中是否已安装 uv，并遵循上述 [环境指南](#use-an-image-with-uv)。浏览 [示例与教程](./jobs-examples) 以查找可运行和适配的工作负载。

## 复用镜像中的软件包并使用 uv 添加依赖项

框架镜像提供了预装的软件包，这些软件包（如 PyTorch、vLLM 及其 CUDA 扩展）的构建过程可能耗时较长或较为复杂。您的脚本可能仍需要额外的 Python 软件包——例如，用于加载特定的数据格式或跟踪实验。

您可以在使用 uv 安装额外依赖项的同时，复用镜像中预装的软件栈。在脚本的 `# /// script` 依赖项头部中声明额外的包，然后将 uv 指向镜像的解释器，并将其 site-packages 添加到导入路径中：

```bash
hf jobs uv run \
    --image vllm/vllm-openai \
    --flavor l4x4 \
    --python /usr/bin/python3 \
    -e PYTHONPATH=/usr/local/lib/python3.12/dist-packages \
    -s HF_TOKEN \
    generate-responses.py
```

- `--python` 使用镜像中的解释器创建 uv 环境，以匹配其编译扩展所使用的 Python 版本。它本身不会暴露镜像中的包。
- `-e PYTHONPATH=...` 使 `import vllm` 在该次运行中解析到镜像中预构建的版本。
- 将 `# /// script` 中的依赖项精简为镜像中_缺失_的部分。`PYTHONPATH` 的搜索优先级高于 uv 的环境，因此镜像会遮蔽头部中为同一包声明的任何内容——包括你固定的更新版本。你保留的依赖项仍可能通过传递依赖引入这些包；uv 不会使用 `PYTHONPATH` 来满足依赖解析。

由于不同图像的路径各不相同，因此请在 `cpu-basic` 上探测它们，而不是硬编码：

```bash
hf jobs run --flavor cpu-basic vllm/vllm-openai bash -c 'which python3; which uv; python3 -m pip show vllm | grep Location'
```

```text
/usr/bin/python3                              # pass to --python
/usr/local/bin/uv                             # uv is present, so `uv run` works
Location: /usr/local/lib/python3.12/dist-packages   # pass to PYTHONPATH
```

将 `vllm` 替换为您正在复用的库。目录结构各不相同——`vllm/vllm-openai` 和 `lmsysorg/sglang` 使用上述系统 `dist-packages`，`unsloth/unsloth` 使用虚拟环境（`/opt/venv/...`），而 `huggingface/trl` 使用 conda（`/opt/conda/lib/python3.11/site-packages`，继承自 `pytorch/pytorch`）。

> [!TIP]
> 这选择的是用于导入的镜像构建，而非用于 uv 依赖解析器的构建。精简头部可以减少冗余安装，但并不能保证完全消除。跳过 `PYTHONPATH` 步骤的 `uv run --system-site-packages` 已在[上游提出请求](https://github.com/astral-sh/uv/issues/7999)。

对于 `huggingface/trl` 镜像，对应的解释器和包路径为：

```bash
hf jobs uv run \
    --image huggingface/trl \
    --flavor a100-large \
    --python /opt/conda/bin/python3 \
    -e PYTHONPATH=/opt/conda/lib/python3.11/site-packages \
    -s HF_TOKEN \
    train.py
```

这些命令使用 `generate-responses.py` 和 `train.py` 作为您自己脚本的名称。

## 故障排除

### 使用框架镜像用于 GPU 库

某些 GPU 库需要额外的系统工具，例如 CUDA 编译器（`nvcc`）、NCCL 或 cuDNN。安装它们的 Python 包并不能保证镜像中包含所需的所有工具。例如，如果镜像中没有 CUDA 工具包，FlashInfer 的采样器在尝试编译内核时可能会失败：

```text
RuntimeError: Could not find nvcc and default cuda_home='/usr/local/cuda' doesn't exist
```

通过传入包含所需 CUDA 工具的框架镜像，可以解决此工具包缺失错误：

```bash
hf jobs uv run --image vllm/vllm-openai --flavor l4x4 -s HF_TOKEN generate-responses.py
```

uv 仍然会单独解析并安装您的脚本依赖项。该镜像提供了系统工具，但并不保证解析出的 Python 包与其兼容。

