☰
kgateway e2e 测试调试实战指南:从 Kind 集群搭建到 IDE 断点排错
2026/10/12 3:38:36 网站建设 项目流程
  • API网关
  • 云原生
  • 微服务

【免费下载链接】kgateway

The Cloud-Native API Gateway and AI Gateway

项目地址:https://gitcode.com/gh_mirrors/kg/kgateway
点击查看免费下载

本文是一份面向 kgateway(Cloud-Native API Gateway 与 AI Gateway)开发者的端到端(e2e)测试调试手册。它围绕test/e2e/debugging.md的完整工作流展开,覆盖测试套件结构、Kind/Tilt 集群准备、测试运行器的用法、环境变量语义,以及如何在 VSCode / Goland 中打断点、如何复现 CI 流水线的分片(shard)测试。读完本文,你将能够在本地独立搭建与 CI 一致的测试环境,用 IDE 对失败用例做源码级调试,并准确复现 CI 上任意一组测试的go test -run正则。

理解 kgateway e2e 测试的整体结构

kgateway 的 e2e 测试入口是标准的 Go 测试函数func TestXyz(t *testing.T),它代表针对某一种安装模式(installation mode)的顶层测试套件。以 test/e2e/tests/kgateway_test.go 中的TestKgateway为例:

//go:build e2e package tests // TestKgateway runs the main kgateway feature suites against a single // installation. func TestKgateway(t *testing.T) { kgateway.Run(t, e2e.DefaultInstallationFactory) }

注意两个细节:

  • 文件头部带有//go:build e2e构建标签,因此必须携带-tags e2e运行,否则该测试根本不会参与编译;
  • 顶层函数只是"薄壳",真正的逻辑委托给子包kgateway(见 test/e2e/tests/kgateway/kgateway.go),它负责安装 kgateway、应用基础 Gateway 与共享 Nginx 后端,最后通过SuiteRunner().Run(ctx, t, testInstallation.Underlying())驱动所有特性套件。

每个特性套件(feature suite)以顶层测试的子测试(subtest)形式被调用。子测试内部使用 testify 中集中注册,例如:

kubeGatewaySuiteRunner.Register("Deployer", deployer.NewTestingSuite) kubeGatewaySuiteRunner.Register("SessionPersistence", session_persistence.NewTestingSuite) kubeGatewaySuiteRunner.Register("BasicRouting", basicrouting.NewTestingSuite) kubeGatewaySuiteRunner.Register("JWT", jwt.NewTestingSuite) // ... 其余几十个套件

这套"顶层函数 + 子包 + Register 注册"的结构对调试至关重要:它决定了go test -run正则的层级写法(^TestKgateway$/^Deployer$/^TestXxx$),也决定了你可以在哪里下断点。

值得一提的配套校验:TestAllE2ETestsInShards(见 test/e2e/tests/shards_test.go)会解析.github/workflows/e2e.yaml中的每一个go-test-run-regex,确保每个已注册的 e2e 测试都被至少一个分片正则覆盖。如果你新增了一个测试套件却忘记加入 CI 分片,这个测试会在 PR 中被自动抓住,避免"测试永远不上 CI"的隐患。

第一步:准备测试集群

方式一:使用已发布的版本(无需本地构建)

kgateway 的 e2e 测试可以直接针对某个已发布的版本运行,适合验证 release candidate 或 nightly 构建。测试套件会自行从指定 release 下载 Helm chart 归档,因此不需要任何本地构建步骤——只需在运行时设置RELEASED_VERSION环境变量。其完整语义定义在 test/testutils/env.go 中:

  • RELEASED_VERSION未设置时,使用本地构建版本;
  • 设置为LATEST时,使用最近发布版本;
  • 设置为具体版本号(如1.15.0-beta1)时,使用该版本。

方式二:使用本地构建版本(前置条件)

若要在本地调试最新代码,需要满足两个前置条件:

  1. kgateway 的 Helm chart 归档位于_test目录;
  2. 存在一个已加载镜像(镜像 tag 与 chart 引用一致)的 kind 集群。
选项 1:hack/kind/setup-kind.sh脚本

CI 正是通过 hack/kind/setup-kind.sh 来完成上述准备的。本地直接运行默认配置通常即可:

./hack/kind/setup-kind.sh

该脚本接受一组环境变量以控制集群创建与资源部署,常用变量包括:

环境变量默认值作用
CLUSTER_NAMEkindkind 集群名称
CLUSTER_NODE_VERSIONv1.36.1@sha256:...集群节点镜像版本(需与 Makefile 保持同步)
VERSIONv1.0.0-ci1镜像 tag 版本
SKIP_DOCKERfalse跳过 Docker 镜像构建(测试已发布版本时很有用)
LOAD_DOCKER_IMAGESfalse只加载预构建镜像而不重建
JUST_KINDfalse只创建 kind 集群后退出
LOCALSTACKfalse是否部署 localstack(供 Lambda/EC2 相关套件使用)
CLOUD_PROVIDER_KINDfalse使用 cloud-provider-kind 代替 MetalLB 提供 LoadBalancer 支持

从源码看,脚本的核心执行顺序是:创建(或复用)kind 集群 → 应用 Gateway API CRDs → 安装 MetalLB(或 cloud-provider-kind)→ 执行make kind-build-and-load构建并加载镜像 → 按需部署 localstack。

在 Apple Silicon 上运行时,请在 Docker 设置中取消勾选Use Rosetta for x86_64/amd64 emulation on Apple Silicon。

选项 2:Tilt 开发工作流

Tilt 提供了更适合迭代式调试的开发工作流:当你修改代码后,它会自动重建并重新部署镜像,无需手动重启整个测试环境。

前置条件:

  • 本地安装 Tilt
  • 安装 ctlptl 用于集群管理

搭建步骤:

  1. 创建带本地镜像仓库的 kind 集群:
ctlptl create cluster kind --name kind-kind --registry=ctlptl-registry
  1. 查看集群状态:
kubectl cluster-info --context kind-kind
  1. 构建并加载初始镜像:
VERSION=1.0.0-ci1 CLUSTER_NAME=kind make kind-build-and-load
  1. 启动 Tilt 启用热更新:
tilt up

Tilt 工作流的收益很明显:自动重建并重新部署镜像、无需重启整个环境即可生效、Web UI 可监控资源状态与日志、调试迭代周期大幅缩短。更完整的说明见 devel/debugging/tilt.md。

如果你需要直接调试运行在 Pod 中的 kgateway 控制器,还可以参考该文档启用 Delve 调试器:在tilt-settings.yaml中设置debug_port(如 50100)并加入port_forwarding,然后在 VSCodelaunch.json中配置远程附加:

{ "name": "Attach to Delve", "type": "go", "request": "attach", "mode": "remote", "port": 50100 }

运行前的 kubeconfig 检查

无论采用哪种方式,运行回归测试前都要确认 kubeconfig 指向运行中的 Kubernetes 集群:

kubectl config current-context

输出应类似于kind-<CLUSTER_NAME>(例如kind-kind)。如果使用已发布版本,还需在调用测试时设置RELEASED_VERSION。

第二步:运行测试

先理解四个关键环境变量

kgateway 的 e2e 调试体验高度依赖环境变量控制"安装/清理"时机。它们的精确定义与清理逻辑在 test/testutils/env.go 中实现,核心如下:

环境变量语义
FAIL_FAST_AND_PERSIST集群已存在则跳过安装;仅在测试失败时跳过 teardown/清理,把 Kind 集群留在失败现场供取证分析。本地开发与调试的推荐配置
PERSIST_INSTALL集群已存在则跳过make setup,同时跳过 Kind 集群与 kgateway 的 teardown,但仍会运行AfterTest、TearDownSuite、t.Cleanup等钩子
SKIP_INSTALL与PERSIST_INSTALL类似,但不做任何环境搭建
SKIP_ALL_TEARDOWN跳过 Kind 集群、kgateway 乃至测试用例自身的全部清理,即使测试通过也保留现场

清理决策的源码逻辑:ShouldSkipCleanup(t)在SKIP_ALL_TEARDOWN生效时直接返回 true;否则在测试失败 && FAIL_FAST_AND_PERSIST=true时返回 true。仓库通过testutils.Cleanup(t, fn)包装了t.Cleanup(),由环境变量自动决定是否真正执行清理函数。

hack/run-test.sh:通用测试运行器

hack/run-test.sh 是统一入口,会自动判断目标是 e2e 还是单元测试并选择对应处理方式。其核心特性包括:

  • 自动检测:通过git grep判断测试属于 e2e 还是单元测试;
  • 智能搜索:按名称自动定位测试所在包与文件;
  • 最小化配置:屏蔽了底层复杂度。

常用示例:

# 运行 e2e 测试套件(自动检测) ./hack/run-test.sh SessionPersistence # 运行单元测试(自动检测) ./hack/run-test.sh TestShouldUseDefaultGatewayParameters # 运行指定包内的全部测试 ./hack/run-test.sh --package ./pkg/utils/helmutils # 集群已存在时跳过安装(加速 e2e 迭代) PERSIST_INSTALL=true ./hack/run-test.sh SessionPersistence # 列出所有可用测试 ./hack/run-test.sh --list # 只打印将要执行的命令,不真正运行 ./hack/run-test.sh --dry-run TestName

支持的主要选项:

  • --list, -l:列出所有可用测试(e2e 与单元测试)
  • --unit, -u/--e2e, -e:强制指定测试模式
  • --package PKG:在指定包内运行测试
  • --rebuild, -r:删除集群并从头重建(仅 e2e);当你此前跳过了清理、或无法复现 CI 上看到的现象时非常有用
  • --dry-run, -n:只打印命令不执行

hack/run-e2e-test.sh:e2e 专用运行器

hack/run-e2e-test.sh 是 e2e 测试的专用脚本,功能更强:

  • 智能模式匹配:自动构建正确的-run正则;
  • 安装管理:与make setup集成,尊重PERSIST_INSTALL;
  • 自动清理冲突:AUTO_SETUP=true时会自动卸载冲突的 Helm release 并删除 kgateway CRD;
  • 默认面向调试:默认启用FAIL_FAST_AND_PERSIST=true与go test -failfast,测试失败时保留本地 Kind 集群等待取证。

常用示例:

# 运行整个测试套件 ./hack/run-e2e-test.sh SessionPersistence # 运行套件内的某个测试方法 ./hack/run-e2e-test.sh TestCookieSessionPersistence # 运行顶层测试函数 ./hack/run-e2e-test.sh TestKgateway # 集群已存在时跳过安装 PERSIST_INSTALL=true ./hack/run-e2e-test.sh SessionPersistence # 自动清理冲突的 Helm release AUTO_SETUP=true ./hack/run-e2e-test.sh SessionPersistence # 删除集群并全部重建 ./hack/run-e2e-test.sh --rebuild SessionPersistence # 列出所有可用 e2e 测试 ./hack/run-e2e-test.sh --list # 查看将要执行的命令(调试时最常用) ./hack/run-e2e-test.sh --dry-run TestCookieSessionPersistence

支持的主要选项:

  • --dry-run, -n:只打印测试命令不执行
  • --list, -l:列出所有测试套件与顶层测试
  • --rebuild, -r:删除 kind 集群、重建镜像、创建全新集群
  • --persist, -p:kind 集群已存在时跳过make setup(加速迭代)
  • --cleanup-on-failure, -c:即使测试失败也总是清理(除非设置了SKIP_ALL_TEARDOWN)

支持的环境变量:

环境变量默认值作用
FAIL_FAST_AND_PERSISTtrue(本脚本默认)集群已存在时跳过安装,仅失败时跳过全部 teardown
PERSIST_INSTALL未设置集群已存在时跳过安装,跳过 Kind/kgateway teardown,但运行套件级与用例级清理钩子
SKIP_INSTALL未设置同PERSIST_INSTALL,但不搭建环境
SKIP_ALL_TEARDOWN未设置无条件跳过全部 teardown/清理
AUTO_SETUP未设置自动清理冲突的 Helm release
CLUSTER_NAMEkindkind 集群名称
TEST_PKG./test/e2e/tests要运行的 Go 测试包

此外脚本还支持CLUSTER_TYPE=kind|k3d切换集群类型(k3d 下默认集群名为k3d)。

模式匹配是如何工作的

hack/run-e2e-test.sh通过git grep在test/e2e/tests与test/e2e/features中查找测试定义,自动生成最精确的go test -run正则:

  1. 套件名(如SessionPersistence)→ 找到套件注册与其父测试 → 生成^TestKgateway$/^SessionPersistence$
  2. 测试方法(如TestCookieSessionPersistence)→ 找到方法、所在套件与父测试 → 生成^TestKgateway$/^SessionPersistence$/^TestCookieSessionPersistence$
  3. 顶层测试(如TestKgateway)→ 生成^TestKgateway$

这避免了手动拼写复杂正则的烦恼。实际执行时脚本内部会转换为类似make go-test GO_TEST_USER_ARGS="-failfast -run '<pattern>'" TEST_PKG=./test/e2e/tests TEST_TAG=e2e的调用(make go-test目标定义见 Makefile)。

手动运行go test(高级用法)

如果需要更多控制,可以直接使用go test。由于每个特性套件都是顶层套件的子测试,可以配合-run标志只运行单个套件。以运行TestKgateway中的Deployer套件为例,既可以内联设置环境变量:

PERSIST_INSTALL=true CLUSTER_NAME=kind INSTALL_NAMESPACE=kgateway-system go test -v -timeout 600s -tags e2e ./test/e2e/tests -run ^TestKgateway$/^Deployer$

也可以先导出再运行:

export PERSIST_INSTALL=true export CLUSTER_NAME=kind export INSTALL_NAMESPACE=kgateway-system go test -v -timeout 600s -tags e2e ./test/e2e/tests -run ^TestKgateway$/^Deployer$

-run标志接受一串正则表达式,每一段都可能匹配套件/测试名的子串;要精确匹配请使用^与$锚定(见 Go 官方 testing 标志文档)。完整的环境变量列表见 test/testutils/env.go。

运行特性套件内的特定测试

推荐方式:直接使用测试运行脚本自动构建完整正则:

# 脚本会自动推导完整模式 ./hack/run-e2e-test.sh TestProvisionDeploymentAndService # 配合 PERSIST_INSTALL 加速迭代 PERSIST_INSTALL=true ./hack/run-e2e-test.sh TestProvisionDeploymentAndService

手动方式:用-run标志指定到方法层级。例如运行TestKgateway下Deployer套件内的TestProvisionDeploymentAndService:

FAIL_FAST_AND_PERSIST=true CLUSTER_NAME=kind INSTALL_NAMESPACE=kgateway-system go test -v -timeout 600s -failfast ./test/e2e/tests -run ^TestKgateway$/^Deployer$/^TestProvisionDeploymentAndService$

使用 IDE 进行源码级调试

VSCode

先用./hack/run-e2e-test.sh --dry-run TestName查看确切的-run正则,再将其写入自定义调试配置。一个可用的launch.json配置如下:

{ "name": "e2e", "type": "go", "request": "launch", "mode": "test", "buildFlags": "-tags=e2e", "program": "${workspaceFolder}/test/e2e/tests/kgateway_test.go", "args": [ "-test.run", "^TestKgateway$/^Deployer$", "-test.v", ], "env": { "FAIL_FAST_AND_PERSIST": "true", "CLUSTER_NAME": "kind", "INSTALL_NAMESPACE": "kgateway-system" }, }

各字段含义:

  • FAIL_FAST_AND_PERSIST=true:跳过 kgateway 的重复安装;仅当测试失败时才跳过 teardown/清理,保留现场供调试。你可以先用make setup或 Tilt 手动搭好环境,也可以不搭(由测试自行安装);
  • CLUSTER_NAME:e2e 测试使用的集群名(需与创建 kind 集群时一致);
  • INSTALL_NAMESPACE:kgateway 的安装命名空间(使用 Tilt 时通常为kgateway-system)。

如果通过 VSCode 的run test按钮运行测试,记得在用户settings.json中设置"go.testTimeout": "600s"——默认值可能低至30s,不足以让 e2e 测试完成。

若要调试套件内的某个具体测试方法,改用三段式正则并加上-failfast:

{ "name": "e2e", "type": "go", "request": "launch", "mode": "test", "program": "${workspaceFolder}/test/e2e/tests/kgateway_test.go", "args": [ "-failfast", "-test.run", "^TestKgateway$/^Deployer$/^TestProvisionDeploymentAndService$", "-test.v", ], "env": { "FAIL_FAST_AND_PERSIST": "true", "CLUSTER_NAME": "kind", "INSTALL_NAMESPACE": "kgateway-system" }, }

Goland

在 Goland 中,可以右键测试函数选择Run 'TestXyz'或Debug 'TestXyz'。需要注意:

  • 设置FAIL_FAST_AND_PERSIST=true,由测试框架自动处理安装,并且只在测试失败时保留资源;
  • 设置运行所需的其他环境变量(CLUSTER_NAME、INSTALL_NAMESPACE等);
  • 套件内存在多个测试时,在 run configuration 的-run标志中追加测试名即可精确定位:
-test.run="^TestKgateway$/^Deployer$/^TestProvisionDeploymentAndService$"

同样建议先用./hack/run-e2e-test.sh --dry-run TestName拿到确切的-run正则再填入配置。

复现 CI 流水线中的测试

CI 是如何负载均衡的

kgateway 在 CI 中把 e2e 测试按运行时长分组(load balancing),分片定义在 GitHub Actions 矩阵中(见 test/e2e/load_balancing_tests.md 与 .github/workflows/e2e.yaml)。相比早期按领域分组的做法,按运行时长的策略可以更均衡地利用硬件:不会出现某个测试集群耗时翻倍的情况。

需要说明的是:原调试文档引用的是pr-kubernetes-tests.yaml,在当前仓库中该文件已演进为 .github/workflows/e2e.yaml,go-test-run-regex与go-test-args的实际定义都在此文件中。

从矩阵中提取正则并复现

e2e.yaml的end_to_end_tests作业通过 matrix 定义多个集群分片,例如:

- cluster-name: 'cluster-one' go-test-args: '-timeout=25m' go-test-run-regex: '^TestKgateway$$/^BasicRouting$$|^TestKgateway$$/^PathMatching$$|^TestKgateway$$/^HTTPRouteServices$$|^TestKgateway$$/^TLSRouteServices$$|^TestKgateway$$/^GRPCRouteServices$$|^TestKgateway$$/^SessionPersistence$$'

复现步骤如下:

  1. 在 e2e.yaml 中查看目标集群的go-test-run-regex,例如go-test-run-regex: '(^TestKgateway$$)';

    注意 GitHub Actions 定义中出现了$$,因为单个$会被展开,实际传给go test的是单个$。

  2. 查看同一分片的go-test-args,例如go-test-args: '-v -timeout=25m';
  3. 将两者组合后通过make go-test调用:
TEST_PKG=./test/e2e/... GO_TEST_USER_ARGS='-v -timeout=25m -run \(^TestKgateway$$/\)' make go-test

make go-test底层会经由 gotestsum 执行go test,并把GO_TEST_USER_ARGS原样附加到参数中(E2E_GO_TEST_ARGS默认含-vet=off -timeout=35m,详见 Makefile),因此你可以自由追加-run正则与超时等参数。

分片覆盖的自动化保障

test/e2e/tests/shards_test.go 中的TestAllE2ETestsInShards会解析e2e.yaml的全部go-test-run-regex,并对比test/e2e/tests下所有顶层测试函数与已注册套件,确保每个 e2e 测试至少被一个分片覆盖(个别负载测试、代价基准与多区集群测试被显式豁免)。这意味着:新增 e2e 测试却忘记加入 CI 矩阵会被自动拦截,同时也保证了本文前述的"从矩阵复现"路径永远与真实测试全集一致。

调试最佳实践小结

综合仓库实现与官方文档,推荐的高效调试路径如下:

  1. 首选脚本而非手写命令:./hack/run-e2e-test.sh --dry-run <TestName>拿到精确-run正则,再决定是直接运行还是填入 IDE;
  2. 本地迭代固定搭配:FAIL_FAST_AND_PERSIST=true+go test -failfast,失败即停并保留集群现场;需要保留成功现场时改用SKIP_ALL_TEARDOWN=true;
  3. 无法复现 CI 现象时:用./hack/run-e2e-test.sh --rebuild <TestName>从零重建集群与镜像,消除残留状态干扰;
  4. 集群复用加速:PERSIST_INSTALL=true让脚本跳过make setup,显著缩短二次运行的等待时间;
  5. 在 Pod 内调试控制器:使用 Tilt + Delve(端口 50100)远程附加,详见 devel/debugging/tilt.md;
  6. 复现 CI 分片:从 .github/workflows/e2e.yaml 提取对应集群的go-test-run-regex与go-test-args,组合进make go-test即可。

这套工作流把"搭建集群、运行用例、断点调试、复现 CI"四个环节串成了闭环,是 kgateway 日常 e2e 开发与排障的标准姿势。

  • API网关
  • 云原生
  • 微服务

【免费下载链接】kgateway

The Cloud-Native API Gateway and AI Gateway

项目地址:https://gitcode.com/gh_mirrors/kg/kgateway
点击查看免费下载
上一篇:番茄小说下载器完整实战:一条流水线把整本书干净地搬进阅读器
下一篇:从零到一搭建虚拟显示器:ParsecVDisplay 游戏串流与多屏工作台完整避坑指南

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询