持续集成(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。