GitHub Actions

概览

RAPIDS 团队使用 GitHub Actions 进行 CI/CD。GitHub Actions 的官方文档可以在这里查看。

目标受众

运维人员

开发者

目录

  1. 介绍
  2. GitHub Actions 工作流程
  3. 夜间构建如何触发
  4. 订阅夜间构建
  5. 可重用工作流程
  6. 可重用 Shell 脚本
  7. 下载 CI Artifacts
  8. 在本地使用 Conda CI Artifacts
  9. 在本地使用 Wheel CI Artifacts
  10. 在其他 PR 中使用 Conda CI Artifacts
  11. 在其他 PR 中使用 Wheel CI Artifacts
  12. 跳过特定提交的 CI
  13. 重新运行失败的 GitHub Actions

介绍

RAPIDS 使用 NVIDIA 提供的自托管运行器进行 GPU 测试。有关这些自托管运行器的更多信息,请访问官方文档网站此处

此外,此处关于拉取请求测试的部分可能对不熟悉该过程的用户有所帮助。

最后,此处的页面列出了可用的运行器标签。

GitHub Actions 工作流程

每个使用 GitHub Actions 的 RAPIDS 仓库都至少包含以下三个 GitHub Action 工作流程文件:

这些 GitHub Actions 工作流程文件包含了作为工作流程一部分运行的所有自动化作业的描述。

这些作业包括 C++/Python 构建、C++/Python 测试、Notebook 测试等。

下表概述了每个工作流程文件的用途。

事件 运行工作流程 执行构建? 执行测试? 上传到 Anaconda.org/Wheel 仓库?
- PRs - pr.yaml
- branch-* 合并
- 发布
- build.yaml
- 夜间构建 - build.yaml
- test.yaml

虽然发布工作流程不运行测试,但它们会经历一周的夜间测试以确保一切按预期工作。有关发布流程的更多详细信息,请参阅此页面

夜间构建如何触发

由于 RAPIDS 包含相互依赖的一系列库,因此夜间构建和测试按正确的顺序运行非常重要。

rapidsai/workflows 仓库有一个夜间管道作业,负责按正确的顺序触发作业。

夜间管道作业的示例运行可以在下面的截图中看到。

订阅夜间构建

GitHub 最近的一篇博文解释了如何通过 Slack 订阅工作流程通知。

文章大意是可以在任何 Slack 频道中运行以下命令来订阅该频道接收特定工作流程的通知:

/github subscribe owner/repo workflows:{name: "workflow_name"}

也可以向命令传递多个工作流程名称以订阅多个工作流程(示例如下)。

对于 RAPIDS 库,建议使用以下命令将特定 Slack 频道订阅到分支构建、夜间构建和夜间测试工作流程运行:

/github subscribe rapidsai/<repo> workflows:{name: "test","build"}
/github unsubscribe rapidsai/<repo> issues pulls commits releases deployments

第二步是必要的,因为 /github subscribe 命令还会订阅该频道到许多其他 GitHub 事件,这将产生很多噪音。

workflows 对象中的 name 字段对应于特定工作流程的名称(例如此字段)。

若要仅订阅夜间构建和夜间测试(而不包括分支构建),可以使用 actor 过滤器:

/github subscribe rapidsai/<repo> workflows:{name: "test","build", actor:"GPUtester"}

GPUtester 账户是一个系统账户,用于从上游工作流程触发夜间工作流程运行。

可重用工作流程

RAPIDS 使用一系列可重用的 GitHub Actions 工作流程来实现通用构建配置设置的单源化。这些可重用工作流程可以在 rapidsai/shared-workflows 仓库中找到。

RAPIDS 使用的一个可重用工作流程示例是 conda-cpp-build.yaml 工作流程,它是构建 RAPIDS C++ 包的架构和 CUDA 版本真相的来源。

类似地,conda-cpp-tests.yaml 工作流程指定了测试 RAPIDS C++ 包的配置。

这些可重用工作流程的大多数都利用了 rapidsai/ci-imgs 仓库中的 CI 镜像。

可重用 Shell 脚本

除了可重用的 GitHub Actions 工作流程外,RAPIDS 项目还利用 rapidsai/gha-tools 仓库中的可重用 shell 脚本。

所有这些 shell 脚本都以字符串 rapids- 为前缀。

例如,rapids-print-env 用于打印常见的环境信息。

rapids-mamba-retry 是另一个工具,它包装了 mamba 可执行文件,以重试因网络问题等临时问题而失败的命令。

下载 CI Artifacts

对于拥有 VPN 访问权限的 NVIDIA 员工,可以从 https://downloads.rapids.ai/ 访问拉取请求和分支构建的 artifacts。

每个 C++ 和 Python 构建作业的末尾都提供了一个链接,可以访问该特定工作流程运行的构建 artifacts。

在本地使用 Conda CI Artifacts

运行 conda build 生成的 artifacts 是 conda 渠道。RAPIDS 的 CI 系统随后将这些 conda 渠道压缩成 tar 包并上传到 https://downloads.rapids.ai/

可以通过将 tar 包解压到本地文件系统,并在 conda 命令中使用 resulting path 来使用 conda 渠道中的包。

例如,以下代码片段将下载 librmm 的拉取请求 artifact 并将其安装到当前的 conda 环境中:

wget https://downloads.rapids.ai/ci/rmm/pull-request/1376/5124d43/rmm_conda_cpp_cuda11_x86_64.tar.gz
mkdir local_channel
tar xzf rmm_conda_cpp_cuda11_x86_64.tar.gz -C local_channel/
mamba install --channel file://local_channel --channel rapidsai-nightly --channel conda-forge --channel nvidia librmm

请注意,CI artifacts 只能在连接到 NVIDIA VPN 时下载。

在本地使用 Wheel CI Artifacts

RAPIDS 的 CI 系统将其构建的 wheel 压缩成 tar 包,并上传到 https://downloads.rapids.ai/

可以通过将 tar 包解压到本地文件系统,并在 pip 命令中使用 resulting path 来使用 wheel。

例如,以下代码片段将下载 librmm 的拉取请求 artifact 并将其安装到当前的 conda 环境中:

wget https://downloads.rapids.ai/ci/rmm/pull-request/1376/5124d43/rmm_wheel_python_rmm_cu12_39_x86_64.tar.gz
mkdir wheels
tar xzf rmm_wheel_python_rmm_cu12_39_x86_64.tar.gz -C wheels/
pip install wheels/rmm_cu12-24.2.0a1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

请注意,CI artifacts 只能在连接到 NVIDIA VPN 时下载。

在其他 PR 中使用 Conda CI Artifacts

对于跨库的更改,可能需要使用一个库的拉取请求中的更改来测试另一个库的拉取请求。测试时请考虑整体的 RAPIDS 依赖图。例如,如果你正在 cuML 中测试 RMM PR rmm#A 的 artifacts,你可能还需要创建一个使用 rmm#A 的 artifacts 的 cuDF PR cudf#B,然后你的 cuML 测试 PR 将需要包含 rmm#Acudf#B 的 artifact 渠道。

为此,需要在另一个库的 CI 工作流程中下载来自一个库的 CI artifacts(如上一节所述)。首先,确定要从其他库测试的拉取请求编号。然后,获取其他库拉取请求中的 CI artifacts,并在构建和测试时使用它们。以下示例代码演示了使用来自其他库 PR 的 conda 包进行构建和测试。根据需要替换拉取请求编号和库名称。请记住,使用 CI artifacts 的更改应是临时的,并且应在合并该 PR 中任何必需的更改之前恢复。

示例 1: 使用 librmmlibraft PR artifacts 构建 libcuml (C++)。

添加一个名为 ci/use_conda_packages_from_prs.sh 的新文件。

# ci/use_conda_packages_from_prs.sh

# download CI artifacts
LIBRAFT_CHANNEL=$(rapids-get-pr-conda-artifact raft 1388 cpp)
LIBRMM_CHANNEL=$(rapids-get-pr-conda-artifact rmm 1095 cpp)

# make sure they can be found locally
conda config --system --add channels "${LIBRAFT_CHANNEL}"
conda config --system --add channels "${LIBRMM_CHANNEL}"

然后将以下内容复制到 ci/ 目录中进行 conda 安装的每个脚本中。

source ./ci/use_conda_packages_from_prs.sh

示例 2: 使用 librmm, rmm, 和 libkvikio PR artifacts 测试 cudf (Python)。

重要的是要包含所有递归依赖项。例如,使用 rmm Python 包的 Python 测试作业也需要 librmm C++ 包。

# ci/use_conda_packages_from_prs.sh

# download CI artifacts
LIBKVIKIO_CHANNEL=$(rapids-get-pr-conda-artifact kvikio 224 cpp)
LIBRMM_CHANNEL=$(rapids-get-pr-conda-artifact rmm 1223 cpp)
RMM_CHANNEL=$(rapids-get-pr-conda-artifact rmm 1223 python)

# make sure they can be found locally
conda config --system --add channels "${LIBKVIKIO_CHANNEL}"
conda config --system --add channels "${LIBRMM_CHANNEL}"
conda config --system --add channels "${RMM_CHANNEL}"

然后将以下内容复制到 ci/ 目录中进行 conda 安装的每个脚本中。

source ./ci/use_conda_packages_from_prs.sh

注意:默认情况下,rapids-get-pr-conda-artifact 使用指定 PR 中的最新提交。可以添加 dependent PR 的提交哈希作为可选的第四个参数,以便将测试固定到特定提交。

在其他 PR 中使用 Wheel CI Artifacts

要使用其他 PR 的 CI 生成的 wheel:

  • 在 CI 作业开始时下载 wheel
  • 约束 pip 始终使用它们

考虑以下示例。

示例: 使用 librmmlibraft PR artifacts 构建 libcuml (C++)。

添加一个名为 ci/use_wheels_from_prs.sh 的新文件。

# ci/use_wheels_from_prs.sh

RAPIDS_PY_CUDA_SUFFIX=$(rapids-wheel-ctk-name-gen "${RAPIDS_CUDA_VERSION}")

# download wheels, store the directories holding them in variables
LIBRMM_WHEELHOUSE=$(
  RAPIDS_PY_WHEEL_NAME="librmm_${RAPIDS_PY_CUDA_SUFFIX}" rapids-get-pr-wheel-artifact rmm 1678 cpp
)
LIBRAFT_WHEELHOUSE=$(
  RAPIDS_PY_WHEEL_NAME="libraft_${RAPIDS_PY_CUDA_SUFFIX}" rapids-get-pr-wheel-artifact raft 2433 cpp
)

# write a pip constraints file saying e.g. "whenever you encounter a requirement for 'librmm-cu12', use this wheel"
cat > /tmp/constraints.txt <<EOF
librmm-${RAPIDS_PY_CUDA_SUFFIX} @ file://$(echo ${LIBRMM_WHEELHOUSE}/librmm_*.whl)
libraft-${RAPIDS_PY_CUDA_SUFFIX} @ file://$(echo ${LIBRAFT_WHEELHOUSE}/libraft_*.whl)
EOF

export PIP_CONSTRAINT=/tmp/constraints.txt

然后将以下内容复制到 ci/ 目录中进行 pip 安装或使用 pip wheel 等构建 wheel 的每个脚本中。

source ./ci/use_wheels_from_prs.sh

这通常就足够了。如果其他 CI 脚本已经设置了环境变量 PIP_CONSTRAINT,你可能需要稍微修改它们,以确保它们是追加而不是覆盖use_wheels_from_prs.sh 设置的约束。

示例 2: 使用 librmm, rmm, 和 libkvikio PR artifacts 测试 cudf (Python)。

重要的是要包含所有递归依赖项。例如,使用 rmm Python 包的 Python 测试作业也需要 librmm C++ 包。

# ci/use_wheels_from_prs.sh

RAPIDS_PY_CUDA_SUFFIX=$(rapids-wheel-ctk-name-gen "${RAPIDS_CUDA_VERSION}")

# download wheels, store the directories holding them in variables
LIBKVIKIO_WHEELHOUSE=$(
  RAPIDS_PY_WHEEL_NAME="libkvikio_${RAPIDS_PY_CUDA_SUFFIX}" rapids-get-pr-wheel-artifact kvikio 510 cpp
)
LIBRMM_WHEELHOUSE=$(
  RAPIDS_PY_WHEEL_NAME="librmm_${RAPIDS_PY_CUDA_SUFFIX}" rapids-get-pr-wheel-artifact rmm 1678 cpp
)
RMM_WHEELHOUSE=$(
  RAPIDS_PY_WHEEL_NAME="rmm_${RAPIDS_PY_CUDA_SUFFIX}" rapids-get-pr-wheel-artifact rmm 1678 python
)

# write a pip constraints file saying e.g. "whenever you encounter a requirement for 'librmm-cu12', use this wheel"
cat > /tmp/constraints.txt <<EOF
libkvikio-${RAPIDS_PY_CUDA_SUFFIX} @ file://$(echo ${LIBKVIKIO_WHEELHOUSE}/libkvikio_*.whl)
librmm-${RAPIDS_PY_CUDA_SUFFIX} @ file://$(echo ${LIBRMM_WHEELHOUSE}/librmm_*.whl)
rmm-${RAPIDS_PY_CUDA_SUFFIX} @ file://$(echo ${RMM_WHEELHOUSE}/rmm_*.whl)
EOF

export PIP_CONSTRAINT=/tmp/constraints.txt

然后将以下内容复制到 ci/ 目录中进行 pip 安装或使用 pip wheel 等构建 wheel 的每个脚本中。

source ./ci/use_wheels_from_prs.sh

如上所述,如果其他 CI 脚本已经设置了环境变量 PIP_CONSTRAINT,你可能需要稍微修改它们,以确保它们是追加而不是覆盖use_wheels_from_prs.sh 设置的约束。

注意:默认情况下,rapids-get-pr-wheel-artifact 使用指定 PR 中的最新提交。可以添加 dependent PR 的提交哈希作为可选的第四个参数,以便将测试固定到特定提交。

跳过特定提交的 CI

请参阅以下 GitHub Actions 文档页面,了解如何阻止 GitHub Actions 在某些提交上运行。这对于阻止 GitHub Actions 在未完全完成的拉取请求上运行很有用。这也有助于节省 RAPIDS 运维团队提供的有限 GPU 资源。

使用 GitHub Actions,无法配置拉取请求的所有提交都被跳过。必须在提交级别指定。

链接: https://githubdocs.cn/en/actions/managing-workflow-runs/skipping-workflow-runs

重新运行失败的 GitHub Actions

请参阅以下 GitHub Actions 文档页面,了解如何重新运行失败的工作流程。除了重新运行整个工作流程外,GitHub Actions 还提供了仅重新运行工作流程中失败作业的功能。

目前,除了文档中描述的方式外,没有其他方法可以使用 GitHub Actions 重新运行测试(例如,GitHub Actions 没有 rerun tests 注释)。

链接: https://githubdocs.cn/en/actions/managing-workflow-runs/re-running-workflows-and-jobs