如何让Istio对GCP负载均衡传入的请求进行URI路径重写?
解决Istio中GCP负载均衡直接访问Pod时的路径重写问题
你的问题核心在于:之前配置的VirtualService仅对服务间流量(从其他带Sidecar的Pod发往myapp Service的请求)生效——因为它的hosts指向Service名称,匹配的是Sidecar的出站流量规则。而GCP负载均衡直接发往Pod的流量属于Sidecar的入站流量,原有规则不会触发。
要处理入站到Pod的路径重写,你可以通过以下两种方式实现:
方式一:使用EnvoyFilter直接修改Sidecar入站规则
EnvoyFilter可以直接操作Sidecar的Envoy配置,添加入站路径重写逻辑,这是最直接的方案:
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: myapp-uri-rewrite namespace: default # 替换为你的myapp所在命名空间 spec: workloadSelector: labels: app: myapp # 替换为你的myapp Pod的标签 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) local path = request_handle:headers():get(":path") -- 处理/foo/前缀的路径 if string.sub(path, 1, 5) == "/foo/" then local new_path = string.sub(path, 6) request_handle:headers():replace(":path", new_path) -- 处理单独的/foo路径 elseif path == "/foo" then request_handle:headers():replace(":path", "/") end end
这个配置会在myapp Pod的Sidecar入站HTTP链中插入Lua过滤器,自动将/foo/xxx重写为/xxx,将/foo重写为/。
方式二:配置Sidecar资源的入站路由规则
如果你不想用Lua脚本,也可以通过Sidecar资源定义入站的路径重写规则:
apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: name: myapp-sidecar namespace: default spec: workloadSelector: labels: app: myapp ingress: - port: number: 8080 protocol: HTTP name: http defaultEndpoint: "localhost:8080" rewrite: uri: match: prefix: "/foo/" prefixRewrite: "/" # 额外处理单独的/foo路径 match: - uri: exact: "/foo" rewrite: uri: "/"
注意事项
- 确保你的
myappPod已经正确注入Istio Sidecar,可以通过kubectl describe pod <pod-name>检查是否存在istio-proxy容器。 - GCP负载均衡的后端服务必须指向Pod的应用端口(即Sidecar劫持的端口),而非Sidecar的其他端口。
内容的提问来源于stack exchange,提问作者Drago Rosson
相关产品推荐
相关产品推荐

