持续集成(CI)

持续集成(CI)要求每次准备提交一组修改时,都构建整个应用, 并执行一套全面的自动化测试 [1],包括单元测试、功能测试和其他测试。

QEMU 的大部分 CI 在 GitLab 基础设施上运行,也使用其他 CI 服务完成特定工作。 最新信息及状态见 项目 Wiki 测试页面。

这些测试也作为合并拉取请求之前的准入检查。 准入检查限制代码在测试或部署流程中进入下一阶段,只有获准后才能推进。 批准可以来自人工操作,也可以由一组测试通过来决定 [2]。

在 QEMU 中,准入流程发生在拉取请求阶段。 项目负责人运行自己的测试集进行批准,测试通过后合并请求。

自定义 CI/CD 变量

可以通过 CI 环境变量调整 QEMU 的 CI 流水线。

在用户 CI 命名空间中全局设置

变量可在用户 CI 命名空间设置中全局定义。 具体方法见:

https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project

推送分支或标签到用户仓库时手动设置

推送分支或标签时,可以通过 git-push 命令行参数手动设置变量。 以下设置 QEMU_CI_EXAMPLE_VAR:

git push -o ci.variable="QEMU_CI_EXAMPLE_VAR=value" myrepo mybranch

具体方法见:

https://docs.gitlab.com/ee/user/project/push_options.html#push-options-for-gitlab-cicd

在 Git 配置中设置别名

通过别名可以方便地使用不同 CI 配置推送分支。 例如定义触发 CI 的别名:

git config --local alias.push-ci "push -o ci.variable=QEMU_CI=1"
git config --local alias.push-ci-now "push -o ci.variable=QEMU_CI=2"

随后运行:

git push-ci

即可创建流水线;或者运行:

git push-ci-now

创建并立即运行流水线。

变量命名和分组

QEMU CI 配置使用的变量划分为几个命名空间:

  • QEMU_JOB_nnnn:在单个作业或模板中定义,影响 .base_job_template 中的公共规则。

  • QEMU_CI_nnn:贡献者在仓库 CI 设置中定义,或通过 git push 传入, 控制流水线运行哪些作业。

  • QEMU_CI_CONTAINER_TAG:阶段 1 发布容器时使用的标签,供阶段 2 构建作业使用。 默认为 latest;多个分支并发运行流水线时,应为各流水线单独覆盖。

  • QEMU_CI_UPSTREAM:视为上游的 GitLab 命名空间,默认为 qemu-project。 修改 base.yml 规则且需要验证上游上下文行为,而非自己 fork 的行为时, 贡献者可以覆盖此值。

  • nnn:其他未归入上述类别的杂项变量, 或因历史原因使用其他名称、尚未完成转换的变量。

维护者控制的作业变量

在 CI 配置文件中定义作业时,可以设置以下变量。

QEMU_JOB_OPTIONAL

作业通常应能成功,但为节约有限 CI 资源,默认不运行。 贡献者可在流水线界面中手动启动。

QEMU_JOB_ONLY_FORKS

作业结果仅对提交代码前的贡献者有用,不是合并准入流水线的必需部分。

QEMU_JOB_SKIPPED

作业通常不能可靠成功,因此目前不适合默认运行。 理想情况下这只是临时标记,直到修复问题或永久移除作业。

QEMU_JOB_PUBLISH

作业用于在分支合入上游默认分支后发布内容。

QEMU_JOB_FUNCTIONAL

作业运行功能测试套件。

QEMU_JOB_MACOS

作业需要访问 macOS 共享运行器,仅 Premium/Ultimate 等级可用。 这包括开源项目成员,但不包括 fork 仓库。

贡献者控制的运行时变量

贡献者可设置以下变量控制作业执行。

QEMU_CI

为节省 CI 额度,贡献者 fork 默认不创建流水线。

设为 1 时创建流水线,但全部作业需要在界面手动启动。

设为 2 时创建流水线并立即运行全部作业,恢复以往的行为。

QEMU_CI_FUNCTIONAL

默认不自动运行使用功能测试框架的测试, 因为需要下载多个产物,可能造成大量网络流量。 设置此变量后,这些测试会自动运行。

其他杂项变量

这些变量主要控制私有运行器上的作业。

AARCH64_RUNNER_AVAILABLE

如果可使用某个 aarch64 主机作为 GitLab CI 运行器, 设置此变量可启用需要此类主机的测试。运行器应带 aarch64 标签。

S390X_RUNNER_AVAILABLE

如果可使用某个 IBM Z 主机作为 GitLab CI 运行器, 设置此变量可启用需要此类主机的测试。运行器应带 s390x 标签。

PPC64LE_RUNNER_AVAILABLE

如果可使用某个 PPC64LE 主机作为 GitLab CI 运行器, 设置此变量可启用需要此类主机的测试。运行器应带 ppc64le 标签。

CCACHE_DISABLE

作业默认使用 ccache,通常能缩短编译时间,但会增加存储占用。 若怀疑它反而增加整体执行时间,可设置 CCACHE_DISABLE=1 禁用。

自定义运行器上的作业

除了前述各种 CI 系统的作业,实际合并前还有一些额外作业。 它们使用相同的 GitLab CI 服务和框架,但依赖额外机器, 而非 GitLab 提供的共享运行器。

GitLab CI 架构允许在不同机器上部署称为 gitlab-runner 的代理, 负责执行推送分支等事件创建的作业。 这里把机器及其正确配置的 gitlab-runner 合称为“自定义运行器”。

相关作业定义位于:

.gitlab-ci.d/custom-runners.yml

自定义运行器需要自行提供机器。 当前 QEMU GitLab CI 部署的机器及维护者名单见 QEMU Wiki。

机器设置方法

Linux 系统的大部分设置可以通过两个 Ansible playbook 自动完成。 在 scripts/ci/setup 下创建 inventory 文件,例如:

fully.qualified.domain
other.machine.hostname

可能需要直接在清单文件中设置变量。 常见需求是要求 Ansible 在这些主机上使用 Python 3,例如:

fully.qualified.domain ansible_python_interpreter=/usr/bin/python3
other.machine.hostname ansible_python_interpreter=/usr/bin/python3

构建环境

scripts/ci/setup/$DISTRO/build-environment.yml 为机器配置构建和运行 QEMU 测试所需的环境, 安装各种必需软件包,并顺带执行总体软件包更新。

已经成功测试的最低 Ansible 版本为 2.8.0,playbook 内也包含版本检查。 运行方式:

cd scripts/ci/setup
ansible-playbook -i inventory $DISTRO/build-environment.yml

多数任务需要超级用户权限,例如 root 身份或通过 sudo 获取权限。 必要时请参阅 ansible-playbook 的 --become、--become-method、 --become-user 和 --ask-become-pass 等选项。

gitlab-runner 设置和注册

每台运行作业的机器都需要安装 gitlab-runner。 机器通过注册令牌与 GitLab 项目关联。 在 GitLab 网页界面按以下路径查找仓库或项目的注册令牌:

  • Settings,左侧竖向工具栏底部的齿轮图标;

  • CI/CD;

  • Runners,点击 Expand;

  • 在 Set up a specific Runner manually 下查找 And this registration token 的值。

将 scripts/ci/setup/vars.yml.template 复制为 scripts/ci/setup/vars.yml, 再将 gitlab_runner_registration_token 设置为此前获取的值。

运行 playbook:

cd scripts/ci/setup
ansible-playbook -i inventory gitlab-runner.yml

注册后,需要在 GitLab 界面配置运行器标签,也可调整其他设置。路径为:

  • Settings,齿轮图标;

  • CI/CD;

  • Runners,点击 Expand;

  • Runners activated for this project;

  • 点击锁形图标旁的编辑图标。

标签用于将特定作业分配给相应类型的运行器,非常重要。 应复核自动创建的标签是否与操作系统和架构一致。 例如 Ubuntu 20.04 aarch64 应设置为:

ubuntu_20.04,aarch64

因为 .gitlab-ci.d/custom-runners.yml 中的作业定义会包含:

ubuntu-20.04-aarch64-all:
 tags:
 - ubuntu_20.04
 - aarch64

另外建议:

  • 将 Maximum job timeout 增加到例如 2h;

  • 填写更清楚的 Description。

参考资料