news 2026/9/19 1:13:33

Perfetto CI 架构解析:基于 GCE 自托管 Runner 与 GitHub Actions 的弹性持续集成系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Perfetto CI 架构解析:基于 GCE 自托管 Runner 与 GitHub Actions 的弹性持续集成系统

Perfetto CI 架构解析:基于 GCE 自托管 Runner 与 GitHub Actions 的弹性持续集成系统

【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto

导读

本文基于 Perfetto 仓库的 continuous-integration.md 设计文档,深入解析 Perfetto 项目用于补充 Android TreeHugger 的持续集成体系:它以 GitHub Actions 为调度入口,在 Google Cloud(GCE + GAE)上运行自托管 Runner,通过"VM → worker 容器 → sandbox 容器"三级分层实现无状态、可弹性伸缩、安全隔离的构建与测试。读完本文,你将掌握这套 CI 的整体架构、启动链路、核心配置参数、日常运维 Playbook 及其安全模型,并可在自己的项目中复用其设计思路。

Perfetto 的 CI 定位十分明确:它叠加在 Android TreeHugger 之上(而非替代),目的是为 TreeHugger 不支持的其它操作系统和较老 Android 设备提供早期测试信号与覆盖。整套 CI 基于 GitHub Actions,入口工作流为 .github/workflows/analyze.yml。

一、CI 整体架构:GitHub Actions + GCE 自托管 Runner

Perfetto CI 由两个主要部分构成:

  1. 调度层:GitHub Actions 工作流(位于 .github/workflows/),负责根据变更文件类型决定触发哪些测试;
  2. 执行层:注册在 GitHub 项目上的自托管 Runner,托管于名为perfetto-ci的 Google Cloud 项目中,源码位于 infra/ci。

与直接使用 GitHub 托管的 runner 不同,自托管方案让 Perfetto 能够完全掌控 runner 的运行环境(Docker 镜像、临时磁盘、网络隔离、服务账号权限),并借助 GCE 的自动扩缩容能力按需拉起计算资源,同时将成本函数与待处理任务队列长度绑定。

从仓库结构看,infra/ci 下包含三类核心组件:

  • frontend/:基于 AppEngine 的控制器(ci.perfetto.dev),负责编排队列与推送扩缩容指标;
  • worker/:运行在每台 GCE VM 上的特权容器与相关脚本;
  • sandbox/:真正执行 GitHub Action Runner 的隔离容器。

下图展示了这套 CI 的整体结构(图片来源为仓库内的 CI 架构图):

二、入口工作流 analyze.yml:按变更类型扇出的作业调度

.github/workflows/analyze.yml 是整个 CI 的入口。它负责在 push(postsubmit,main分支)和 pull_request(presubmit,maindev/**/*分支,类型为openedsynchronize)时被触发,并设置了concurrency组以在新提交推送时取消同一 PR/分支上的旧任务。

该工作流中的analyzejob 特意运行在GitHub 的ubuntu-latest公共池上(而非自托管 sandbox)。注释给出了两点刻意设计的原因:

  1. analyze不需要 sandbox 容器提供的任何特殊能力,公共池更快;
  2. 当 CI 自动扩缩容降到 0 时,等待自托管资源就绪会很久,从而延迟子任务的排队、进而延迟扩容——把analyze放在公共池能尽快扇出子任务。

analyzejob 通过git diff --name-only对比上游分支,产出三个关键输出(outputs),用于驱动下游作业的条件执行:

输出判定逻辑(仓库内egrep正则)含义
TRIVIAL_CHANGE变更文件全部落在^(docs\|infra\|tools\|test/data\|[.]github)/纯文档/基建变更,跳过全部构建测试
UI_ONLY_CHANGE变更文件全部落在^(ui\|test/data/ui-screenshots)/仅 UI 变更,跳过 linux/android 等重型测试
BIGTRACE_CHANGE存在^ui/src/bigtrace/下的变更额外触发 bigtrace 测试

随后analyze按条件扇出以下子工作流(均为needs: analyze的可复用工作流):

  • linux-tests.yml:非 UI-only 且非 trivial 时触发;
  • android-tests.yml:同上;
  • ui-tests.yml:非 trivial 时触发;
  • bazel-tests.yml 与 fuzzer-tests.yml:非 UI-only 且非 trivial 时触发;
  • bigtrace-tests.yml:仅BIGTRACE_CHANGE == '1'时触发;
  • repo-checks.yml 与 rust-sdk-tests.yml:分别无条件/条件触发。

工作流末尾的ensure-ci-is-greenjob 汇总所有(可能被跳过的)子工作流结果:successskipped视为通过,cancelled会取消整个 run,其余视为失败——该 job 供仓库的 "require CI to pass" ruleset 使用,是合入门禁的最终裁决点。

三、自托管 Runner 的三级分层:VM → worker → sandbox

Perfetto CI 的执行资源按"三级容器/进程"组织,职责逐级收窄、权限逐级收缩。

3.1 GCE VM 层:无状态、只读系统盘

Worker GCE VM 的数量可变(由GCE_VM_TYPE等参数驱动,见 infra/ci/config.py),由 Google Cloud Autoscaler 动态拉起,上限为MAX_VMS_PER_REGION。每台 VM 的整机系统镜像是只读的,VM 本身完全无状态:除上传到 Google Cloud Storage 的 UI 产物与 GitHub 缓存外,不持久化任何状态;SSD 仅作为 scratch 盘用于 tmpfs/swap,每次重启即清空。

VM 的动态伸缩以ci.perfetto.devAppEngine 推送的 Stackdriver 自定义指标为成本函数,该指标即"排队中 + 运行中的 pull-request 数量"。

3.2 worker 容器层:VM 的"管家"

每台 GCE VM 上运行一个特权 Docker 容器worker。它负责 VM 的基础设置,除此之外不做任何事——只通过 supervisord 确保始终有 N 个 sandbox 在运行。worker 容器是特权容器,但注释明确说明:它不是用于隔离的(隔离是 sandbox 的职责),只是便于部署

3.3 sandbox 容器层:真正执行 GitHub Action Runner

每个 sandbox 容器运行一个 GitHub Action Runner 实例,构建与测试都在 Action Runner 内完成。sandbox 运行在受限网络与受限服务账号下,是安全边界所在(详见第六节)。

3.4 服务账号划分

账号使用方权限
gce-ci-worker@perfetto-ci.iam.gserviceaccount.comGCE VM 与特权 worker 容器云平台基础权限(见GCE_SCOPES
gce-ci-sandbox@perfetto-ci.iam.gserviceaccount.comsandbox 容器仅允许创建(不可删除/覆盖)gs://perfetto-ci-artifacts中的产物

这一设计确保即使 sandbox 被攻破,攻击者也无法覆盖或删除已有 CI 产物。

四、从开机到测试运行的完整链路(Sequence Diagram)

原文档给出的启动序列如下(左侧为层次,右侧为实际执行的脚本/工作流):

make -C /infra/ci start-workers ┗━ gcloud start ... [GCE] # From /infra/ci/worker/gce-startup-script.sh docker run worker ... [worker] # From /infra/ci/worker/Dockerfile ┗━ /infra/ci/worker/worker_entrypoint.sh ┗━ supervisord ┗━ [N] /infra/ci/worker/sandbox_runner.py ┗━ docker run sandbox-N ... [sandbox-X] # From /infra/ci/sandbox/Dockerfile ┗━ /infra/ci/sandbox/sandbox_entrypoint.sh ┗━ github-action-runner/run.sh ┗━ .github/workflows/analyze.yml ┣━ .github/workflows/linux-tests.yml ┣━ .github/workflows/ui-tests.yml ... ┗━ .github/workflows/android-tests.yml

结合源码,可将每一层的关键实现展开如下:

1.make -C infra/ci start-workers(Makefile)Makefile 先通过include $(shell python3 config.py makefile)从 config.py 生成配置(这就是"所有变量只存一处"的设计),再依次执行:构建 GCE 实例模板(instance-templates create,注入startup-script-urlnum-workerssandbox-imgworker-img等 metadata,机器类型为c2d-standard-32,配 2 块 NVMe local SSD 与 100GB PD-SSD 启动盘)、创建托管实例组并配置 autoscaling。

2. GCE 启动脚本(gce-startup-script.sh)从 metadata server 拉取worker-img镜像名;将 NVMe 盘组 RAID0 并格式化为无日志 ext4(注释说明这是最快配置,-E nodiscard避免 TRIM 开销),挂载为/tmp作为构建/检出/缓存的 scratch 空间;关闭内核地址空间随机化kernel.randomize_va_space=0),因为新版内核会阻止 sandbox 内调用personality(ADDR_NO_RANDOMIZE),若不关闭则需把 sandbox 改为--privileged,从而破坏隔离初衷;最后以--privileged --net=host挂载 docker.sock 拉起 worker 容器。

3. worker 入口(worker_entrypoint.sh)从 metadata 读取num-workerssandbox-imgdocker pull最新 sandbox 镜像;创建名为sandbox的受限 bridge 网络,并用 iptables拒绝该网络访问169.254.0.0/16(GCE metadata server 网段),防止 sandbox 窃取 metadata 或模拟服务账号;随后生成 supervisord 配置,以numprocs=${NUM_WORKERS}启动 N 个sandbox_runner.py进程,并设置autorestart=true保证常驻。

4. sandbox 运行器(sandbox_runner.py)为每个 sandbox 分配GCE_HostName-N名称;通过gcloud auth application-default print-access-token --impersonate-service-account=为沙箱生成1 小时短时效的降权令牌create_sandbox_token,且每 50 分钟刷新一次);向 GitHub 申请注册令牌后,docker run启动嵌套 sandbox 容器:--cap-add SYS_PTRACE(供调试工具使用)、--network sandbox --dns 8.8.8.8、将/tmp/sandbox-N以 tmpfs 方式挂载为容器内/tmp,并通过环境变量注入GITHUB_TOKEN_PATHSVC_TOKEN_PATH。脚本同时用/tmp/perfetto_ci_lastrun的 mtime 记录最近活动,供闲置关机决策使用。

5. sandbox 入口(sandbox_entrypoint.sh)github-action-runner复制到 tmpfs(因为 Action Runner 会在_work子目录检出仓库);以--unattended --ephemeral --replace模式注册一次性 Runner--ephemeral表示跑完一个 job 即退出);配置 gcloud 使用降权令牌文件;注册 SIGTERM 清理钩子(cleanup()中执行config.sh remove优雅摘除 Runner);最后后台运行./run.sh等待 job。

6. 作业执行Runner 被 GitHub 分配任务后执行 analyze.yml,再按变更分类扇出上节列出的各测试工作流。

五、核心配置参数一览(infra/ci/config.py)

所有 CI 相关变量集中定义在 infra/ci/config.py,既被 Python 脚本 import,也可用python3 config.py makefile生成 Makefile 片段(config.mk),或python3 config.py js生成前端使用的 JSON。关键参数如下:

参数说明
GITHUB_REPOgoogle/perfetto关联的 GitHub 仓库
GITHUB_APP_ID/GITHUB_APP_INSTALLATION_ID1184402/62928975用于以 GitHub App 身份申请 Runner 注册令牌
PROJECTperfetto-ciGoogle Cloud 项目 ID
SANDBOX_IMG/WORKER_IMGus-docker.pkg.dev/perfetto-ci/containers/gh-sandbox/gh-worker容器镜像仓库地址
CI_SITEhttps://ci.perfetto.dev前端控制台
GCS_ARTIFACTSperfetto-ci-artifacts产物桶名
JOB_TIMEOUT_SEC/CL_TIMEOUT_SEC45 * 60/3h单 job / 单 change-list 超时
LOGS_TTL_DAYS15日志保留时长
TRUSTED_EMAILS^.*@google.com$可信提交者邮箱正则
GCE_REGIONSus-west1部署区域
GCE_VM_TYPEc2d-standard-32VM 机器类型(32 vCPU 计算优化型)
MAX_VMS_PER_REGION8每区域 VM 上限
NUM_WORKERS_PER_VM4每台 VM 上的 sandbox 数量
AUTOSCALER_MIN0可缩容至零(闲置成本为零)
SANDBOX_SVC_ACCOUNTgce-ci-sandbox@perfetto-ci.iam.gserviceaccount.comsandbox 降权账号

Makefile 中的 autoscaling 配置同样值得注意:实例组以 Stackdriver 自定义指标custom.googleapis.com/perfetto-ci/ci_job_queue_len为利用率信号,目标值为 0.1(gauge 类型),冷却期 60 秒——队列越长,扩的 VM 越多。

六、日常运维 Playbook

6.1 前端(JS/HTML/CSS/py)变更

  • 本地测试:make -C infra/ci/frontend test
  • 部署:make -C infra/ci/frontend deploy

前端位于 infra/ci/frontend/,内含 AppEngine 配置(app.yamlcron.yamlindex.yaml)、main.py、stackdriver_metrics.py(推送扩缩容指标)等。

6.2 Worker / Sandbox 变更

  1. 构建并推送新的 Docker 容器:
    make -C infra/ci build push

    build依次构建 worker 与 sandbox 镜像(构建前会把config.pycommon_utils.py复制进构建上下文),push推送至us-docker.pkg.dev(若推送失败,Makefile 提示先执行gcloud auth configure-docker us-docker.pkg.dev)。

  2. 重启 GCE 实例组(手动或执行):
    make -C infra/ci restart-workers

    该目标等价于stop-workers start-workers:先删除托管实例组,再重新创建并配置自动扩缩容。

其余辅助目标:start-workers(含gce-template依赖,重建实例模板并创建实例组)、stop-workersautoscaler-debug(查看当前扩容状态)、start-worker-for-testing/stop-worker-for-testing(测试用单 VM)、cli(交互式调试客户端)。

七、安全设计考量

原文档明确列出并逐一论证了这套 CI 的安全模型,核心要点如下:

  • gs://perfetto-ci-artifacts全局可读,但仅 GAE 与 GCE 服务账号可写;sandbox 账号只可创建、不可删除或覆盖。
  • 该项目中没有任何账号拥有值得一提的特权:worker 与 sandbox 服务账号在 CI 项目之外无任何特殊能力,即便被攻破,能做的事情也不会超过自己另开一个 GCP 项目。
  • 该 CI只做功能与性能测试,不涉及任何形式的持续部署;GitHub Actions 仅对perfetto-teamperfetto-contributors自动触发。
  • sandbox 并不难逃逸(Docker 是唯一边界),因此 pre-submit 与 post-submit 的构建产物均不被视为可信,只用于功能正确性与性能回归判定。
  • CI 构建出的二进制不会在 CI 项目之外的任何机器上运行,也刻意不推送至 GCS
  • 唯一被保留(最长 30 天)并上传至 GCS 桶的构建产物是UI 产物,目的仅为获得 HTML 变更的可视化预览;且这些 UI 产物通过 GCS per-bucket API 从与生产 UI 不同的源提供服务,避免与生产环境共享 origin。

从代码实现上看,这些设计均有落地:sandbox 网络被 iptables 阻断 metadata server(worker_entrypoint.sh)、沙箱令牌为 1 小时降权短令牌且定期刷新(sandbox_runner.py)、GCE 启动脚本关闭 ASLR 以免被迫给 sandbox 提权(gce-startup-script.sh)。

八、总结与延伸阅读

Perfetto CI 的核心设计哲学可以概括为:调度与执行分离、执行资源完全无状态、权限按层收敛、成本随队列弹性伸缩。GitHub Actions 负责按变更分类扇出任务,GCE 自托管 Runner 以"VM 只读无状态 + worker 管家 + 一次性 sandbox"的三层结构承载构建测试,而 AppEngine 前端则以任务队列长度驱动 Autoscaler 在 0~8 台 VM 之间伸缩。

如需进一步了解 Perfetto 的测试策略与相关实现,可继续阅读仓库内的以下资源:

  • 测试策略总览:docs/contributing/testing.md(原文档指定入口)
  • CI 入口工作流:.github/workflows/analyze.yml
  • 各测试工作流:.github/workflows/(linux-tests、ui-tests、android-tests、bazel-tests、fuzzer-tests、rust-sdk-tests、bigtrace-tests 等)
  • CI 源码:infra/ci(含 config.py、Makefile、worker/sandbox 容器源码)
  • GCS 缓存 Action:.github/actions/cache-on-google-cloud-storage/(自托管 runner 无法使用 GitHub 自带 cache 时的 GCS 缓存方案)

【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 1:13:30

IDEA中输出SQL的完整指南:从MyBatis日志到Druid监控

我经常遇到这样的咨询:项目跑起来了,接口也通了,但控制台就是看不到SQL;或者MyBatis把SQL和参数分两行打印,想复制到Navicat里直接跑,还得手动替换那一堆问号;还有人用的是JPA,开了s…

作者头像 李华
网站建设 2026/9/19 1:13:28

Agent技能层:决定LLM应用上限的关键工程实践

Agent技能层,才是决定LLM应用上限的关键做Agent开发这两年多,我最大的感触是:模型选型固然重要,但真正决定一个Agent能干什么、干得稳不稳的,其实是中间那层技能层(agent-skills)的工程设计。同…

作者头像 李华
网站建设 2026/9/19 1:13:26

Zabbix 7.4 + Rocky Linux 9.6 SNMP监控全链路实战指南

1. 项目概述:Zabbix如何真正“看懂”设备——从被动接收走向主动理解SNMP数据Zabbix获取客户端的SNMP数据,不是简单地把一个IP填进监控界面就完事。它是一整套设备语言翻译系统:Zabbix是那个坐在监控室里的资深工程师,SNMP是设备厂…

作者头像 李华
网站建设 2026/9/19 1:13:23

Git命令行与GUI双线实战:安装配置、分支管理与排错

1. 命令行与图形界面到底该选谁:先搞清使用场景刚上手版本控制的人,几乎都会在同一个岔路口停下来:一边是黑底白字的终端,git status、git commit敲下去,输出一屏信息看得心里发虚;另一边是各种图形客户端&…

作者头像 李华
网站建设 2026/9/19 5:15:14

STM32智能鱼缸:本地闭环控制与微信小程序物联网设计

简介:这是一份面向嵌入式物联网学习者及课程设计、毕业设计需求者的项目文档,围绕基于STM32的智能鱼缸系统与配套微信小程序展开。资源以单个PDF交付,压缩包约42.7MB,正文系统梳理了以STM32F103RCT6为主控的硬件方案,涵…

作者头像 李华
网站建设 2026/9/19 5:15:57

PHP与Python:Web开发语言对比与技术选型指南

1. 语言背景与定位差异PHP和Python作为两种主流的服务器端编程语言,各自有着截然不同的发展轨迹和应用场景。PHP最初由Rasmus Lerdorf于1994年创建,设计初衷是为了管理个人主页(Personal Home Page),后来逐渐演变成专业…

作者头像 李华