Istio EnvoyFilter+Lua 简单实现动态路由转发 因为种种原因,我们需要实现一个将服务名和subset携带在http请求的header里面,根据这个来实现将服务转发去特定的istio的服务的subset。
比如以下example:
携带 service: msg-group
tag: gray
的话,将其路由去msg-group 的gray subset。
该版本返回数据: Call Read from msg-group,By New version!!!!
携带 service: msg-group
tag: default
的话,将其路由去msg-group 的default subset。
改版本返回数据: Call Read from msg-group
用istio的Virtual Service来实现 大概如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: onroute-com namespace: develop spec: gateways: - msggroup-gateway hosts: - onroute.com http: - match: - headers: service: exact: msg-group tag: exact: gray route: - destination: host: msg-group.develop.svc.cluster.local subset: gray headers: response: set: test: This value added By static route to gray - match: - headers: service: exact: msg-group route: - destination: host: msg-group.develop.svc.cluster.local subset: default headers: response: set: test: This value added By static route default
请求构造及结果如下:
注:10.99.20.74
是istio-ingressgateway的IP
请求 msg-group 的 gray
版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 * Trying 10.99.20.74:80... * Connected to 10.99.20.74 (10.99.20.74) port 80 ( > GET /read HTTP/1.1 > Host: onroute.com > User-Agent: curl/7.77.0 > Accept: */* > service: msg-group > tag: gray > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < content-type: text/plain;charset=UTF-8 < content-length: 43 < date : Fri, 16 Sep 2022 07:36:35 GMT < x-envoy-upstream-service-time: 7 < server: istio-envoy < test : This value added By static route to gray < * Connection Call Read from msg-group,By New version!!!!%
请求 msg-group 的 default
版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 curl -v -H "Host: onroute.com" -H "service: msg-group" -H "tag: default" 10.99.20.74/read * Trying 10.99.20.74:80... * Connected to 10.99.20.74 (10.99.20.74) port 80 ( > GET /read HTTP/1.1 > Host: onroute.com > User-Agent: curl/7.77.0 > Accept: */* > service: msg-group > tag: default > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < content-type: text/plain;charset=UTF-8 < content-length: 24 < date : Fri, 16 Sep 2022 07:38:41 GMT < x-envoy-upstream-service-time: 12 < server: istio-envoy < test : This value added By static route default < * Connection Call Read from msg-group%
能实现问题,但是有几个小问题
配置不够灵活,如果面对几百个服务,配置是个巨大的工作量。
不同的namespace要配置不同的规则。
用Envoy Filter + Lua来实现 针对上面提到的问题,如果用EnvoyFiltter来实现动态的路由的话,就可以解决这个问题。
解决思路都是围绕config.route.v3.RouteAction cluster_header 这个字段来的
(string ) Envoy will determine the cluster to route to by reading the value of the HTTP header named by cluster_header from the request headers. If the header is not found or the referenced cluster does not exist, Envoy will return a 404 response.
设置route的cluster_header字段为 x-service
从header读取service和tag的值组合出upstream cluster格式,并将x-service
头替换为它
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: onroute-routing namespace: istio-system spec: workloadSelector: labels: istio: ingressgateway configPatches: - applyTo: VIRTUAL_HOST match: context: GATEWAY patch: operation: ADD value: name: dynamic_routing domains: - 'onroute.com' - 'onroute.com:*' routes: - name: "path-matching" match: prefix: "/" route: cluster_header: "x-service" - applyTo: HTTP_FILTER match: context: GATEWAY listener: filterChain: filter: name: "envoy.http_connection_manager" subFilter: name: "envoy.router" patch: operation: INSERT_BEFORE value: name: envoy.service-helper typed_config: "@type" : "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua" inlineCode: | function envoy_on_request(request_handle) local headers = request_handle:headers() local mesh_service = headers:get("service") local tag = headers:get("tag") if mesh_service ~= nil then if tag ~= nil then request_handle:headers():replace("x-service", "outbound|80|" .. tag .. "|" .. mesh_service .. ".svc.cluster.local") end end end function envoy_on_response(response_handle) response_handle:headers():add("test", "from envoy filter response" ) end
下面是测试结果:
请求 msg-group的 gray
版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 curl -v -H "Host: onroute.com" -H "service: msg-group.develop" -H "tag: gray" 10.99.20.74/read * Trying 10.99.20.74:80... * Connected to 10.99.20.74 (10.99.20.74) port 80 ( > GET /read HTTP/1.1 > Host: onroute.com > User-Agent: curl/7.77.0 > Accept: */* > service: msg-group.develop > tag: gray > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < content-type: text/plain;charset=UTF-8 < content-length: 43 < date : Fri, 16 Sep 2022 08:07:29 GMT < x-envoy-upstream-service-time: 16 < server: istio-envoy < test : from envoy filter response < * Connection Call Read from msg-group,By New version!!!!%
请求 msg-group的 default
版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 curl -v -H "Host: onroute.com" -H "service: msg-group.develop" -H "tag: default" 10.99.20.74/read * Trying 10.99.20.74:80... * Connected to 10.99.20.74 (10.99.20.74) port 80 ( > GET /read HTTP/1.1 > Host: onroute.com > User-Agent: curl/7.77.0 > Accept: */* > service: msg-group.develop > tag: default > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < content-type: text/plain;charset=UTF-8 < content-length: 24 < date : Fri, 16 Sep 2022 08:12:40 GMT < x-envoy-upstream-service-time: 14 < server: istio-envoy < test : from envoy filter response < * Connection Call Read from msg-group%
参考资料