# BuildfarmDeployment **Repository Path**: xiaonqedu/buildfarm-deployment ## Basic Information - **Project Name**: BuildfarmDeployment - **Description**: 基于 Buildfarm 的 Bazel 远程构建实验环境,提供 Go 示例及部署脚本,集成 OpenTelemetry、Jaeger、Prometheus 和 Grafana,支持远程构建验证、调用链追踪与构建耗时分析 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-28 - **Last Updated**: 2026-10-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # BuildfarmDeployment 本项目用于在本机搭建最小 Buildfarm 集群,通过 Go + Bazel 示例验证远程构建,并使用 OpenTelemetry、Jaeger、Prometheus、Grafana 排查构建耗时 **服务端:Buildfarm;客户端:bazel-example;监控配置:deployment/observability** 这是 Linux/amd64 单机验证环境,配置中的 `127.0.0.1` 和本地存储不适用于直接部署生产集群 ## 1. 服务与数据流 | 服务 | 运行方式 | 本机端口 | 作用 | | --- | --- | --- | --- | | Redis | Docker,7.2.4 | 16379 | 保存任务队列、状态、Worker 注册和文件位置等元数据 | | Buildfarm Server | 本机 Java 进程 | 18980;指标 19090 | 接收 Bazel 请求,协调任务和返回结果 | | CAS Worker | 本机 Java 进程 | 18981;指标 19091 | 保存构建输入文件、输出产物 | | Execution Worker | 本机 Java 进程 | 18982;指标 19092 | 获取任务和输入,执行编译、链接、测试 | | OpenTelemetry Collector | Docker | 4317 / 4318 | 接收调用链,批量转发到 Jaeger | | Jaeger | Docker | 16686 | 保存、查询调用链,并生成 Span 指标 | | Prometheus | Docker | 9091 | 采集并保存指标 | | Grafana | Docker | 3000 | 展示指标和调用链 | Java Agent 加载在三个 Buildfarm Java 进程内部,不是独立服务 ```text 构建:Bazel → Server → Redis 任务队列 → Execution Worker Server、Execution Worker ↔ CAS Worker(输入和输出文件) 链路:Java Agent / trace-build.py → Collector → Jaeger → Jaeger 页面或 Grafana 指标:Buildfarm 原生指标 + Jaeger Span 指标 + Collector 指标 → Prometheus → Grafana ``` ## 2. 目录与核心配置 ```text BuildfarmDeployment/ ├── Buildfarm/ # Buildfarm 源码,独立的 Bazel 工作区 ├── bazel-example/ # 客户端示例:共用一个 Bazel 工作区和 Go 模块 │ ├── .bazelversion # 固定 Bazel 9.0.0 │ ├── .bazelrc # 构建参数、Buildfarm 地址和实例名 │ ├── MODULE.bazel # 构建规则、Go SDK 和依赖接入 │ ├── go.mod # Go 模块、版本和依赖 │ ├── go-demo/ # hello 程序和测试,业务 BUILD 定义构建目标 │ ├── go-demo2/ # goodbye 程序和测试 │ └── trace-build.py # 记录构建总 Span,关联远程 RPC 并输出查询链接 └── deployment/ ├── config/ │ ├── server.yml # Redis 地址、Server 端口、实例名 shard │ ├── cas.yml # CAS 能力、数据目录、20 GiB 文件缓存 │ └── exec.yml # 执行能力、并发数 2、10 GiB 本地文件缓存 ├── data/ # Redis、CAS、执行 Worker 的运行数据,不提交 Git ├── logs/ # Buildfarm 运行日志,不提交 Git ├── distdir/ # 可选的依赖下载包缓存 └── observability/ ├── compose.yml # 统一定义四个监控容器、端口和数据卷 ├── start.sh # 启动监控容器,重启 Buildfarm 并加载 Agent ├── opentelemetry/ # Agent、进程管理脚本、Collector 和 Jaeger 配置 ├── prometheus/ # 指标采集和告警规则 ├── grafana/ # 账号、数据源和仪表盘配置 └── examples/ # 备用配置,默认不启动 ``` [客户端示例说明](bazel-example/README.md) · [监控部署说明](deployment/observability/README.md) ## 3. 首次准备 需要 Docker、Docker Compose、Python 3、Bazelisk;Buildfarm 使用 Bazel 9.0.0 和 JDK 21,当前配置由 Bazel 获取 Java 工具链 Go SDK 由示例的 Bazel 配置管理,不要求另装系统 Go 当前部署路径为 `/home/qcraft/PycharmProjects/BuildfarmDeployment`;换目录时,先修改 `cas.yml`、`exec.yml` 中的绝对 `worker.root` 路径 **未编译过 Buildfarm 时执行一次,已有产物可跳过:** ```bash cd /home/qcraft/PycharmProjects/BuildfarmDeployment/Buildfarm bazelisk --output_user_root=/home/qcraft/.cache/bazel-buildfarm-deployment build \ //src/main/java/build/buildfarm:buildfarm-server \ //src/main/java/build/buildfarm:buildfarm-shard-worker ``` 编译成功会生成 `Buildfarm/bazel-bin/src/main/java/build/buildfarm/` 下的 Server 和 Worker 启动程序 缓存根目录放在 `/home/qcraft/.cache/`,避免与当前 Buildfarm 沙箱的 `/tmp` 挂载配置冲突 还需准备 Java Agent **2.14.0**,从 [官方发布页](https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/tag/v2.14.0) 下载 `opentelemetry-javaagent.jar`,放入 `deployment/observability/opentelemetry/`;当前机器已准备,该 JAR 不提交 Git **Redis 容器尚未创建时执行一次:** ```bash cd /home/qcraft/PycharmProjects/BuildfarmDeployment mkdir -p deployment/data/{redis,cas,exec} deployment/logs docker run -d --name bf-lab-redis \ -p 127.0.0.1:16379:6379 \ -v /home/qcraft/PycharmProjects/BuildfarmDeployment/deployment/data/redis:/data \ redis:7.2.4 redis-server --appendonly yes ``` 已有 `bf-lab-redis` 容器时,不要重复 `docker run`,直接执行下一步 ## 4. 启动服务 等待正在执行的构建结束;脚本可识别本项目通过绝对或相对配置路径启动的 Buildfarm 进程,手动启动的进程也会被重启 ```bash cd /home/qcraft/PycharmProjects/BuildfarmDeployment # 先启动已有 Redis 容器 docker start bf-lab-redis docker exec bf-lab-redis redis-cli ping ``` 确认返回 `PONG` 后再执行: ```bash # 启动监控容器,并依次启动加载 Agent 的 CAS、执行 Worker、Server bash deployment/observability/start.sh # 检查四个监控容器是否为 Up docker-compose -p bf-otel -f deployment/observability/compose.yml ps ``` `start.sh` 首次生成 Grafana 账号配置,随后启动监控容器,并重启三个 Buildfarm Java 进程;Redis 不由该脚本启动 Buildfarm 在后台运行,日志位于 `deployment/logs/cas-otel.log`、`exec-otel.log`、`server-otel.log` 本文使用当前机器的 `docker-compose` 命令;使用 Compose V2 时替换为 `docker compose` ## 5. 构建并查询调用链 ```bash cd /home/qcraft/PycharmProjects/BuildfarmDeployment/bazel-example python3 trace-build.py -- \ bazelisk build --config=buildfarm-lab \ //go-demo/cmd/hello:hello ``` 成功标志:`Build exit code: 0`,产物为 `bazel-bin/go-demo/cmd/hello/hello_/hello` 打开终端输出的 Jaeger 链接,或复制 **Trace ID** 到 Grafana 调用链面板 如需触发重新远程执行,先清理本地结果,再禁用远程结果缓存: ```bash bazelisk clean && \ python3 trace-build.py -- \ bazelisk build --config=buildfarm-lab --noremote_accept_cached \ //go-demo/cmd/hello:hello ``` 构建摘要应出现 `remote` 执行任务;仅添加 `--noremote_accept_cached` 不会清理本地缓存 无需删除 Redis、CAS 数据或执行 `clean --expunge` - 普通构建也可以直接执行 `bazelisk build --config=buildfarm-lab //go-demo/cmd/hello:hello` - 测试两个业务:`bazelisk test --config=buildfarm-lab //go-demo/... //go-demo2/...` - `trace-build.py` 创建构建总 Span,通过 `traceparent` 关联远程调用,记录耗时和退出码,不改变原有构建规则与缓存策略 - **Invocation ID** 是 Bazel 本次命令的标识;**Trace ID** 用于查链路;当前脚本尚未将 Invocation ID 写入 Span 属性 ## 6. 页面入口 | 页面 | 用途 | | --- | --- | | [Grafana 运行总览](http://127.0.0.1:3000/d/bf-otel-overview) | 看构建耗时、RPC 错误、队列、执行槽位和采集状态 | | [Grafana 调用链](http://127.0.0.1:3000/d/bf-otel-traces) | 输入 Trace ID,查看调用时间轴和关系图 | | [Jaeger](http://127.0.0.1:16686) | 按 Trace ID 或服务、时间、耗时、属性搜索链路 | | [Prometheus Targets](http://127.0.0.1:9091/targets) | 确认六个采集目标均为 UP | Grafana 用户名为 `admin`,在项目根目录查看本机密码: ```bash cd /home/qcraft/PycharmProjects/BuildfarmDeployment sed -n 's/^GF_SECURITY_ADMIN_PASSWORD=//p' deployment/observability/grafana/grafana.env ``` 上述 Grafana 链接对应仓库预置仪表盘;自行新建的仪表盘从 Dashboards 列表打开 手动配置链路面板时,在**同一个仪表盘**创建 Text box 变量 `trace_id`,再添加 Jaeger 数据源的 Traces 面板:查询类型选 `TraceID`,查询值填 `$trace_id` 真实 ID 填仪表盘的 Trace ID 输入框,不填 Grafana 全局搜索框 ## 7. 重启与停止 以下命令在项目根目录执行,按需要选择,不要整段连续运行 ```bash # 只重启监控容器;末尾可追加 grafana 等单个服务名 docker-compose -p bf-otel -f deployment/observability/compose.yml restart # 只重启本项目的三个 Buildfarm Java 进程,自动加载 Agent python3 deployment/observability/opentelemetry/buildfarm-services.py restart ``` 全部停止时,先等待构建结束,再按顺序执行: ```bash python3 deployment/observability/opentelemetry/buildfarm-services.py stop docker stop bf-lab-redis docker-compose -p bf-otel -f deployment/observability/compose.yml stop ``` `stop` 同样适用于按本文档手动启动的进程;也可在对应终端按 `Ctrl+C`,顺序为 Server → 执行 Worker → CAS `start` 仅启动服务;`restart` 先检查 Agent、可执行文件、配置、日志写入和 Redis 端口,再停止旧进程并启动 普通重启保留数据;不要执行 `down -v`,它会删除 Compose 数据卷 修改 Compose 的镜像、端口或挂载后用 `up -d` 应用,单纯 `restart` 不会更新容器定义 ## 8. 当前验证范围 - `buildfarm-lab` 将 Go 标准库准备放在本地,其余可远程执行的编译、链接和测试任务交给 Buildfarm,禁止失败后回退本地 - 缓存命中时没有重新编译,Trace 可能只有总 Span 和能力查询,这不代表监控故障 - Agent 尚未贯通 Redis 队列的 Trace 上下文,部分 Worker 调用会成为独立 Trace;不能据此宣称已覆盖完整 Action 生命周期 - Trace 的 206 个 Span 不代表 206 个 Action,嵌套和并行 Span 的耗时不能直接相加 - Jaeger 使用本地 Badger 数据卷保留 Trace 7 天;Prometheus 数据保留 15 天或 5 GB,以先达到的限制为准 - Grafana 预置仪表盘由 JSON 文件管理,页面修改不会自动写回文件;账号文件、运行数据和日志不提交 Git ## 9. 详细文档 以下为当前工作站上的详细操作记录,迁移到其他机器后需调整文档链接: - [01.Buildfarm部署.md]():环境准备、源码编译、服务配置及手动启动、Bazel 示例 - [02.OpenTelemetry.md]():Agent 原理、监控部署、手动接入及 Grafana / Jaeger 操作