如何通过K3S TestContainers测试Istio EnvoyFilter中的Lua代码?
用K3S TestContainers在Java集成测试中验证Istio嵌入式Lua脚本
完全可以这么做,这种容器化的测试方案能彻底解决真实Kubernetes环境测试慢的问题,非常适合回归测试场景。下面是具体的实现步骤和关键细节:
具体实现步骤
1. 启动K3S TestContainers实例
用TestContainers的K3sContainer快速拉起轻量Kubernetes集群,注意禁用自带的Traefik避免和Istio Ingress冲突:
K3sContainer k3s = new K3sContainer("rancher/k3s:v1.27.3-k3s1") .withCommand("server", "--disable", "traefik") .withExposedPorts(6443) .withResources(ResourceRequirements.builder() .limits(CpuCount.of(2), MemorySize.of("4Gi")) .build()); // 分配足够资源避免Istio安装失败 k3s.start(); // 获取KubeConfig用于后续Kubernetes操作 String kubeConfig = k3s.getKubeConfigYaml();
2. 在K3S中安装Istio
通过容器内执行istioctl命令安装Istio,选择demo配置文件足够满足测试需求,资源占用更低:
// 下载并安装指定版本的Istio k3s.execInContainer( "sh", "-c", "curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.18.2 sh - && " + "istio-1.18.2/bin/istioctl install --set profile=demo -y" ); // 等待Istio核心组件就绪(用Fabric8 Kubernetes Client检查) try (KubernetesClient client = new DefaultKubernetesClient(new ConfigBuilder().withKubeconfig(kubeConfig).build())) { client.pods().inNamespace("istio-system") .waitUntilCondition(pod -> "Running".equals(pod.getStatus().getPhase()), Duration.ofMinutes(5)); }
3. 部署Nginx并启用Istio Sidecar
给默认命名空间开启Sidecar自动注入,然后部署Nginx的Deployment和Service:
// 启用默认命名空间的Istio Sidecar注入 k3s.execInContainer("kubectl", "label", "namespace", "default", "istio-injection=enabled"); // 定义Nginx的K8s资源YAML String nginxYaml = """ apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:alpine --- apiVersion: v1 kind: Service metadata: name: nginx-service spec: ports: - port: 80 targetPort: 80 selector: app: nginx """; // 部署Nginx资源 k3s.copyFileToContainer(Transferable.of(nginxYaml.getBytes()), "/tmp/nginx.yaml"); k3s.execInContainer("kubectl", "apply", "-f", "/tmp/nginx.yaml"); // 等待Nginx Pod就绪 try (KubernetesClient client = new DefaultKubernetesClient(new ConfigBuilder().withKubeconfig(kubeConfig).build())) { client.pods().inNamespace("default").withLabel("app=nginx") .waitUntilCondition(pod -> "Running".equals(pod.getStatus().getPhase()), Duration.ofMinutes(2)); }
4. 配置Envoy Filter嵌入Lua脚本
创建Envoy Filter资源,在Sidecar的入站HTTP链中插入Lua脚本,实现自定义请求头生成:
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: lua-header-filter namespace: default spec: workloadSelector: labels: app: nginx configPatches: - applyTo: HTTP_FILTER match: context: SIDECAR_INBOUND listener: portNumber: 8080 filterChain: filter: name: "envoy.filters.network.http_connection_manager" subFilter: name: "envoy.filters.http.router" patch: operation: INSERT_BEFORE value: name: envoy.filters.http.lua typed_config: "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua" inline_code: | function envoy_on_request(request_handle) -- 生成自定义请求头 request_handle:headers():add("X-Generated-By", "Istio-Lua-Script") request_handle:headers():add("X-Request-Timestamp", tostring(os.time())) end
在Java中部署这个Envoy Filter:
String envoyFilterYaml = // 上述YAML内容 k3s.copyFileToContainer(Transferable.of(envoyFilterYaml.getBytes()), "/tmp/lua-filter.yaml"); k3s.execInContainer("kubectl", "apply", "-f", "/tmp/lua-filter.yaml");
5. 执行端到端测试验证效果
通过端口转发将Nginx服务暴露到本地,发送请求并检查Lua生成的请求头:
// 启动端口转发 Process portForward = k3s.execInContainer("kubectl", "port-forward", "service/nginx-service", "8080:80"); Thread.sleep(2000); // 等待端口转发就绪 // 发送请求并验证响应头 RestTemplate restTemplate = new RestTemplate(); ResponseEntity<String> response = restTemplate.getForEntity("http://localhost:8080", String.class); // 断言Lua脚本生成的头存在且符合预期 assert response.getHeaders().containsKey("X-Generated-By"); assert "Istio-Lua-Script".equals(response.getHeaders().getFirst("X-Generated-By")); assert response.getHeaders().containsKey("X-Request-Timestamp"); // 停止端口转发 portForward.destroy();
关键注意事项
- 资源分配:必须给K3S容器分配足够的CPU和内存,否则Istio组件可能因资源不足启动失败。
- 就绪等待:所有K8S资源(Istio、Nginx)都要等待Pod进入
Running状态再执行测试,避免过早请求导致失败。 - Lua调试:可以通过
kubectl logs <nginx-pod-name> istio-proxy查看Envoy Sidecar日志,排查Lua脚本的执行问题(脚本中可通过request_handle:logInfo("调试信息")输出日志)。 - 测试隔离:每个测试用例可启动独立的K3S实例,或测试后清理所有K8S资源,避免测试间的干扰。
内容的提问来源于stack exchange,提问作者bobmarksie
相关产品推荐
相关产品推荐

