在 k8s 世界中,所有资源都是通过控制器创建的。就像有用于 pod、部署、副本集等的内置控制器一样。所以基本上,控制器只不过是一个控制循环,它持续监视集群的状态并采取措施使集群进入所需的状态。资源具有提供所需状态的规范。控制器检查当前状态。如果与期望的状态不匹配,它将进行适当的更改或修改,使其更接近期望的状态。
ReplicaSet Controller:该控制器负责维护一组稳定的副本 Pod 在任何给定时间运行。它通常与 Deployment 结合使用,以确保指定数量的 pod 副本始终在运行,即使在节点故障或 pod 终止的情况下也是如此。
部署控制器:此控制器为 Pod 和 ReplicaSet 提供声明性更新。它允许轻松扩展、滚动更新和回滚应用程序。 Deployment 控制器管理 ReplicaSet 的创建和删除,以确保所需数量的 pod 始终运行。
StatefulSet Controller:此控制器用于管理有状态应用程序,例如数据库。它为集合中的每个 Pod 提供唯一的标识(稳定的主机名),并维护这些 Pod 的顺序和唯一性。当您需要稳定的网络标识符、稳定的持久存储以及有序、优雅的部署和扩展时,它特别有用。
服务控制器:该控制器负责维护一组 pod 的稳定 IP 地址和 DNS 名称。它充当负载均衡器,并根据服务的选择器将流量路由到适当的 Pod。这确保了服务有一个稳定的端点来访问正在运行的 Pod,即使它们在集群中被创建、销毁或移动。
因此,在进行测试之前,我们必须了解标准控制器的基本架构。在 Kubernetes 的客户端-服务器架构中,控制器作为向 Kubernetes API 服务器进行 API 调用(主要是 HTTP)的客户端发挥着至关重要的作用。他们的主要目标是协调 Kubernetes API 对象与实际系统资源。该架构中的一个重要组成部分是 Informers 的使用。举报者负责监控集群中的任何变化,这至关重要,因为持续轮询来检索资源信息会显着降低 API 服务器的性能。
告密者通过查询资源数据并将其存储在本地缓存中来工作。一旦数据被存储,只有当对象(或资源)的状态发生变化时才会生成事件。这种方法可确保系统不会被不必要的事件淹没,并且仅在发生相关更改时才通知控制器。
该架构中的另一个重要概念是资源版本。该版本随每次写入操作而变化,用于乐观并发控制。它确保以避免冲突并保持整个系统一致性的方式管理资源更新。通过理解和利用这些机制,Kubernetes 控制器可以有效地管理和协调集群中资源的状态。
Kubernetes 允许创建自定义资源定义 (CRD),它是 Kubernetes API 的扩展,使用户能够定义自定义资源。这些自定义资源在默认 Kubernetes 安装中不可用,用于适应特定于域的用例和复杂的应用程序要求。
要管理这些自定义资源,需要一个自定义控制器。自定义控制器、CRD 和 Kubernetes API 服务器形成紧密的关系,其中:
CRD 定义自定义资源。
API 服务器管理这些资源的生命周期。
自定义控制器确保根据所需的配置维护这些资源的状态。
该架构实现了 Kubernetes 的可扩展性,允许用户根据自己的特定需求定制平台。
在将 Kubernetes 控制器部署到生产环境之前,确保 Kubernetes 控制器已准备好向 Kubernetes API 服务器提供请求至关重要。有多种方法可以测试 Kubernetes 控制器。我提到的一些内容来自文章:
使用 client-go fakes 或更高级别的抽象:这种方法避免运行任何支持 API,使其适合单独对各个组件进行单元测试。
使用控制器运行时中的 envtest 包:该包与精简的 API 服务器配合使用,以验证与 API 的真实交互,包括计时和缓存同步,而不会受到其他控制器的干扰。它支持针对精简实例的本地测试和针对功能齐全的集群的测试。
运行真正的 API 服务器:此方法适合临时环境或实例(例如临时类型或 microk8s),用于测试真实结果。它允许测试与真实 API 服务器的交互。
使用外部进程(例如 envtest 或真正的 API 服务器)的优点是它可以解决分布式系统固有的延迟。像 Gomega 这样的库可用于在操作发生后等待特定条件。上述方法通常听起来最适合单元测试和集成级别测试,在这些测试中我们单独测试特定组件。要么通过编写测试来伪造数据
虽然上述技术对于单元和集成测试有效,但它们可能不涵盖端到端(e2e)测试,而这对于确保控制器的整体功能至关重要。 e2e 测试的一种方法是执行资源更新和其他操作,以在受控环境中测试控制器的整个流程,并在必要时复制该过程。这有助于验证控制器在现实场景中的行为,并确保其为生产部署做好准备。
总之,单元、集成和端到端测试的结合对于确保 Kubernetes 控制器在投入生产之前的可靠性和有效性至关重要。
在本地构建和测试 Kubernetes 控制器可能具有挑战性,尤其是在处理传出 API 调用时。然而,Keploy 作为一种通过 API 调用、数据库查询等创建测试用例和数据模拟的工具,提供了一种解决方案。 Keploy 允许您记录和重放 Kubernetes 控制器发出的传出呼叫,这对于测试和确保控制器按预期运行非常有用。
您可能想知道如何在不更改任何代码的情况下实现这一点。 Keploy 使用 eBPF 向内核空间添加探测器并收集网络缓冲区数据。然后,该数据被发送到 Keploy 的代理,该代理充当用户空间,其中缓冲区的所有处理均由不同的协议解析器完成。 Keploy 可以捕获控制器的出口流量,并将该特定事件的请求和响应存储在 YAML 文件中。在重播模式下,Keploy 不会对真正的 API 服务器进行 API 调用,而是会从存储的 YAML 文件返回针对该特定请求的响应。这使得该过程独立于集群或环境,为本地测试 Kubernetes 控制器提供了一种便捷高效的方法。
因此,要在本地或从任何实时环境捕获控制器的测试,您必须首先启动 kubernetes 集群并创建自定义控制器以与服务器进行一些交互。
要使用 Keploy 录制您的控制器,请按照以下步骤操作:
将您的 Kubernetes *rest.Config 对象设置为不安全且没有 CA 文件:
cfg.Insecure = true cfg.CAFile = ""
创建自定义 RoundTripper 以添加包含资源版本的标头字段。此标头用作跟踪 ID,用于在同一状态下将请求与记录的模拟进行匹配。这是一个示例实现:
type customRoundTripper struct { rt http.RoundTripper } func (crt *customRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { ctx := req.Context() rsv := ctx.Value("ResourceVersion") if rsv != nil { req.Header.Add("keploy-header", rsv.(string)) } return crt.rt.RoundTrip(req) } cfg.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { return &customRoundTripper{rt: rt} }
确保在同步过程中在 context.Context 中设置资源版本值。这对于将修改后的上下文传递给控制器的更新和创建方法至关重要。例如:
func (c *Controller) syncHandler(ctx context.Context, key string) error { // set ResourceVersion in ctx rv := foo.GetResourceVersion() if rv != "" { ctx = context.WithValue(ctx, "ResourceVersion", rv) } }
构建 Kubernetes 控制器的 Go 二进制文件:
go build -o sample-controller .
要通过 Keploy 记录去电,请使用 Keploy 的记录命令包装您的控制器命令。注意 - keploy 的此功能处于测试版使用状态,尚未在主版本中发布。这是专门为 Kubernetes 爱好者尝试并给出评论而创建的实验。因此,您必须在这个特定分支中签出并使用 go build 命令构建 keploy 二进制文件。 https://github.com/keploy/keploy/pull/1342。
到指定分店结账。
1.
git checkout kube-controller ``` {% endraw %}
为该分支构建 keploy 二进制文件。
{% 原始 %}
go build -o keploy && sudo mv keploy /usr/local/bin
根据您的 kube 配置添加必要的标志:
sudo -E env PATH=$PATH keploy record -c "./sample-controller -kubeconfig=$HOME/.kube/config" --mtls-cert-path "$HOME/.minikube/profiles/minikube/client.crt" --mtls-key-path "$HOME/.minikube/profiles/minikube/client.key" --mtls-host-name 192.168.49.2:8443
一旦 Keploy 开始拦截出站调用,您就可以看到创建的 keploy/test-set-0/mocks.yaml。每个资源版本都有一个单独的模拟文件,用mocks_“
注意 - 我想澄清的一件事是,上述功能对 TDD(测试驱动开发)没有帮助。但是,您仍然可以在编写单元测试时利用 keploy 的存根生成功能来进行 keploy。因此,您无需制作任何模拟 api 服务器或为特定单元测试编写存根,只需在真实环境中进行该测试即可。 Keploy 会将所有交互存储在模拟文件中,并在下次运行测试时使用该数据。
使用录制的模拟测试您的控制器:
在测试模式下运行 Keploy,并将 mockAssert 标志设置为 true 并提供您的控制器二进制文件。 Keploy 会自动为您创建一个假的 kube 配置:
cfg.Insecure = true cfg.CAFile = ""
(可选)您可以设置自己的重播时间,这将尝试在提供的时间内重播您录制的会话:此处给出了与 keploy 集成的完整示例应用程序。
type customRoundTripper struct { rt http.RoundTripper } func (crt *customRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { ctx := req.Context() rsv := ctx.Value("ResourceVersion") if rsv != nil { req.Header.Add("keploy-header", rsv.(string)) } return crt.rt.RoundTrip(req) } cfg.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { return &customRoundTripper{rt: rt} }
请注意,重播过程会将足够大的事件时间间隔修剪为举报者的两个事件之间的精确平均持续时间。这允许事件在记录中发生之前发送,从而促进更快的重播。
这可以帮助您重放控制器生成的 api 调用的整个会话,但这次您不需要真正的 k8s 服务器或任何外部源来获取响应。所有响应都将由 keploy 本身返回,就像模拟服务器或中间人一样。这可以让您有信心在 CI-CD 管道中运行它。
例如 - 您在大型云计算组织工作,要部署所有内容,需要大量虚拟化,并且是资源密集型操作。因此,在真实环境中对其进行测试几乎是不可能的。在这里,类似 Keploy 的工具非常有用,因为它已经提供了您在成功推出该资源时想要获得的响应。因此,它可以是快速、可靠且节省成本的操作,因为您只需一次捕获控制器服务的正确流程。并且可以在后续版本中重复使用 keploy 重放。
使用 Keploy 等工具可以使本地测试 Kubernetes 控制器变得更加高效和可靠。通过录音和重播去电,您可以确保控制器在各种场景下都能正确运行,从而提高 Kubernetes 应用程序的整体质量。由于 keploy 原生支持 gotest 等测试框架,因此还可以获得任何应用程序的线路覆盖率,甚至是 kube 控制器的线路覆盖率。探索 Keploy 并增强您的 Kubernetes 控制器测试工作流程!
记录和重放传出 API 调用:这消除了测试期间对实时环境的需求。
提高效率:通过使用存储的模拟,测试变得更快并且独立于实际的 Kubernetes 集群。
节省成本和资源:它减少了对资源密集型环境进行验证的依赖,使其成为大规模运营中 CI/CD 管道的理想选择。
Keploy 使用 eBPF 探针 拦截传出呼叫并将请求-响应对存储在模拟文件中。在重播模式下:
呼叫被拦截并与之前录制的模拟进行匹配。
响应是从这些模拟返回的,而不是到达实际的 API 服务器。
这种机制确保测试可以在不需要实时 Kubernetes 集群的情况下运行。
虽然Keploy的录音和重放功能并不是专门为TDD设计的,但它仍然可以有效地使用:
存根生成:在真实环境中运行控制器一次以捕获交互。 Keploy 将创建模拟以供后续使用。
单元测试支持:通过利用这些模拟,您可以避免手动编写存根并专注于测试执行。
Keploy 通过简化模拟创建和减少开发开销来补充现有的 TDD 工作流程。
以上是如何使用自定义 Kubernetes 控制器测试流量:分步指南的详细内容。更多信息请关注PHP中文网其他相关文章!