教程详解如何将持续集成工作流从 GitHub 迁移到 Hugging Face Jobs,涵盖配置细节和迁移策略。
默认配置很方便,但也有局限性。GitHub Actions 可能很慢或因维护而停机,托管机器是通用的,而且大多数开源项目无法直接启用 GPU 访问。对于 Trackio 来说,这些局限性开始成为问题。我们既需要可靠的 CPU CI 来运行基本的单元测试和前端检查,也需要 GPU CI 来运行需要在真实 CUDA 硬件上执行的测试。
所以我们构建了一个替代方案:由 GitHub Actions 管理 CI,但在 Hugging Face Jobs 上运行实际的任务。
结果是:Trackio 的 CI 现在运行在 Hugging Face Jobs 上,并实时流式传输日志,将 CPU 任务的 CI 时间减少了约 30%,并启用了一整套在 GPU 机器上运行的新测试套件!
在这篇文章中,我们逐步说明如何为你的 GitHub 仓库重建相同的设置。如果你在使用一个 agent,可以将它指向这篇文章,因为我们同时提供了 CLI 指令和浏览器界面的说明。
让我们从 Hugging Face Jobs 的简要介绍开始吧!
Hugging Face Jobs 让你可以在 Hugging Face 的无服务器基础设施上运行命令或脚本,支持几乎任何硬件配置。一个 Job 基本上包括:
一个 Docker 镜像,来自 Docker Hub 或 Hugging Face Space
一个硬件配置,如 CPU、t4-small 或 h200 GPU
可选的环境变量和密钥
例如,你可以运行:
hf jobs run python:3.12 python -c "print('Hello world')"
hf jobs uv run --flavor a10g-small "https://raw.githubusercontent.com/huggingface/trl/main/trl/scripts/sft.py"
这使得 Jobs 非常适合 CI。CI 任务本身就是以命令驱动的,在干净的环境中运行,并且通常受益于选择正确的硬件。对于 ML 库来说,GPU 情况尤其引人注目:你可以在真实的 GPU 硬件上运行测试套件,而无需维护自己的常开 runner。
关键步骤是连接 GitHub Actions 到 HF Jobs,我们在下面描述这个过程。
为了实现这个设置,我们创建了 huggingface/jobs-actions,这是一个小的桥接层,将一个 GitHub Actions 任务转换为在 HF Job 内运行的临时自托管 runner。
完整的流程如下:
一个 pull request 触发 GitHub Actions 工作流。
GitHub 将其 runs-on 标签不可用的任何任务排队,例如 hf-jobs-cpu-upgrade 或 hf-jobs-t4-small,并通过 GitHub App 向 dispatcher 发送签名的 workflow_job.queued webhook。
dispatcher Space 验证 webhook,检查 hf-jobs-* 标签,生成一个短期 GitHub runner 注册令牌,并在匹配的硬件上启动一个 HF Job。
HF Job 启动一个临时 GitHub Actions runner 并使用该一次性令牌将其注册到仓库。
GitHub 将待处理的工作流任务分配给该 runner;runner 执行 CI 任务,向 GitHub 报告状态,然后退出。
从 GitHub 的角度来看,这只是一个自托管 runner。从 Hugging Face 的角度来看,它只是一个启动容器来运行仓库的 GitHub Actions 工作流步骤的 Job。
首先你需要 dispatcher。这是一个小的 Docker Space,它接收 GitHub workflow_job webhook 事件并相应地启动 HF Jobs。
首先创建这个是因为 GitHub App 需要一个 webhook URL,而那个 URL 来自这个 Space。这个 Space 应该在你自己的命名空间或你有写入权限的 Hugging Face 组织下。
进入 huggingface/jobs-actions-dispatcher 并点击 Duplicate this Space。
Owner: your HF user or org
Name: jobs-actions-dispatcher
Hardware: cpu-upgrade
为了实际的 CI,请使用 cpu-upgrade 以保证 dispatcher 始终可用于接收 GitHub webhook。cpu-basic 可以用于测试,可能也可以工作,但它在不活动后可能会休眠;如果 GitHub 的 webhook 在它唤醒时到达,工作流可能会永远停留在队列中。
构建完成后,打开复制的 Space。你会看到一个部分说 "Required Space secrets",现在可以忽略。登陆页面应该显示你在下一步需要的 GitHub App webhook URL。它看起来会像这样:
https://YOUR-HF-NAMESPACE-jobs-actions-dispatcher.hf.space/webhook
如果你更喜欢用 agent 设置 dispatcher Space 或使用 CLI 工作流:
export HF_NAMESPACE=your-hf-user-or-org
export SPACE_ID="$HF_NAMESPACE/jobs-actions-dispatcher"
hf repo duplicate huggingface/jobs-actions-dispatcher "$SPACE_ID" \
--type space \
--flavor cpu-upgrade \
--exist-ok
export DISPATCHER_URL="https://${HF_NAMESPACE}-jobs-actions-dispatcher.hf.space"
接下来,从 dispatcher Space 本身创建并安装 GitHub App。这个 App 需要权限来监听排队的工作流任务并创建临时自托管 runner 注册令牌。
打开你复制的 dispatcher Space:
https://YOUR-HF-NAMESPACE-jobs-actions-dispatcher.hf.space
在设置表单中,输入其 CI 应该在 HF Jobs 上运行的 GitHub 仓库:
YOUR-GITHUB-ORG/YOUR-REPO
然后点击按钮来创建 GitHub App。GitHub 会要求你为这个 App 选择一个名称;名称可以是任何东西,只要在你的 GitHub 账户或组织中可用。提交后,最后一个屏幕会准确告诉你如何使用 hf CLI 将 App 凭证上传到 dispatcher Space。
重要提示:你需要提供一个具有启动 Jobs 权限的 Hugging Face 令牌,对应于你的个人账户或应该对 Jobs 进行计费的组织。这个令牌应该被保存为 dispatcher Space 中的 HF_TOKEN 密钥。
最后,你将在你在 Space 中输入的同一个 GitHub 仓库上安装这个 App。在 Trackio 设置中,我们在 gradio-app/trackio 上安装了它。
GitHub App 清单流程仍然是基于浏览器的,但一个 agent 可以遵循相同的 Space 驱动路径:
export HF_NAMESPACE=your-hf-user-or-org
export GITHUB_REPO=YOUR-GITHUB-ORG/YOUR-REPO
open "https://${HF_NAMESPACE}-jobs-actions-dispatcher.hf.space"
将 $GITHUB_REPO 粘贴到 Space 中,点击 GitHub App 创建按钮,选择任何可用的 App 名称,并按照生成的 GitHub 指令操作。
App 存在后,从 App 设置页面在你的仓库上安装它。对于 GitHub 组织,安装设置在:
https://github.com/organizations/YOUR-GITHUB-ORG/settings/installations
此时,dispatcher Space 应该已配置。GitHub App 设置流程生成了将 App 凭证、webhook 密钥和 Hugging Face 令牌上传到 Space 的命令。
默认情况下,HF Jobs 在与 dispatcher Space 相同的命名空间下启动。或者,如果你想将任务计费到不同的 Hugging Face 用户或组织,可以将 HF_NAMESPACE 设置为 Space 变量:
export SPACE_ID=YOUR-HF-NAMESPACE/jobs-actions-dispatcher
hf spaces variables add "$SPACE_ID" -e HF_NAMESPACE=your-billing-namespace
hf spaces restart "$SPACE_ID"
你在第 2 步中设置的令牌应该对应于这个命名空间。
实际的工作流更改很小。不使用:
runs-on: ubuntu-latest
而是使用 dispatcher 处理的标签之一:
runs-on: hf-jobs-cpu-upgrade
对于 GPU 测试,使用 GPU 标签:
runs-on: hf-jobs-t4-small
对于任何你想在 HF Jobs 上运行的 GitHub Action,这个 1 行的更改就是你需要做的一切!
要从 CLI 添加一个最小的冒烟测试工作流:
mkdir -p .github/workflows
cat > .github/workflows/hf-jobs-test.yml <<'EOF'
name: HF Jobs Test
on:
pull_request:
push:
branches: [main]
workflow_dispatch:
jobs:
test:
runs-on: hf-jobs-cpu-upgrade
steps:
- uses: actions/checkout@v4
- run: echo "Hello from Hugging Face Jobs"
EOF
git add .github/workflows/hf-jobs-test.yml
git commit -m "Run CI on Hugging Face Jobs"
git push
要从 CLI 验证:
gh run list --repo YOUR-GITHUB-ORG/YOUR-REPO --limit 5
hf jobs ps --namespace "$HF_NAMESPACE"
hf spaces logs "$SPACE_ID"
你应该能够看到日志,就像一个常规的 GitHub Action 一样——例如,在这个 Trackio PR #565 中。
我们最初的 CPU 设置使用 ubuntu:22.04 并在每次运行时安装缺失的系统包。这有效,但速度不如应该的那样快。GitHub 的 ubuntu-latest 镜像默认包括大量开发者工具;一个裸的 Ubuntu 镜像则不包括。
对于 Trackio,UI 测试需要 Playwright 浏览器、Node、ffmpeg、sqlite、git 和普通的 Linux 构建依赖。Hugging Face Jobs 支持使用任何 Docker 镜像,所以我们切换到了 Microsoft Playwright 镜像,效果很好:
mcr.microsoft.com/playwright:v1.60.0-jammy
对于 GPU 任务,我们使用了:
nvidia/cuda:12.4.0-runtime-ubuntu22.04
以下是 Trackio CI 的数字:
最大的胜利是 GPU CI。Trackio GPU 检查在 HF Jobs 上运行,在 45 秒内通过,成本不到一分钱(按 t4-small 的速率计算那个时长)。
CPU 结果也很令人鼓舞。使用正确的镜像,Linux 测试任务比 GitHub 托管的基线更快。这表明 HF Jobs 可以是一个实用的 CI 后端,特别是对于需要自定义镜像或加速器的 ML 项目。
日志是另一个惊喜。GitHub Actions 的日志很有用,但 web UI 对于大日志可能很重。HF Jobs 的日志很容易从 CLI 获取:
hf jobs logs <job_id> > logs.txt
这使得它们易于用本地工具或 coding agent 检查。在我们的桥接层中,我们也将 GitHub Actions 任务日志镜像到 HF Job 日志中,所以任一系统都有足够的信息来调试一次运行。
最后,虽然我们没有为 Trackio 的 CI 需要它们,但 HF Jobs 也支持挂载卷,这非常有帮助,如果你需要在 CI 过程中快速从 Hugging Face 加载数据集或模型。
希望这能给你尝试 HF Jobs 来运行你的 GitHub Actions 所需的一切!
更多来自我们博客的文章
在 5 分钟内学习 Hugging Face Kernel Hub
在 HF Jobs 上一条命令运行 vLLM 服务器
GitHub CI 是无限的且免费的。在 Huggingface 中我现在甚至无法运行超过 3 个 CPU spaces。
嗨 @k-l-lambda,当你尝试运行超过 3 个 CPU Spaces 时看到什么错误?能否分享更多关于你的 CI 设置?
如果你在迁移 CI 时需要任何帮助,请随时留下评论!
本文提到的 Spaces