十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Consul 升级集成测试指南:基于 consul-container 框架验证受支持升级路径

Consul 升级集成测试指南:基于 consul-container 框架验证受支持升级路径 Consul 升级集成测试指南基于 consul-container 框架验证受支持升级路径【免费下载链接】consulConsul is a distributed, highly available, and data center aware solution to connect and configure applications across dynamic, distributed infrastructure.项目地址: https://gitcode.com/gh_mirrors/con/consul导读本文围绕 Consul 仓库中 test/integration/consul-container/test/upgrade/README.md 展开系统讲解 Consul 升级集成测试Upgrade Integration Tests的设计目标、工作原理、环境准备、运行方式与新增测试用例的方法。升级测试的核心目标是确保 Consul 在官方支持的升级路径上无痛升级——任何时刻 Consul 都支持最新次要版本及其前两个次要版本如 1.15、1.14、1.13且允许跨次要版本升级例如从 1.13 直接升级到 1.15。读完本文后你将掌握如何用 Docker 在本地跑通单条或全部升级测试、如何理解StandardUpgrade的升级顺序与快照机制、如何参照既有用例ACL、Peering、Ingress Gateway 等编写新的升级测试以及如何处理 1.14 之前版本的错误处理差异。升级测试要解决什么问题升级测试的目标是确保受支持升级路径上的升级过程无故障。Consul 的版本支持策略是在任何给定时刻官方支持最新次要版本以及更早的两个次要版本。例如在 1.15 为最新版本时受支持版本为 1.15、1.14 与 1.13。升级到任何更高版本都是被允许的包括跳过次要版本例如从 1.13 直接跳到 1.15。除了验证升级成功之外升级测试还刻意暴露用户在尝试把当前版本升级到更新版本时可能遇到的错误让这类问题在发版前就被测试框架捕获而不是等到真实用户在生产环境升级时才发现。工作原理与部署架构升级测试的部署架构如上图所示该图位于 test/integration/consul-container/test/util/upgrade_tests_workflow.png一个典型的升级测试会部署两个 Consul agent一个 server、一个 client以及一个 static-server、一个 static-client 和它们的 Envoy sidecar。所有 Consul agent 与用户工作负载如应用服务、mesh-gateway都运行在 Docker 容器中。每个升级测试通常遵循以下五步流程创建集群并启用被测特性用指定数量的 server 与 client agent 创建一个集群启用待测试的功能特性创建工作负载例如注册两个服务 static-server 与 static-client。static-server 是一个简单的 HTTP 应用同时是 static-client 的上游服务对集群做额外配置例如配置 Consul intention 拒绝 static-client 与 static-server 之间的连接然后验证连接确实无法建立升级集群到target-version并重启 Envoy sidecar重启 sidecar 是为了确保升级后的 Consul 二进制能读取上一版本持久化的状态并生成正确的 Envoy 配置重新校验在目标版本下再次验证 client、server 与 sidecar确认上一版本持久化的数据在目标版本中仍可访问并重新验证连接/断连例如 deny Action是否符合预期。环境准备与前置条件要运行升级测试本机需要安装以下工具Go版本需与 CI 配置中使用的 Go 镜像版本一致golangci-lint用于代码静态检查Make用于执行 Makefile 目标Docker本地运行测试所必需因为所有 Consul agent 与工作负载都跑在容器里。运行升级集成测试完整的运行步骤如下先构建开发版 Consul Docker 镜像make dev-docker构建 consul-envoy 容器镜像注意命令需要在test/integration/consul-container目录下执行cd test/integration/consul-container docker build -t consul-envoy:latest-version \ --build-arg CONSUL_IMAGEdocker.mirror.hashicorp.services/consul:1.20.0-rc1 \ --build-arg ENVOY_VERSION1.31.2 -f ./assets/Dockerfile-consul-envoy ./assets运行单条测试例如 ACL 节点令牌升级测试go test -v -timeout 30m -run ^TestACL_Upgrade_Node_Token$ ./.../upgrade/运行全部升级测试go test -v -timeout 30m -run ./.../upgrade测试支持通过--target-version与--latest-version参数指定目标镜像与最新镜像的版本。默认情况下测试使用consulDocker 镜像分别以local与latest作为 tag。若想使用开发版 consul 镜像可传入target-image与target-version-target-image hashicorppreview/consul -target-version 1.15-dev默认情况下所有容器的日志会输出到stdout或stderr当测试用例创建大量容器时这会非常嘈杂、难以调试。可以通过-follow-log false关闭容器日志跟踪。支持的 CLI 选项下表整理了升级测试支持的全部命令行选项其默认值与描述可在 test/integration/consul-container/libs/utils/version.go 中找到对应实现Flags默认值说明--latest-imageconsulCE/hashicorp/consulenterpriseENT初始部署的 Docker 镜像名称--latest-versionlatest初始部署的 Docker 镜像 tag--target-imageconsulCE/hashicorp/consulenterpriseENT升级目标 Docker 镜像名称--target-versionlocal升级目标 Docker 镜像 taglocal即上文make dev-docker构建出的 tag-follow-logtrue是否输出所有容器日志本地开发建议--follow-logfalse从源码实现看这些 flag 通过标准库flag包注册version.go其中TargetVersion默认值为local、LatestVersion默认值为latest。此外GetTargetImageName()与GetLatestImageName()会在调试模式-debug下自动为镜像名追加-dbg后缀DockerImage()则会在检测到企业版镜像且版本为语义化版本时自动追加-ent后缀version.go。升级过程的底层实现StandardUpgrade升级测试的核心方法是cluster.StandardUpgrade其实现位于 test/integration/consul-container/libs/cluster/cluster.go。该方法遵循 Consul 官方文档中标准升级的步骤先做快照当前实现会丢弃该快照在 ACL 开启时使用 bootstrap token 执行consul snapshot save否则直接执行快照用于在升级前备份集群状态cluster.go按顺序逐个升级 agent先是followersfollower server然后是leader最后是client agentscluster.go。该顺序保证了整个升级过程中始终存在可用 leader客户端连接不被中断升级每个 agent 时会重新生成其配置 JSON对 server 取消bootstrap配置因为只需要首次引导对 client 则设置retry_join: [agent-0]确保客户端在重启后能以正常方式重新加入集群cluster.go每个 agent 升级完成后会等待成员数量恢复WaitForMembers并等待 leader 选举完成WaitForLeader确认升级后的节点成功重新加入集群cluster.go。值得注意的是StandardUpgrade同时返回error而非直接断言失败这让测试可以编写断言升级会失败的负向场景cluster.go 中的注释明确说明了这一设计意图。新增一个升级集成测试所有升级测试都定义在 test/integration/consul-container/test/upgrade 子目录中。新增测试用例的步骤分为四步。第一步创建集群使用工具函数创建一个指定版本的单集群或创建两个 peer 集群// NewCluster 创建单个集群 cluster, _, _ : libtopology.NewCluster(t, libtopology.ClusterConfig{ NumServers: 1, NumClients: 1, BuildOpts: libcluster.BuildOptions{ Datacenter: dc1, ConsulVersion: utils.LatestVersion, }, })或者创建两个已建立 peering 的集群// BasicPeeringTwoClustersSetup 创建两个 peer 集群分别命名为 accepting 和 dialing accepting, dialing : libtopology.BasicPeeringTwoClustersSetup(t, utils.LatestVersion, false)某些工作负载需要额外资源应在 setup 阶段一并创建。例如 peering 测试会创建第二个 static-server 来验证跨集群的路由参见 peering/peering_http_test.go 中TestPeering_HTTPRouter的写法它额外创建了一个static-server-2服务并写入service-router配置项。第二步验证工作负载在升级之前先确认工作负载运行正常libassert.HTTPServiceEchoes(t, localhost, port, ) libassert.AssertFortioName(t, fmt.Sprintf(http://localhost:%d, appPort), static-server-2-v2, )第三步调用 StandardUpgrade 执行升级调用StandardUpgrade方法并检查升级是否成功。同时要重启 Envoy sidecar确保升级后的 agent 能生成正确的 Envoy 配置require.NoError(t, cluster.StandardUpgrade(t, context.Background(), utils.TargetVersion)) require.NoError(t, staticServerConnectProxy.Restart()) require.NoError(t, staticClientConnectProxy.Restart())第四步升级后再次验证重复第二步中的验证确认升级后工作负载仍然正常libassert.HTTPServiceEchoes(t, localhost, port, ) libassert.AssertFortioName(t, fmt.Sprintf(http://localhost:%d, appPort), static-server-2-v2, )对于较长的验证逻辑建议封装成本地函数以便在升级前后复用tests : func() { libassert.HTTPServiceEchoes(t, localhost, port, ) libassert.AssertFortioName(t, fmt.Sprintf(http://localhost:%d, appPort), static-server-2-v2, ) } tests() // ... 执行升级 tests()已有测试用例一览升级测试目录下已存在的用例可作参考模板基础升级basic/basic_test.go 中的TestBasic创建单个 server 集群、注册api服务、执行标准升级然后通过 Catalog 查询确认服务在升级后仍然存在升级前后的成员与 leader 等待分别由libcluster.WaitForLeader与libcluster.WaitForMembers完成ACL 节点令牌acl_node_test.go 中的TestACL_NodeToken在开启 ACL 的集群中创建一个 agent token升级后用该 token 查询 catalog 节点验证升级后 agent 能继承持久化令牌并加入集群、升级前的令牌依然有效注意该用例在 bootstrap 阶段关闭了 auto.encrypt避免与 ACL token 冲突Peering 升级peering/peering_http_test.go 覆盖了 peering 基础升级、HTTP 路由、ResolverFailover、ResolverSplitter 等场景其peeringUpgrade辅助函数依次升级 accepting 与 dialing 集群并在每次升级后断言 peering 状态仍为ACTIVE随后重启 mesh gateway 与 sidecar 验证数据面与控制面流量Peering 控制面 mesh gatewaypeering/peering_control_plane_mgw_test.go 验证PeerThroughMeshGateways配置可被升级后的集群继承并通过 Envoy admin 端口指标cluster.server.dc1.peering的upstream_cx_total确认控制面流量经由 mesh gatewayIngress Gateway 升级ingress_gateway_test.go、ingress_gateway_grpc_test.go、ingress_gateway_sds_test.go 分别覆盖 ingress gateway 的 HTTP、gRPC 与 SDS 场景公共工具common.go 中的CreateAndRegisterStaticClientSidecarWith2Upstreams创建一个带两个 upstream本地绑定端口 5000 与 5001的 static-client sidecar支持跨集群场景crossCluster为 true 时为 upstream 设置MeshGatewayModeLocal供 peering 相关测试复用。错误处理用例1.14 之前版本的注意事项对于1.14之前的版本存在一些特殊错误处理的注意事项。例如 peering 等特性的 API 在升级时可能发生变更并返回错误这些情况需要在升级测试中专门处理。如果升级测试涉及任何1.14之前的版本必须加入以下代码跳过相关断言否则测试无法通过fromVersion, err : version.NewVersion(utils.LatestVersion) require.NoError(t, err) if fromVersion.LessThan(utils.Version_1_14) { t.Skip(...) }其中utils.Version_1_14在 test/integration/consul-container/libs/utils/version.go 中定义为version.NewVersion(1.14)。仓库中的 ingress_gateway_test.go 也展示了类似的按版本跳过逻辑例如当LatestVersion 1.15时ingress gateway 不支持Defaults.PassiveHealthCheck测试会以t.Skipf跳过相关断言。此外如果发现升级过程中暴露的 bug可以针对该场景编写专门的回归测试用例参考升级测试目录下现有用例的组织方式。FAQ常见问题排查Q. 容器端口例如 Consul 的 8500、Envoy sidecar 的 admin 端口或本地 upstream 端口是否暴露在 Docker 主机上A.是的这些端口都会被暴露。不过它们是通过 pod 容器暴露的相关实现见 libs/cluster/container.go也就是说一个 Consul agent 与其注册的 Envoy 代理容器与 pod 容器共享同一个 Linux 网络命名空间即它们共享localhost见 libs/cluster/app.go且 pod 容器的名称与 Consul agent 使用相同前缀。这也是测试中可以通过localhost:port直接访问服务、通过localhost:adminPort访问 Envoy admin 页面的原因。Q. 排障时如何向已部署的集群发送 API 请求或执行 consul 命令A.先确保集群、服务与 sidecar 已创建完毕然后在测试代码中获取相关端口并暂停测试见下方示例再在终端中用docker ps -a | grep consul找到运行中的服务与集群exec进入集群容器后直接执行命令或对localhost:port发起 API 请求Envoy 则访问localhost:adminPortcluster, _, _ : topology.NewCluster() clientService : createServices(t, cluster) _, port : clientService.GetAddr() _, adminPort : clientService.GetAdminAddr() // ... time.Sleep(900 * time.Second) fmt.Println(port, adminPort)Q. 排障时如何访问 Envoy admin 页面A.同样需要先确保集群、服务与 sidecar 已创建。获取 client 或 server sidecar 的 adminPort获取方式见上例然后在浏览器中访问http://localhost:adminPort/即可查看 Envoy 的配置、集群端点状态与指标。Q. 测试卡在 could not start or join all agents: container 0: port not found 错误A.直接重跑测试即可。如果错误持续出现先清理 Docker 镜像缓存docker system prune然后重新执行make dev-docker再重跑测试。从源码看该错误在 libs/cluster/cluster.go 中已有应对创建容器时会以 10 秒间隔重试专门针对包含 port not found 的错误做重试因为本地开发中相邻两次运行间隔过近时容易出现该问题。Q. 如何清理升级测试创建的资源A.执行docker ps | grep consul找出所有遗留资源然后对每个容器执行docker stop {CONTAINER_ID} docker rm {CONTAINER_ID}逐一停止并删除。总结Consul 的升级集成测试是一套完全容器化的端到端验证体系它以最新版本 前两个次要版本的支持矩阵为边界通过StandardUpgrade的快照备份、follower→leader→client 的升级顺序以及升级后 Envoy sidecar 重启系统性地验证持久化状态、服务发现、Service Mesh 流量与 ACL、Peering、Ingress Gateway 等特性在跨版本升级后的行为一致性。对于 Consul 的贡献者或需要自定义升级验证场景的开发者参考 test/integration/consul-container/test/upgrade 目录下的现有用例与本文的四步编写流程即可快速产出可运行、可回归的新升级测试。【免费下载链接】consulConsul is a distributed, highly available, and data center aware solution to connect and configure applications across dynamic, distributed infrastructure.项目地址: https://gitcode.com/gh_mirrors/con/consul创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表