在 eBay Tess 平台的 CI/CD 体系中,prow-images 和 tessops 是两个核心仓库,前者提供各类 CI 容器工具镜像,后者定义整个 K8s 集群的配置规格。理解它们的工作原理和协同方式,是深入参与 Tess 集群开发与维护的关键。本文将从整体架构出发,逐一拆解各核心组件,并重点介绍如何利用 tessops 作为集群配置源来搭建 K8s 集群。
整体架构概览 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ┌─────────────────────────────────────────────────────────────┐ │ Developer Workflow │ │ │ │ commit to tessops ──► Prow CI triggers ──► validates │ │ │ │ │ ┌───────────────▼──────────────┐ │ │ │ prow-images │ │ │ │ ┌────────┐ ┌────────────┐ │ │ │ │ │ kind │ │ e2e │ │ │ │ │ │ │ │ │ │ │ │ │ │ create │ │ apply tess-│ │ │ │ │ │ k8s │ │ ops specs │ │ │ │ │ │cluster │ │ & run tests│ │ │ │ │ └────────┘ └────────────┘ │ │ │ │ ┌────────┐ ┌────────────┐ │ │ │ │ │ bazel │ │ kaniko │ │ │ │ │ │ build │ │ img build │ │ │ │ │ └────────┘ └────────────┘ │ │ │ └───────────────────────────────┘ │ │ │ │ tessops (cluster config) ──► deployed to real clusters │ └─────────────────────────────────────────────────────────────┘
两个仓库分工明确:
prow-images :提供 CI/CD 流水线中使用的各类容器镜像(构建工具、测试框架、集群管理等)
tessops :定义 Tess 平台上 K8s 集群的完整配置规格(Salt 状态 + Releaser 模板)
prow-images 仓库解析 仓库结构 prow-images 包含约 46 个独立的 Docker 镜像目录,每个目录对应一个功能明确的工具镜像。镜像发布到内部 registry hub.tess.io/prowimages/。
1 2 3 4 5 6 7 8 9 10 11 12 prow-images/ ├── Makefile # 统一构建入口,32 个 image/push target ├── go.mod # Go module 依赖 ├── kind/ # Kubernetes-in-Docker 集群管理 ├── e2e/ # 端到端测试框架 ├── bazel/ # Bazel 构建系统 ├── golang/ # 多版本 Go 编译环境 ├── kaniko/ # 容器镜像构建 ├── git/ # Git 操作(含加密支持) ├── auto-approval/ # PR 自动审批 ├── helm-bot/ # Helm chart 管理 └── ...
Makefile 构建模式统一:
1 2 3 4 5 6 image-kind: docker build -t hub.tess.io/prowimages/kind:$(shell cat kind/VERSION) \ -f kind/Dockerfile . push-kind: docker push hub.tess.io/prowimages/kind:$(shell cat kind/VERSION)
版本由每个目录下的 VERSION 文件管理,当前 kind 镜像版本为 v0.0.13。
核心镜像详解 1. kind 镜像 — K8s 集群创建核心 功能 :在 Prow Job 容器内创建完整的 Kubernetes 集群,用于 E2E 测试。
Dockerfile 结构 (以 1.32.Dockerfile 为例):
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 FROM hub.tess.io/prowimages/golang:1.25 -latestWORKDIR /go/src/tess.io/contrib/prow-images ADD . /go/src/tess.io/contrib/prow-images RUN CGO_ENABLED=0 go install tess.io/contrib/prow-images/kind/entrypoint RUN git clone https://github.com/AGWA/git-crypt.git && \ cd git-crypt && make && make install FROM hub.tess.io/tess/alpine:hardened as ebay-certFROM gcr.io/k8s-staging-test-infra/krte:latest-1.32 ARG KIND_VERSION="v0.27.0" ARG KUBECTL_VERSION="v1.32.12" COPY --from=ebay-cert /etc/ssl/certs/* /etc/ssl/certs/ RUN apt update && apt install -yy net-tools COPY --from=0 /usr/bin/git-crypt /usr/bin/git-crypt COPY --from=0 /go/bin/entrypoint /entrypoint RUN curl -L ".../kind-linux-amd64" -o /usr/bin/kind && chmod +x /usr/bin/kind RUN curl -L ".../kubectl" -o /usr/bin/kubectl && chmod +x /usr/bin/kubectl RUN curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash ADD kind/config.toml /etc/containerd/config.toml ENTRYPOINT ["/entrypoint" ]
支持的 K8s 版本:1.23、1.28、1.32、1.34,每个版本对应一个独立 Dockerfile。
entrypoint(kind/entrypoint/main.go)的核心逻辑 :
1 2 3 4 5 6 7 1. 解析参数(--gpg-key, --repo-root, --script, --timeout 等) 2. 从 /credentials/githubtoken 读取 GitHub token 3. 若设置了 --wait-for,等待指定 GitHub Check 成功 4. 通过 git-crypt 解锁并 checkout 目标仓库 5. 若是 kubernetes-patches 仓库,还会 fetch 上游 K8s 源码并 apply patch 6. chdir 进入工作目录 7. 执行 bash -c <script>(实际的集群操作脚本)
kind node 镜像构建(build-node-image.sh) :
kind 集群的每个节点是一个 Docker 容器,节点镜像需要包含特定版本的 K8s 组件。build-node-image.sh 完成以下工作:
1 2 3 4 5 6 7 8 9 10 11 12 tag="${BASE_REF} -$(date +%Y%m%d) " tag="pr-${PULL_NUMBER} " kind build node-image --image=hub.tess.io/kindest/node:${tag} --type =source . docker build -t hub.tess.io/kindest/node:${tag} -f /tmp/Dockerfile . docker push hub.tess.io/kindest/node:${tag}
2. e2e 镜像 — 端到端测试编排 功能 :编排 E2E 测试,管理集群申请/释放生命周期,执行测试脚本。
entrypoint(e2e/entrypoint/main.go)核心流程 :
关键设计:即使测试失败,defer releaseCluster() 也确保集群被释放,避免资源泄露。
3. bazel 镜像 — 构建系统 基于官方 gcr.io/bazel-public/bazel:5.4.0,叠加:
eBay 内部 CA 证书(ebay.crt, certadmin.crt, ca.ebay.goskope.com.crt)
git-crypt(加密仓库支持)
crane(容器 registry 操作工具)
4. kaniko 镜像 — 无特权镜像构建 在 Prow Job(非特权容器)内构建 Docker 镜像,避免 Docker-in-Docker 的安全问题。
5. git 镜像 — 加密 Git 操作 专门处理 git-crypt 加密仓库的 clone/checkout,带 GitHub token 认证。
6. 自动化工具类镜像
镜像
功能
auto-approval
满足条件时自动 approve PR
auto-comment
在 PR 上自动发送评论
auto-security-pr
自动创建安全修复 PR
auto-validation
自动触发验证流程
autotag
自动打版本 tag
helm-bot
自动更新 Helm chart 依赖
prow-config-validator
验证 Prow 配置合法性
tessops 仓库解析 tessops 是 Tess 平台所有 K8s 集群的”配置真相来源”,采用 Salt(传统基础设施配置) + Releaser(云原生应用部署) 双轨架构。
目录结构 1 2 3 4 5 6 7 8 9 10 tessops/ ├── hrt/ # Host Runtime - 主机级配置(与 K8s 无关) ├── kubernetes/ # K8s 组件配置(etcd/apiserver/kubelet...) ├── addon/ # 废弃的 kube-addon-manager 管理的插件 ├── modules/ # 自定义 Salt 模块 ├── reactor/ # Salt 事件驱动自动化 └── releases/ # 现代化 Releaser 部署规格(主要使用这里) ├── templates/ # 88 个组件的 Go 模板 ├── values/ # 分层配置参数 └── kubectl.yaml # Releaser CRD 配置
Salt 配置层(hrt + kubernetes) Salt 负责节点级别的基础配置,在集群启动时由 Salt minion 执行:
hrt(Host Runtime Templating) :
1 2 3 4 5 6 hrt/ ├── pillar/<profile>/ # 环境参数(ci, dev, production...) └── salt/common/ ├── kernel-modules/ # 加载内核模块 ├── sssd/ # SSSD 认证配置 └── sysctl/ # 内核参数调优
kubernetes salt 环境 :
1 2 3 4 5 6 7 8 9 10 11 12 kubernetes/ ├── pillar/ │ ├── ci/ # CI 集群 pillar │ ├── production/ # 生产集群 pillar │ ├── testing/ │ └── ... # 共 14 个集群 profile └── salt/common/ ├── etcd/ # etcd 安装和配置 ├── apiserver/ # kube-apiserver 静态 manifest ├── kubelet/ # kubelet 配置和服务 ├── certs/ # 证书生成和管理 └── ...
Releases 配置层(核心) releases 是取代 addon 的现代化部署系统,使用 Releaser 控制器将 Go 模板渲染为 YAML 并 kubectl apply 到集群。
模板系统 releases/templates/ 下有 88 个组件目录,每个包含 K8s 资源的 Go 模板:
1 2 3 4 5 6 7 8 templates/ ├── 00-base/ # 集群基础资源(namespace, clusterrole, CRD) ├── 01-ebay-controller-manager/ # eBay 定制控制器 ├── 02-managed-cd/ # ArgoCD 管理的 CD 流程 ├── cilium-*/ # Cilium CNI 相关 ├── ai-adoption-controller/ ├── applicationinstance-status-controller/ └── ...(共 88 个组件)
模板语法示例:
1 2 3 4 5 6 7 8 9 10 11 replicas: {{if eq .cluster_type "ci" }}1 {{else }}3 {{end }}image: {{.tetragon_image | default "hub.tess.io/tess/tetragon:latest" }}username: {{.pillar_kube2udns_username }}config: '{{`{{.internalTemplate}} `}}'
值(Values)层次体系 这是 tessops 最精妙的设计:通过分层合并实现”通用默认 + 环境覆盖 + 集群精细化”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 releases/values/ ├── global/ # 所有集群的默认值(110+ 文件) ├── regions/<region>/ # 地域级覆盖 ├── zones/<zone>/ # 可用区级覆盖 ├── envs/<env>/ # 环境级覆盖(dev/staging/prod) ├── clustertypes/ │ ├── ci/ # CI 集群类型覆盖(50+ 配置项) │ ├── production/ │ ├── testing/ │ └── ... └── clusters/ ├── 11/ # 特定集群精细化配置 ├── 103/ └── ...(180+ 个具体集群)
优先级(从高到低) :
1 cluster > clustertypes > envs > zones > regions > global
CI 集群类型覆盖示例(values/clustertypes/ci/):
1 2 3 4 5 6 7 8 image_resource_requests_cpu: "0" image_resource_requests_memory: "0" force_best_effort: "true" account_hierarchy_admission: "enabled" cilium_env: "dev"
kubectl.yaml — Releaser 控制器配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 apiVersion: fleet.crd.tess.io/v1alpha1 kind: KubectlConfiguration spec: paths: - releases/templates/ valueTemplates: - configMapRef: pillars - secretRef: pillars prune: skip: - apiGroups: ["" ] resources: ["ConfigMap" ] namespaces: ["kube-system" ] ytt: releases/ytt.yaml
如何用 tessops 构建 K8s 集群 理解架构后,来看实际的集群构建流程。E2E 测试中的集群创建是最典型的使用场景。
Step 1:启动 kind 容器(Prow Job 配置) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 spec: containers: - image: hub.tess.io/prowimages/kind:v0.0.13-1.32 args: - --gpg-key=/credentials/git-crypt.key - --repo-root=/workspace - --script=/path/to/create-cluster.sh - --timeout=2h volumeMounts: - name: github-token mountPath: /credentials/githubtoken subPath: token - name: git-crypt-key mountPath: /credentials/git-crypt.key subPath: key
Step 2:entrypoint 执行集群创建 kind 镜像的 entrypoint 完成:
使用 git-crypt 解锁并 checkout tessops 仓库
调用用户提供的 --script
Step 3:kind 集群初始化脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #!/bin/bash kind create cluster --config kind-config.yaml \ --image hub.tess.io/kindest/node:v1.32-20260101 kubectl wait --for =condition=Ready nodes --all --timeout =5m kubectl apply -f /workspace/tessops/releases/templates/00-base/
Step 4:通过 Releaser 应用 tessops 规格 在真实集群中,Releaser 控制器负责持续应用 tessops 配置:
1 2 3 4 5 6 7 8 9 10 apiVersion: fleet.crd.tess.io/v1alpha1 kind: Release metadata: name: tessops-addons namespace: kube-system spec: branch: master revision: <commitID> repository: https://git.vip.ebay.com/tess/tessops
Releaser 控制器执行流程:
1 2 3 4 5 6 7 1. 拉取 tessops 仓库指定 revision 2. 读取 kubectl.yaml 中的配置 3. 根据当前集群的 region/zone/env/clustertype/cluster 查找并合并 values 4. 从 ConfigMap/Secret "pillars" 补充敏感配置 5. 渲染 88 个组件的 Go 模板 6. kubectl apply 所有生成的 YAML 7. prune 删除不再管理的资源(根据 skip 规则)
Step 5:E2E 测试中的 addons 值注入 e2e 镜像支持通过 --addons-values 参数覆盖 tessops 的默认值:
1 2 3 4 5 6 7 /e2e-entrypoint \ --addons-values="tetragon_enabled=true" \ --addons-values="cilium_env=dev" \ --addons-values="some_feature=enabled" \ --script=/e2e.sh \ --timeout =150m
entrypoint 将这些参数转换为 ADDONS_VALUES 环境变量,供 E2E 脚本读取并传递给 Releaser。
集群配置分层实例 以 CI 集群 #11 为例,展示配置合并过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 tetragon_enabled: "false" tetragon_image: "hub.tess.io/tess/tetragon:v0.10.0" image_resource_requests_cpu: "0" force_best_effort: "true" cilium_env: "dev" cilium_version: "1.14.5" tetragon_enabled: "true"
常见 Prow 镜像组合
场景
使用的镜像
构建 Go 代码
golang:1.24-latest
构建容器镜像
kaniko:v1.23.2
K8s E2E 测试
kind:v0.0.13-1.32 + e2e:latest
运行 Bazel 构建/测试
bazel:v5.4.0
Git 加密仓库操作
git:latest
Helm chart 更新
helm-bot:latest
安全 PR 自动化
auto-security-pr:latest
验证 Prow 配置
prow-config-validator:latest
总结 prow-images 和 tessops 共同构成了 Tess 平台 CI/CD 的基础设施骨架:
prow-images 提供工具层:每个 Docker 镜像职责单一,通过 VERSION 文件精确版本管理,通过 eBay 证书注入适配内网环境
tessops 提供配置层:Salt 管理主机级状态,Releaser 管理 K8s 应用级状态,通过 6 级值层次体系实现”一份配置,多集群复用”
两者协同 :Prow Job 使用 kind 镜像创建测试 K8s 集群,使用 e2e 镜像将 tessops 配置应用到测试集群并执行验证,通过后 tessops master 分支变更自动同步到生产集群
这套架构的优雅之处在于:代码即配置(Configuration as Code) 落地得非常彻底——从节点的 sysctl 参数到集群的 CNI 配置,从 CI 脚本到生产部署,全部以 Git 仓库作为唯一真相来源,通过 PR 审核机制保障变更质量。