- 云原生
- 可观测性
【免费下载链接】prometheus-operator
Prometheus Operator creates/configures/manages Prometheus clusters atop Kubernetes
Prometheus Operator 的端到端(E2E)测试是一套以 Go test 形式编写、在真实 Kubernetes 集群上运行的自动化测试,用于验证 Operator 在真实用户场景下的完整行为。本指南将围绕 test/e2e/README.md 的核心说明,结合仓库中的测试框架源码与 Makefile 构建目标,系统讲解 E2E 测试的前置条件、构建与运行方式、测试套件的组织与筛选、镜像准备以及失败诊断方法,帮助你从零开始在本机复现并调试这套与 CI 完全一致的测试体系。
E2E 测试是什么
端到端(End-to-end,E2E)测试是面向真实用户场景的自动化测试。与单元测试在隔离环境下验证单个函数不同,E2E 测试会启动一个真实的 Kubernetes 集群,在其中部署 Prometheus Operator、CRD、Prometheus/Alertmanager/ThanosRuler 等资源,并验证从"用户提交 CR 资源"到"Operator 完成协调并产生预期效果"的完整链路。
在 Prometheus Operator 仓库中,E2E 测试与单元测试、长时测试共同构成完整的测试矩阵,这一点在 TESTING.md 中有明确说明:
- 单元测试:在隔离环境下测试特定代码片段,反馈循环最快;
- 长时测试(long tests):包含耗时更长的单元测试用例;
- E2E 测试:在真实 Kubernetes 集群中验证 Operator 的整体行为,也是 Pull Request 流水线中运行的那套测试。
从 Makefile 可以看到,三者可通过make test一键串联执行:
.PHONY: test test: test-unit test-long test-e2e ## Run all tests (unit, long, and e2e).运行 E2E 测试的前置条件
根据 test/e2e/README.md,运行 E2E 测试需要满足三个前置条件:
- 一个正在运行的 Kubernetes 集群,以及对应的 kubeconfig,测试时需要把 kubeconfig 作为参数传入;
- kubeconfig 文件就绪,测试框架需要通过它连接集群的 API Server;
- Prometheus Operator 镜像就绪,用于在集群内拉起 Operator 的 Deployment。
E2E 测试本身是标准的 Go test 程序,因此 Go 测试的所有技术手段(例如选择运行哪些用例、控制超时时长)都同样适用。最简单的运行方式是直接调用go test:
$ go test -v ./test/e2e/ --kubeconfig "$HOME/.kube/config" --operator-image=quay.io/prometheus-operator/prometheus-operator其中:
--kubeconfig:指定 kubeconfig 文件的路径;--operator-image:指定要部署到集群中的 Operator 镜像;-v:输出每个测试用例的详细运行结果。
这两个自定义 flag 是在 test/e2e/main_test.go 的TestMain中通过标准库flag包注册的,这也是"E2E 测试是标准 Go test"这一说法的源码依据:
func TestMain(m *testing.M) { kubeconfig := flag.String( "kubeconfig", "", "kube config path, e.g. $HOME/.kube/config", ) opImage = flag.String( "operator-image", "", "operator image, e.g. quay.io/prometheus-operator/prometheus-operator", ) flag.Parse() // ... }需要说明的是:直接运行go test时 Operator 镜像是已存在的(可以是本地构建并导入 kind 的镜像,也可以是远程仓库中的镜像)。测试框架会把该镜像写入 Operator 的 Deployment 清单中,具体逻辑见下文"测试框架如何拉起 Operator"一节。
推荐实践:通过 Makefile 运行 E2E 测试
虽然go test命令可以直接运行,但仓库在 Makefile 中封装了更完整的test-e2e目标,它会自动处理 kubeconfig 默认值、instrumented-sample-app 证书生成、镜像 tag 拼接等细节:
.PHONY: test-e2e test-e2e: KUBECONFIG?=$(HOME)/.kube/config test-e2e: test/instrumented-sample-app/certs/cert.pem test/instrumented-sample-app/certs/key.pem ## Run end-to-end tests. go test -timeout 120m -v ./test/e2e/ $(TEST_RUN_ARGS) --kubeconfig=$(KUBECONFIG) --operator-image=$(IMAGE_OPERATOR):$(TAG) -count=1该目标的几个关键点:
KUBECONFIG默认取$(HOME)/.kube/config,可通过环境变量覆盖;- 依赖
test/instrumented-sample-app/certs/下的证书,缺失时会通过 test/instrumented-sample-app/Makefile 的generate-certs目标自动生成; - 测试整体超时上限为120 分钟(
-timeout 120m); -count=1禁用 Go 测试缓存,确保每次都是真实执行;$(IMAGE_OPERATOR):$(TAG)中的镜像仓库默认为quay.io/prometheus-operator/prometheus-operator,TAG默认为当前 git 短提交哈希(见 Makefile);- 预留了
TEST_RUN_ARGS变量,可向go test追加参数(例如只运行某个测试,见下文)。
也就是说,最直接的运行方式就是:
make test-e2emake test-e2e会运行完整的 E2E 测试套件,与 Pull Request 流水线中执行的测试完全一致,确保所有控制器的功能需求都得到验证。
分控制器运行:按需裁剪测试范围
完整测试套件运行时间很长(即使在高配笔记本上也需要几十分钟甚至更久),而一次改动通常只会影响某一个控制器。为此,Makefile 提供了多个按控制器裁剪的目标,其实现原理是通过设置"排除类"环境变量来跳过不相关的测试套件(Makefile):
| Makefile 目标 | 运行内容 | 等价环境变量组合(其余 EXCLUDE 变量设为非空) |
|---|---|---|
make test-e2e-alertmanager | 仅 Alertmanager 相关测试 | EXCLUDE_ALERTMANAGER_TESTS=(不排除,其他全排除) |
make test-e2e-prometheus | Prometheus 测试(有限命名空间权限场景) | EXCLUDE_PROMETHEUS_TESTS=(不排除) |
make test-e2e-prometheus-all-namespaces | 常规 Prometheus 测试(全命名空间) | EXCLUDE_PROMETHEUS_ALL_NS_TESTS=(不排除) |
make test-e2e-thanos-ruler | ThanosRuler 相关测试 | EXCLUDE_THANOSRULER_TESTS=(不排除) |
make test-e2e-operator-upgrade | 验证由上一版本 Operator 管理的监控栈升级到当前版本后仍正常 | EXCLUDE_OPERATOR_UPGRADE_TESTS=(不排除) |
make test-e2e-prometheus-upgrade | 验证兼容矩阵内一系列 Prometheus 版本可依次升级 | EXCLUDE_PROMETHEUS_UPGRADE_TESTS=(不排除) |
make test-e2e-feature-gates | 验证处于 feature gate 之后的特性 | EXCLUDE_FEATURE_GATED_TESTS=(不排除) |
这些排除变量的作用在 test/e2e/main_test.go 中实现,例如:
func skipPrometheusAllNSTests(t *testing.T) { if os.Getenv("EXCLUDE_PROMETHEUS_ALL_NS_TESTS") != "" { t.Skip("Skipping Prometheus all namespace tests") } }当对应环境变量非空时,相关测试套件会被t.Skip跳过。CI 中始终运行全部测试,但本地开发时通过跳过无关套件可以显著缩短反馈循环。
只运行单个测试
如果正在调试某个具体用例,可以结合TEST_RUN_ARGS与 Go 的-run参数精确锁定目标。例如只运行TestPrometheusRuleCRDValidation/valid-rule-names子测试:
TEST_RUN_ARGS="-run TestPrometheusRuleCRDValidation/valid-rule-names" make test-e2e-prometheusTEST_RUN_ARGS会被拼接到go test命令中,配合-run正则即可只执行匹配的测试函数。
搭建本地测试集群与准备镜像
推荐使用 Kind
E2E 测试需要在真实集群上运行,官方推荐使用 KinD(Kubernetes in Docker):它足够轻量,能在小型笔记本上运行,同时也是项目 CI 使用的集群方案。Minikube 也是可选方案。
仓库在 test/e2e/kind-conf.yaml 中提供了 CI 所用的集群配置,包含两个关键设计:
- kubelet 同步频率降为 10 秒:将 kubelet 同步挂载的 ConfigMap 与 Secret 的间隔从默认 1 分钟降到 10 秒,加速配置变更在容器中的传播,从而加快测试速度;
- worker 节点打上可用区标签:两个 worker 分别标记为
topology.kubernetes.io/zone: zone-a与zone-b,用于拓扑感知分片(topology sharding)类测试。
使用该配置创建集群:
kind create cluster --config test/e2e/kind-conf.yaml构建镜像并加载到集群
在运行自动化 E2E 测试之前,需要先构建镜像并把它们加载进本地集群。使用 Docker 时执行:
KIND_CONTEXT=e2e make test-e2e-imagestest-e2e-images目标(Makefile)会依次构建三个镜像并通过kind load加载进名为e2e的 kind 集群:
prometheus-operator(Dockerfile)prometheus-config-reloader(cmd/prometheus-config-reloader/Dockerfile)admission-webhook(cmd/admission-webhook/Dockerfile)
KIND_CONTEXT的默认值就是e2e(Makefile),因此如果集群名不是e2e,需要显式覆盖。
使用 podman 的注意事项
在 macOS 上使用 podman 运行 kind 时,建议用4个 CPU 和8 GiB内存创建 podman machine,资源不足会导致 E2E 测试因集群资源匮乏而失败:
podman machine init --cpus=4 --memory=8192 --rootful --now随后用 podman 构建并加载镜像:
CONTAINER_CLI=podman KIND_CONTEXT=e2e make test-e2e-images设置CONTAINER_CLI=podman后,Makefile 会改用podman save导出镜像归档,再用kind load image-archive加载。
测试套件的组织与测试入口
顶层测试函数一览
test/e2e/main_test.go 是 E2E 测试的入口文件,其中定义了多个顶层测试函数,每个函数对应一类测试场景:
| 顶层测试函数 | 验证场景 | 源码位置 |
|---|---|---|
TestAllNS | Operator 监听全部命名空间(含 Alertmanager、Prometheus、ThanosRuler、多 Operator 并存) | main_test.go#L168-L225 |
TestMultiNS | Operator 只监听指定命名空间 | main_test.go#L360-L369 |
TestDenylist | Operator 配置了拒绝监听的命名空间 | main_test.go#L372-L383 |
TestPromInstanceNs | 设置--prometheus-instance-namespace时的多场景行为 | main_test.go#L386-L401 |
TestRepairPolicy | Operator 能修复损坏的 StatefulSet | main_test.go#L404-L413 |
TestAlertmanagerInstanceNs | 设置--alertmanager-instance-namespace时的多场景行为 | main_test.go#L416-L427 |
TestOperatorUpgrade | 从上一稳定小版本升级 Operator 后监控栈仍正常 | main_test.go#L430-L440 |
TestGatedFeatures | feature gate 之后的特性(DaemonSet Agent、status 子资源、拓扑分片等) | main_test.go#L447-L487 |
TestPrometheusVersionUpgrade | 兼容矩阵中各 Prometheus 版本可依次升级 | main_test.go#L490-L506 |
其中TestAllNS内部的 Prometheus 套件覆盖了非常广泛的场景,从 main_test.go#L264-L335 可以看到包括但不限于:CRD 校验、RemoteWrite 与 TLS、集群创建/删除/扩缩容、ServiceMonitor/PodMonitor 选择、Sharding/Resharding、Thanos 集成、UTF-8 指标与标签支持、状态条件(Degraded/Unavailable)等。
TestMain:测试的初始化与升级测试基础
TestMain 除了注册 flag,还做了两件关键的事情:
- 读取
../../VERSION确定当前版本,并计算出"上一稳定小版本"与"下一小版本"(当前开发目标版本)。VERSION文件当前内容为0.94.0(见 VERSION)。 - 初始化两套测试框架:
previousVersionFramework:使用上一稳定版本(如v0.93.x)的 Operator 镜像与示例资源目录,服务于 Operator 升级测试;framework:使用传入的--operator-image与当前仓库的example/目录、test/framework/resources/目录,服务于常规测试。
这也解释了升级类测试的运作方式:它们会先用旧版本 Operator 部署并管理一套监控栈,再升级到当前版本,验证旧资源在升级后依旧被正确协调。
测试框架如何工作
Framework 对象与客户端初始化
E2E 测试的底层能力由 test/framework 包提供。Framework结构体(framework.go#L66-L81)聚合了与 Kubernetes 交互所需的全部客户端:
KubeClient:标准 Kubernetes client;MonClientV1/MonClientV1alpha1/MonClientV1beta1:monitoring 组 v1 / v1alpha1 / v1beta1 三个 API 版本的客户端(对应pkg/apis/monitoring下的 CRD 类型);APIServerClient:API 扩展客户端,用于操作 CRD 本身;HTTPClient:复用 API Server 的 HTTP 客户端;MasterHost、RestConfig:API Server 地址与 REST 配置。
New()(framework.go#L84-L143)通过clientcmd.BuildConfigFromFlags("", kubeconfig)从 kubeconfig 构建连接配置,创建上述所有客户端,并校验集群至少存在一个节点,否则直接报错。
拉起 Operator:CreateOrUpdatePrometheusOperatorWithOpts
每个测试在运行前,都会通过CreateOrUpdatePrometheusOperatorWithOpts(framework.go#L254-L557)在集群中完整部署一套 Prometheus Operator,其流程包括:
- 基于 example/rbac/prometheus-operator/prometheus-operator-deployment.yaml 等清单创建 ServiceAccount、ClusterRole、ClusterRoleBinding;
- 依次创建并等待所有 CRD 就绪:Alertmanager、PodMonitor、Probe、Prometheus、PrometheusRule、ServiceMonitor、ThanosRuler、AlertmanagerConfig(v1alpha1/v1beta1)、PrometheusAgent,以及可选的 ScrapeConfig(通过
EnableScrapeConfigs控制); - 为 Operator 生成自签名证书并写入 Secret;
- 将 Operator Deployment 的镜像替换为
--operator-image传入的镜像,并同步推导prometheus-config-reloader与admission-webhook的镜像 tag; - 根据测试需要注入启动参数,例如
--namespaces、--deny-namespaces、--prometheus-instance-namespaces、--alertmanager-instance-namespaces、--feature-gates等; - 若开启
EnableAdmissionWebhook,还会部署 admission-webhook 服务,并配置 PrometheusRule 的变更/校验 webhook、AlertmanagerConfig 的校验 webhook 与 v1alpha1/v1beta1 转换 webhook; - 返回一组 finalizer 函数,供测试结束(
Cleanup)时回收资源。
PrometheusOperatorOpts(framework.go#L207-L218)集中表达了上述可配置项,包括命名空间白名单/黑名单、Prometheus/Alertmanager 实例命名空间、是否启用 admission webhook、ClusterRoleBinding、ScrapeConfig、附加参数与启用的 feature gate。
例如TestAllNS中通过如下方式部署 Operator(main_test.go#L176-L184):
finalizers, err := framework.CreateOrUpdatePrometheusOperatorWithOpts( ctx, operatorFramework.PrometheusOperatorOpts{ Namespace: ns, EnableAdmissionWebhook: true, ClusterRoleBindings: true, EnableScrapeConfigs: true, }, )测试上下文与失败诊断
每个测试还会通过framework.NewTestCtx(t)(context.go#L103-L196)创建独立的TestCtx,其职责包括:
- 生成唯一的命名空间:以测试名加时间戳为前缀,保证测试之间互不干扰;
- 管理资源回收:所有创建的集群资源都通过
AddFinalizerFn注册清理函数,测试结束(无论成功失败)时由Cleanup并行执行; - 失败诊断收集:当测试失败时,自动收集当前集群中的关键信息用于排查,包括工作负载资源(Alertmanager/Prometheus/ThanosRuler/PrometheusAgent)、配置资源(ServiceMonitor/PodMonitor/Probe/PrometheusRule/ScrapeConfig/AlertmanagerConfig)、Kubernetes 资源(StatefulSet/DaemonSet/Pod/Service/ConfigMap/Secret,其中 Secret 中的内容会被脱敏为
obfuscated)、Pod 日志与事件。
诊断信息默认输出到 stdout;设置环境变量E2E_DIAGNOSTIC_DIRECTORY后,会改为按测试名分目录写入文件,便于归档分析:
E2E_DIAGNOSTIC_DIRECTORY=/tmp/e2e-diag make test-e2e-prometheus手动运行 Operator:run-external.sh
除了完整的自动化测试,scripts/run-external.sh 提供了"手动测试"场景:它会在你的 kind 集群中检查所有前置条件,然后以本地编译的 Operator 二进制直接运行,适合开发调试。
./scripts/run-external.sh -c该脚本的主要行为:
-c / --use-default-context:使用当前 kubeconfig 的默认 context;也可以直接传入 context 名;-f / --no-operator-run-check:跳过"集群中不能已有 prometheus-operator 运行"的检查(脚本默认会检查并拒绝在已有 Operator 的集群上运行,避免冲突);- 从 kubeconfig 中提取 API Server 地址、CA、客户端证书与密钥;
- 执行
make operator构建本地二进制; - 通过
kubectl apply --server-side --force-conflicts安装 example/prometheus-operator-crd-full 下的全部 CRD,并等待其 Established; - 以前台方式运行
./operator,日志输出到tmp/operator.log。
它支持通过环境变量定制运行参数,例如REPAIR_POLICY(StatefulSet 修复策略)、FEATURE_GATES(feature gate 列表)、LOG_LEVEL(日志级别)等。
常见问题与调试建议
- 测试总是超时或卡住:检查 kind 集群资源是否充足(尤其是 podman 场景,建议 4 CPU / 8 GiB),以及镜像是否已正确加载进集群——
go test不会自动构建镜像,遗漏make test-e2e-images是常见原因。 - kubeconfig 路径错误:直接运行
go test时必须显式传--kubeconfig;使用make test-e2e时默认取$HOME/.kube/config,可用KUBECONFIG=...覆盖。 - 只想跑某类测试:优先选择 Makefile 中对应的分目标,或自行组合
EXCLUDE_*环境变量;调试单个用例用TEST_RUN_ARGS="-run 测试名"。 - 测试失败需要排查:设置
E2E_DIAGNOSTIC_DIRECTORY让框架在失败时把集群状态、Pod 日志、事件落盘;也可以参照TestAllNS末尾对 Operator Pod 重启次数的断言逻辑(main_test.go#L211-L224),自行检查 Operator 是否意外重启。
小结
Prometheus Operator 的 E2E 测试是一套完整的、可在本机复现的自动化测试体系:以 test/e2e/README.md 的三条前置条件与一条go test命令为起点,配合 Makefile 的test-e2e系列目标、test/e2e/main_test.go 的套件编排与EXCLUDE_*跳过机制、test/framework 的集群操作能力,你可以在本机完整复现 CI 中的验证流程,也可以精确裁剪测试范围来加速开发反馈循环。无论是提交新功能、修复缺陷,还是验证 Operator 升级兼容性,这套 E2E 测试都能在真实集群环境中给出最可信的答案。
- 云原生
- 可观测性
【免费下载链接】prometheus-operator
Prometheus Operator creates/configures/manages Prometheus clusters atop Kubernetes
相关推荐
eCapture 端到端(E2E)测试全指南:从环境搭建、测试架构到 CI/CD 集成
eCapture 端到端(E2E)测试全指南:从环境搭建、测试架构到 CI/CD 集成 导读 本文基于 eCapture 仓库中的端到端测试套件( docs/e
网络安全网络可观测性系统编程Vertical Pod Autoscaler 开发与端到端测试完全指南:本地 e2e 测试环境搭建与运行详解
Vertical Pod Autoscaler 开发与端到端测试完全指南:本地 e2e 测试环境搭建与运行详解 导读 本指南以 Kubernetes Autos
弹性伸缩云原生容器编排Kubernetes 动态资源分配(DRA)端到端测试指南:Kind 集群搭建、代理式测试驱动与 e2e 运行全流程
Kubernetes 动态资源分配(DRA)端到端测试指南:Kind 集群搭建、代理式测试驱动与 e2e 运行全流程 动态资源分配(Dynamic Resour
云原生容器编排集群管理微服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考