Prow 是 Kubernetes 社区开源的 CI/CD 框架,在 eBay Tess 平台中被深度定制化部署,成为整个平台 CI/CD 流水线的神经中枢。本文将从架构设计出发,逐一剖析 Prow 的核心组件、PR 完整生命周期流转,并结合 eBay test-infra 仓库的实际配置,说明各组件在 cluster 908(tessprow 集群)上的部署位置与职责边界。
整体架构:服务集群 vs 构建集群
Prow 采用双集群架构,职责严格分离:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ┌──────────────────────────────────────────────────────────────────┐ │ GitHub Enterprise │ │ (github.corp.ebay.com) │ │ │ │ │ Webhook Events / API calls │ └────────────────────────┬─────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────┐ │ Service Cluster (cluster 908 / tessprow) │ │ │ │ Hook → Plank/ProwControllerManager → Tide → Crier │ │ Deck Horologium Sinker GHProxy Manual-Trigger │ │ GIS-Approve (eBay-specific) │ │ │ │ Creates ProwJob CRDs, schedules Pods │ └──────────────────────────────┬───────────────────────────────────┘ │ ┌───────────────┼──────────────────┐ ▼ ▼ ▼ Build Cluster 1 Build Cluster 2 ...more (default/trusted) (rules-k8s) CI clusters Runs Pods Runs Pods kind/e2e jobs
|
Service Cluster(服务集群):运行所有 Prow 控制面组件,处理 GitHub 事件,管理 ProwJob CRD,不直接运行测试 Pod。
Build Cluster(构建集群):只运行 Prow 调度过来的 Pod,实际执行 CI 测试、构建任务。
在 eBay 内部,service cluster 对应的是 cluster 908,其中 Prow 组件统一部署在 tessprow 命名空间(eBay 自定义)以及 default 命名空间(上游兼容)。
test-infra 仓库结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| test-infra/ # eBay fork of kubernetes/test-infra ├── config/ │ ├── prow/ │ │ ├── config.yaml # Prow 主配置(plank/deck/sinker/tide) │ │ ├── plugins.yaml # 插件配置(approve/trigger/owners等) │ │ └── cluster/ # K8s 部署清单(56 个 manifest 文件) │ │ ├── hook_deployment.yaml │ │ ├── deck_deployment.yaml │ │ ├── tide_deployment.yaml │ │ ├── crier_deployment.yaml │ │ ├── sinker_deployment.yaml │ │ ├── horologium_deployment.yaml │ │ ├── ghproxy.yaml │ │ ├── gis-approve-deploy-svc.yaml # eBay 专属组件 │ │ └── monitoring/ # Prometheus + Grafana + AlertManager │ └── clusters/ │ └── k8s-prow/ │ └── cluster-configuration.tf # GKE 集群 Terraform ├── prow/ # Prow 核心源码 │ ├── cmd/ # 各组件入口 │ │ ├── hook/ │ │ ├── plank/ │ │ ├── deck/ │ │ ├── tide/ │ │ ├── sinker/ │ │ ├── crier/ │ │ ├── horologium/ │ │ ├── pipeline/ # Tekton 集成(含 TrustFabric 改造) │ │ └── manual-trigger/ # eBay 自定义:手动触发器 │ └── kube/ │ └── cluster.go # TrustFabric 认证集成 ├── images/ # CI 工具镜像 │ ├── git/ # git + github known hosts │ └── git-custom-k8s-auth/ # git + AWS IAM + GKE auth └── docs/ └── playbooks/prow.md # 运维手册
|
核心组件深度剖析
1. Hook —— 事件入口网关
职责:接收 GitHub Webhook 事件,分发给各 Plugin 处理。
部署位置:default 命名空间,4 副本(高可用)
1 2 3 4 5 6 7 8
| spec: replicas: 4 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 1
|
处理流程:
1 2 3 4 5 6 7 8 9 10 11
| GitHub Webhook │ ▼ Hook(:8888) │ 验证 HMAC 签名(hmac-token Secret) ├─► trigger plugin → 创建 ProwJob(PR comment "/test all") ├─► approve plugin → 管理 /approve 标签 ├─► lgtm plugin → 管理 /lgtm 标签 ├─► label plugin → 管理 PR 标签 ├─► size plugin → 计算 PR 大小 └─► ... 40+ plugins
|
eBay 定制:Hook 连接的是内部 GitHub Enterprise(github.corp.ebay.com/api/v3),并通过 --github-endpoint=http://ghproxy 将请求经由 GHProxy 缓存转发,减少直接 API 调用消耗。
Hook 通过 KUBECONFIG 环境变量同时挂载多个集群的 kubeconfig,实现跨集群 ProwJob 调度:
1 2 3 4 5 6
| env: - name: KUBECONFIG value: "/etc/kubeconfig/config:\ /etc/kubeconfig-build-test-infra-trusted/kubeconfig:\ /etc/kubeconfig-build-k8s-prow-builds/kubeconfig:\ /etc/kubeconfig-build-rules-k8s/kubeconfig"
|
2. Plank / ProwControllerManager —— 任务调度器
职责:监听 ProwJob CRD,创建 Pod 到对应 build cluster 并同步状态。
部署位置:default 命名空间
核心逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ProwJob CRD(created by Hook/Horologium/Tide) │ ▼ ProwControllerManager │ 读取 .spec.cluster 字段确定目标集群 │ 读取 decoration config 注入 utility containers ├─► 创建 Pod 到 build cluster │ ├── initupload (init container: 上传起始元数据) │ ├── clonerefs (init container: clone 代码) │ ├── place-entrypoint (init container: 安装 entrypoint) │ ├── test-container (用户定义的测试逻辑) │ └── sidecar (sidecar: 收集日志 + 上传 GCS) │ └─► 更新 ProwJob 状态(Pending → Running → Success/Failure)
|
Decoration Config(config.yaml 中配置):
1 2 3 4 5 6 7 8 9 10 11 12 13
| plank: default_decoration_config_entries: - config: timeout: 2h grace_period: 15m utility_images: clonerefs: "gcr.io/k8s-prow/clonerefs:v20230125-c8bfad3373" initupload: "gcr.io/k8s-prow/initupload:v20230125-c8bfad3373" entrypoint: "gcr.io/k8s-prow/entrypoint:v20230125-c8bfad3373" sidecar: "gcr.io/k8s-prow/sidecar:v20230125-c8bfad3373" gcs_configuration: bucket: "kubernetes-jenkins" path_strategy: "legacy"
|
3. Deck —— Web 仪表盘
职责:提供 Prow Web UI,展示 ProwJob 历史、Spyglass 日志查看、PR 状态。
部署位置:default 命名空间,3 副本
1 2 3 4 5 6
| args: - --tide-url=http://tide/ - --hook-url=http://hook:8888/plugin-help - --spyglass=true - --rerun-creates-job - --github-endpoint=http://ghproxy
|
Spyglass 功能:内嵌日志查看器,支持:
metadata lens:展示 started.json / finished.json
buildlog lens:高亮错误(支持 DATA RACE、Fatal Error 等正则)
coverage lens:代码覆盖率可视化
Deck 通过 --rerun-creates-job 允许用户在 UI 中一键重新触发失败的 ProwJob。
4. Tide —— 自动合并控制器
职责:监控所有 PR 的标签状态,自动 retest + merge 满足条件的 PR。
部署位置:default 命名空间,单副本(必须,避免并发 merge 冲突)
1 2 3 4
| spec: replicas: 1 strategy: type: Recreate
|
合并决策流程:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 每隔 ~1min 同步一次:
Tide 轮询所有配置的 GitHub 仓库 │ ▼ 对每个 PR 检查: ✓ 是否满足 merge 条件(labels: lgtm + approved + !do-not-merge) ✓ 是否通过所有 required status checks ✓ base branch 是否是最新 │ ├─► 条件满足 → 触发 merge(single or batch) ├─► 缺少测试结果 → 创建 batch ProwJob 重跑 └─► 落后 base → 需要 rebase
|
Tide 的状态持久化到 GCS:
1 2
| --history-uri=gs://k8s-prow/tide-history.json --status-path=gs://k8s-prow/tide-status-checkpoint.yaml
|
5. Horologium —— 定时任务调度器
职责:触发 periodic 类型的 ProwJob(cron 触发,不依赖 GitHub 事件)。
部署位置:default 命名空间
periodic job 示例:
1 2 3 4 5 6 7 8 9
| periodics: - name: ci-kubernetes-e2e-gce interval: 2h spec: containers: - image: gcr.io/k8s-prow/kubekins-e2e:latest args: - --repo=k8s.io/kubernetes - --test=true
|
Horologium 读取 config.yaml 中所有 periodics 配置,按 interval 或 cron 表达式精确触发。
6. Sinker —— 垃圾清理器
职责:定期清理过期的 ProwJob 和 Pod,防止集群资源堆积。
部署位置:default 命名空间
1 2 3 4 5 6
| sinker: resync_period: 1m max_prowjob_age: 48h max_pod_age: 48h terminated_pod_ttl: 30m
|
7. Crier —— 状态报告器
职责:将 ProwJob 状态回报到 GitHub(commit status / check run)、Slack 等渠道。
部署位置:default 命名空间
1 2 3 4 5 6 7
| ProwJob 状态变更(Pending/Running/Success/Failure) │ ▼ Crier ├─► GitHub Status API(绿色 ✓ / 红色 ✗) ├─► GitHub Check Runs(更详细的 UI) └─► Slack 通知(失败时)
|
Crier 从 ProwJob 的 .spec.reporter_config 中读取各渠道配置,实现多目标状态同步。
8. GHProxy —— GitHub API 缓存代理
职责:缓存对 GitHub API 的请求,防止触发 Rate Limit,并提升响应速度。
部署位置:default 命名空间(build cluster 也有部署)
1 2 3 4
| Prow 组件 → http://ghproxy → github.corp.ebay.com/api/v3 ↑ HTTP Cache(304 Not Modified 优化) Rate Limit 统计与监控
|
所有组件(Hook、Tide、Deck、Crier)都通过 --github-endpoint=http://ghproxy 路由 GitHub API 请求。
9. GIS-Approve —— eBay 专属审批组件
职责:eBay 内部自动化审批机器人,满足条件时自动 /approve PR。
部署位置:tessprow 命名空间(eBay 专属)
1 2 3 4 5 6 7 8 9 10
| metadata: namespace: tessprow spec: containers: - args: - --github-host=github.corp.ebay.com - --login-user=tess-bot - --login-mail=DL-eBay-tess-ci@ebay.com image: hub.tess.io/k8s-prow/gis-approve:v2
|
Bot 账号:tess-bot(tess-ci@ebay.com)
10. Manual-Trigger —— 手动触发器(eBay 扩展)
职责:提供 HTTP API 接口,允许用户绕过 GitHub 事件直接触发 ProwJob。
部署位置:tessprow 命名空间,通过 http://manual-trigger.tessprow 访问
1 2 3 4 5 6 7 8 9 10
| curl -X POST \ "http://manual-trigger.tessprow/manual-trigger?\ org=tess&repo=tessops&base_ref=master\ &prowtype=postsubmit&prowjob=sddz-e2e-k8s-1.32"
curl -X POST "http://manual-trigger.tessprow/manual-trigger" \ -H "Content-Type: application/json" \ -d '{"org":"tess","repo":"tessops","pull_number":123,"prowjob":"unit-test"}'
|
典型使用场景:
- CI 集群故障后手动补跑失败 job
- 针对特定 commit 触发部署验证
- 运维操作中的一次性任务触发
PR 完整生命周期:从提交到合并
以一个典型的 presubmit 流程为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| ┌─────────────────────────────────────────────────────────────────┐ │ 1. Developer opens PR on github.corp.ebay.com │ │ → GitHub sends webhook to Hook │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 2. Hook receives pull_request event │ │ trigger plugin: checks plugins.yaml for presubmit jobs │ │ → creates ProwJob CRD (type: presubmit) │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 3. ProwControllerManager picks up ProwJob │ │ → determines target build cluster (.spec.cluster) │ │ → injects utility init containers (clonerefs, initupload) │ │ → creates Pod in build cluster │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 4. Pod runs in build cluster │ │ init: clonerefs → clone PR branch + base branch │ │ init: place-entrypoint → install wrapper │ │ main: test container runs actual CI script │ │ sidecar: stream logs to GCS, await exit │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 5. Crier reports status back to GitHub │ │ → GitHub PR shows ✓ or ✗ on commit status │ │ → Deck Spyglass shows full log via GCS link │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 6. Reviewer adds /lgtm and /approve │ │ Hook approve plugin: sets "approved" label │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 7. Tide detects PR: lgtm ✓ + approved ✓ + CI ✓ │ │ → optionally retests to ensure base is latest │ │ → merges PR (or batch-merges with other ready PRs) │ └─────────────────────────────────────────────────────────────────┘
|
eBay Tess 平台特殊定制
TrustFabric 认证
标准 Prow 使用 kubeconfig 文件进行 K8s API 认证。eBay 在 prow/kube/cluster.go 和 prow/cmd/pipeline/main.go 中集成了 TrustFabric(eBay 内部 SPIFFE/mTLS 认证框架),允许在 Go >= 1.18 的运行时中通过工作负载身份(Workload Identity)直接认证 K8s API Server,无需静态 kubeconfig。
GitHub Enterprise 适配
所有组件连接的是内部 GitHub Enterprise,通过统一配置:
1 2 3 4
| github_host: github.corp.ebay.com github_endpoint: https://github.corp.ebay.com/api/v3 github_graphql_endpoint: https://github.corp.ebay.com/api/graphql
|
内部镜像 Registry
所有基础镜像从 hub.tess.io 拉取,避免依赖外部 registry:
1 2 3 4
| baseImageOverrides: gcr.io/distroless/static: hub.tess.io/tess/alpine:hardened
|
组件在 Cluster 908 上的部署位置总览
Cluster 908 是 eBay Tess 平台的 Prow 服务集群,对应上文中的 service cluster。以下是各组件的完整部署位置:
| 组件 |
命名空间 |
Manifest 文件 |
副本数 |
说明 |
| Hook |
default |
hook_deployment.yaml |
4 |
高可用 Webhook 接收 |
| Deck |
default |
deck_deployment.yaml |
3 |
Web UI,滚动升级 |
| Tide |
default |
tide_deployment.yaml |
1 |
严禁扩容,Recreate 策略 |
| Horologium |
default |
horologium_deployment.yaml |
1 |
Periodic job 调度 |
| Sinker |
default |
sinker_deployment.yaml |
1 |
垃圾回收 |
| Crier |
default |
crier_deployment.yaml |
1 |
状态报告 |
| ProwControllerManager |
default |
prow_controller_manager_deployment.yaml |
1 |
取代 Plank 的新控制器 |
| Pipeline |
default |
pipeline_deployment.yaml |
1 |
Tekton 集成 |
| CherryPicker |
default |
cherrypicker_deployment.yaml |
1 |
自动 cherry-pick |
| GHProxy |
default |
ghproxy.yaml |
1 |
GitHub API 缓存 |
| Halogen |
default |
halogen.yaml |
1 |
日志高亮服务 |
| GIS-Approve |
tessprow |
gis-approve-deploy-svc.yaml |
1 |
eBay 专属审批 Bot |
| Manual-Trigger |
tessprow |
(独立部署) |
1 |
eBay 专属手动触发 |
| Kube-State-Metrics |
default |
kube-state-metrics_deployment.yaml |
1 |
监控指标采集 |
| Prometheus |
monitoring |
monitoring/ |
1 |
指标存储 |
| Grafana |
monitoring |
monitoring/ |
1 |
可视化仪表盘 |
| AlertManager |
monitoring |
monitoring/ |
1 |
告警路由 |
关键区别:
- 上游标准组件部署在
default 命名空间
- eBay 自研/定制组件部署在
tessprow 命名空间(隔离管理,便于权限控制)
Monitoring 体系
config/prow/cluster/monitoring/ 目录下有 28 个监控配置文件,构建完整的可观测性栈:
1 2 3 4 5 6 7
| monitoring/ ├── prometheus_deployment.yaml # Prometheus 主实例 ├── prometheus_rbac.yaml ├── grafana_deployment.yaml # Grafana 可视化 ├── alertmanager_*.yaml # AlertManager 告警 ├── *_servicemonitor.yaml # 各组件的 ServiceMonitor └── *_podmonitor.yaml # Pod 级别监控
|
关键监控指标:
- ProwJob CRD 数量(按 type/state/cluster 分组)→ 检测积压
- GitHub API Rate Limit(via GHProxy)→ 防止限流
- Tide merge 速率→ 检测 merge 停滞
- Build cluster Pod 资源使用→ 容量规划
小结
Prow + test-infra 构成了 eBay Tess CI/CD 的完整基础设施:
- Hook 是事件驱动的入口,通过 Plugin 体系扩展性强
- ProwControllerManager 实现跨集群的 Pod 调度,是核心任务引擎
- Tide 的批量合并能力显著提升大规模代码库的吞吐
- eBay 定制层(TrustFabric + GIS-Approve + Manual-Trigger)在不破坏上游兼容性的前提下满足了企业级需求
- Cluster 908(tessprow)上,标准组件跑在
default 命名空间,eBay 扩展组件隔离在 tessprow 命名空间,职责清晰
理解这套架构后,无论是排查 CI 失败、新增 Plugin 功能、还是扩展构建集群,都能找到明确的代码路径和配置入口。