Istio中如何处理thrift等协议(istio 协议)
对于Istio来说,分为控制面和数据面。控制面负责下发Envoy 的配置。数据面接受控制面下发的配置,按照配置工作。
所以本质上只有envoy支持的协议,控制面才能够支持。实际情况,istio支持的协议类型,远远少于Envoy支持的类型。
Istio对于HTTP,gRPC协议之外的协议,支持并不是特别好。而实际的应用中,其实很多单位都在使用诸如thrift,dubbo或其他私有协议。随着Istio用户越来越多,增加对其他协议的支持是一个强需求。
Istio如何确定各种协议
Istio支持代理任何TCP通信。这包括HTTP,HTTPS,gRPC以及原始TCP协议。为了提供其他功能,例如路由和丰富的metrics,我们必须确定具体协议。确定的方式有:
- 自动检测
- 手动指定
自动检测
Istio可以自动检测HTTP和HTTP/2通信。其他协议类型,如果没有手动指定,则将流量视为纯TCP流量。
手动指定
如何指定?
我们知道对于Istio来说,支持k8s中的 Service 和 非k8s环境ServiceEntry两种资源对象转换为内部的统一服务模型。
对于k8s中的Service:
- 通过端口名: name:
[- ] - Kubernetes 1.18+, 可以通过 appProtocol 字段: appProtocol:
通过appProtocol字段指定,具体示例如下:
kind: Service
metadata:
name: myservice
spec:
ports:
- number: 3306
name: database
appProtocol: mysql
- number: 80
name: http-web
对于ServiceEntry,通过ports列表中protocol属性自定,具体示例如下:
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: external-svc-mongocluster
spec:
hosts:
- mymongodb.somedomain # not used
addresses:
- 192.192.192.192/24 # VIPs
ports:
- number: 27018
name: mongodb
protocol: MONGO
location: MESH_INTERNAL
resolution: STATIC
endpoints:
- address: 2.2.2.2
- address: 3.3.3.3
截止到目前,支持以下值:
http
http2
https
tcp
tls
grpc
grpc-web
mongo
mysql
redis
thrift
其中*标注的协议,默认是不支持,需要在特性开关中启用。对于thrift来说,我们需要给pilot设置环境变量:
PILOT_ENABLE_THRIFT_FILTER 。
可以看出,Istio逐步在增加对其他协议的支持,比如mongo,redis,mysql,thrift。
Istio 如何支持其他协议
那么我们目前有以下几种方式支持thrift等协议。
1)EnvoyFilter
EnvoyFilter是Istio中自定义的一种网络资源对象,用来更新配置Envoy中的filter,为服务网格控制面提供了更强大的扩展能力,使Envoy中filter chain具备自定义配置的能力。
我们以thrift举例说明。
Istio默认把Thrift协议当做普通的TCP协议来处理。我们需要通过EnvoyFilter移除默认的TCP Filter,并增加Thrift proxy Filter。
具体的EnvoyFilter如下:
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: thrift-demo
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
# will match outbound listeners in all sidecars
context: SIDECAR_OUTBOUND
listener:
# The port dedicated to thirft
portNumber: 10005
filterChain:
filter:
name: envoy.tcp_proxy
patch:
# Remove envoy.tcp_proxy filter
operation: REMOVE
- applyTo: NETWORK_FILTER
match:
# will match outbound listeners in all sidecars
context: SIDECAR_OUTBOUND
listener:
# The port dedicated to thirft
portNumber: 10005
patch:
operation: INSERT_FIRST
value:
name: envoy.filters.network.thrift_proxy
config:
stat_prefix: "outbound|10005||thrift-demo-server.thrift-demo.svc.cluster.local"
transport: AUTO_TRANSPORT
protocol: AUTO_PROTOCOL
thrift_filters:
- name: envoy.filters.thrift.router
route_config:
routes:
- match:
# empty string matches any request method name
method_name: ""
route:
cluster: "outbound|10005||thrift-demo-server.thrift-demo.svc.cluster.local"
更多内容可查看 istio-thrift-example 。
该方案的确可以实现,但是非常繁杂,也容易出错。
2)Aeraki
由于难以手动对 EnvoyFilter 进行管理和维护 ,腾讯云Mesh团队创建了 Aeraki 项目来自动化这个流程。
Aeraki 的基本工作原理如下图所示:Aeraki 从 Istio 中拉取服务数据,根据 ServiceEntry 和 Aeraki 流量规则生成 Envoy 配置,并采用 EnvoyFilter 将生成的配置推送到 Istio 中。简而言之,你可以把 Aeraki 看做 Istio 中管理的七层协议的Operator。
该方案,又做了一些抽象,并且不会对Istio代码做侵入性改动。
3)通过给Istio增加新的future,增加对其他协议支持
上面我们已经讲到,目前istio正在增加对其他协议的支持,已经支持了mongo,thrift等。
这里可以看出社区终究会支持其他主流协议。
个人观点:如果所用协议为开源社区主流协议,尤其是envoy已经支持的协议,通过改动Istio代码会更加合适,当然如果可以贡献给社区,并且被接受,那就更加完美了。而且整体难度也不会特别大,按照社区对于mongo等支持的方式,添加对其他协议的支持。
比如thrift:
case protocol.Thrift:
if features.EnableThriftFilter {
// Thrift filter has route config, it is a terminating filter, no need append tcp filter.
filterstack = append(filterstack, buildThriftFilter(statPrefix))
} else {
filterstack = append(filterstack, tcpFilter)
}
如果我们启用了
PILOT_ENABLE_THRIFT_FILTER。filter列表中,将会直接添加thrift filter,而不是tcp filter。