1什么是grpc
gRpc 是来自 Google 的 RPC 框架。它使用协议缓冲区作为底层 序列化 IDL(接口描述语言的缩写) 格式。在传输层,它使用 HTTP/2 进行请求/响应复用。Envoy 在传输层和应用层都提供对 gRPC 的一流支持:
•gRPC 使用 HTTP/2 trailers 特性(可以在 HTTP 请求和响应报文后追加 HTTP Header)来传送请求状态。Envoy 是能够正确支持 HTTP/2 trailers 的少数几个 HTTP 代理之一,因此也是可以传输 gRPC 请求和响应的代理之一。•某些语言的 gRPC 运行时相对不成熟。Envoy 支持 gRPC 桥接过滤器,允许 gRPC 请求通过 HTTP/1.1 发送给 Envoy。然后,Envoy 将请求转换为 HTTP/2 以传输到目标服务器。该响应被转换回 HTTP/1.1。•安装后,除了标准的全局 HTTP 统计数据之外,桥接过滤器还会根据每个 RPC 统计数据进行收集。•gRPC-Web 由一个指定的过滤器支持,该过滤器允许 gRPC-Web 客户端通过 HTTP/1.1 向 Envoy 发送请求并代理到 gRPC 服务器。•gRPC-JSON 转码器由一个指定的过滤器支持,该过滤器允许 RESTful JSON API 客户端通过 HTTP 向 Envoy 发送请求并获取代理到 gRPC 服务。
2grpc相关过滤器有哪些
gRPC HTTP/1.1 Bridge
允许grpc请求通过http/1/1方式发送到envoy,然后envoy转换成http/2或http/3传输到目标服务器。响应会转换回http/1.1
gRPC HTTP/1.1 Reverse Bridge
允许grpc请求发送到envoy,然后转换成http/1.1,到上游。响应转换回grpc到下游。上游可以不感知grpc的存在。
gRPC statistics
这个过滤器启用grpc调用遥测。他会计算成功和失败的调用,把他们通过方法名称分组。
gRPC Web
grpc-web是一个js客户端库,他支持相同的api如grpc-node方式访问grpc服务。
这个过滤器启用grpc-web客户端和grpc服务器桥接。
gRPC-JSON transcoder
这个过滤器允许restful json api客户端请求envoy用http的方式,代理到grpc服务端。
3实战
3.1gRPC HTTP/1.1 Bridge
例子来自:https://github.com/envoyproxy/envoy/tree/main/examples/grpc-bridge
bridge-deploy.yaml
kubectl apply -f bridge-deploy.yaml -n istio
---apiVersion: apps/v1kind: Deploymentmetadata:name: grpc-serverlabels:app: grpc-serverspec:selector:matchLabels:app: grpc-serverreplicas: 1template:metadata:labels:app: grpc-serverversion: v1spec:containers:- name: csrfimage: registry.cn-beijing.aliyuncs.com/hxpdocker/grpc-bridge-server:latestimagePullPolicy: Alwaysports:- containerPort: 8081---apiVersion: v1kind: Servicemetadata:name: grpc-serverspec:selector:app: grpc-serverports:- name: grpc-serverprotocol: TCPport: 8081targetPort: 8081---apiVersion: apps/v1kind: Deploymentmetadata:name: grpc-clientlabels:app: grpc-clientspec:selector:matchLabels:app: grpc-clientreplicas: 1template:metadata:labels:app: grpc-clientversion: v1spec:containers:- name: csrfimage: registry.cn-beijing.aliyuncs.com/hxpdocker/grpc-bridge-client:latestimagePullPolicy: Alwaysenv:- name: CLIENT_PROXYvalue: http://grpc-server:8081
ef-bridge-client.yaml
kubectl apply -f ef-bridge-client.yaml -n istio
apiVersion: networking.istio.io/v1alpha3kind: EnvoyFiltermetadata:name: grpc-clientspec:workloadSelector:labels:app: grpc-clientconfigPatches:- applyTo: HTTP_FILTERmatch:context: SIDECAR_OUTBOUNDlistener:name: 0.0.0.0_8081filterChain:filter:name: envoy.filters.network.http_connection_managersubFilter:name: envoy.filters.http.routerpatch:operation: INSERT_BEFOREvalue:name: envoy.filters.http.grpc_http1_bridgetyped_config:"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_http1_bridge.v3.Config
测试:
kubectl exec -it -n istio grpc-client-5f86876755-564t6 -- /bin/bash/client/grpc-kv-client.py set foo bar2[root@node01 ~]# kubectl logs -f -n istio grpc-server-59ff9799c4-7pcqn2021/10/15 03:14:36 starting grpc on :80812021/10/15 03:33:10 set: foo = bar2021/10/15 03:33:20 get: foo2021/10/15 03:33:40 set: foo = bar2021/10/15 03:33:44 get: foo2021/10/15 03:33:50 set: foo = bar22021/10/15 03:33:53 get: foo2021/10/15 03:34:37 get: foo2021/10/15 03:41:41 set: foo = bar22021/10/15 03:42:01 set: foo = bar2
3.2gRPC HTTP/1.1 Reverse Bridge
例子来自:https://github.com/sp-manuel-jurado/istio-grpc-http1-reverse-bridge
reverse-bridge-deploy.yaml
kubectl apply -f reverse-bridge-deploy.yaml -n istio
---apiVersion: v1kind: Servicemetadata:name: ping-httplabels:app: ping-httpspec:ports:- port: 8888name: httpselector:app: ping-http---apiVersion: apps/v1kind: Deploymentmetadata:name: ping-httpspec:replicas: 1selector:matchLabels:app: ping-httptemplate:metadata:labels:app: ping-httpspec:containers:- name: ping-httpimage: registry.cn-beijing.aliyuncs.com/hxpdocker/ping-http:latestresources:requests:cpu: "100m"memory: "128Mi"imagePullPolicy: Alwaysports:- containerPort: 8888---apiVersion: v1kind: Servicemetadata:name: ping-grpclabels:app: ping-grpcspec:ports:- port: 10005name: grpcselector:app: ping-grpc---apiVersion: apps/v1kind: Deploymentmetadata:name: ping-grpcspec:replicas: 1selector:matchLabels:app: ping-grpctemplate:metadata:labels:app: ping-grpcspec:containers:- name: ping-grpcimage: registry.cn-beijing.aliyuncs.com/hxpdocker/ping-grpc:latestresources:requests:cpu: "100m"memory: "128Mi"imagePullPolicy: Alwaysports:- containerPort: 10005
ef-reverse-bridge.yaml
kubectl apply -f ef-reverse-bridge.yaml -n istio
---apiVersion: networking.istio.io/v1alpha3kind: EnvoyFiltermetadata:name: lab-testspec:workloadSelector:labels:app: ping-httpconfigPatches:- applyTo: HTTP_FILTERmatch:context: SIDECAR_INBOUNDlistener:portNumber: 8888filterChain:filter:name: envoy.filters.network.http_connection_managersubFilter:name: envoy.filters.http.routerpatch:operation: INSERT_BEFOREvalue:name: envoy.filters.http.grpc_http1_reverse_bridgetyped_config:"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_http1_reverse_bridge.v3.FilterConfigcontent_type: application/grpc+protowithhold_grpc_frames: true
测试
grpcurl -v -proto ./proto/SP/Rpc/ping_service.proto -plaintext -import-path ./proto -d '{}' 10.68.10.2:10005 sp.rpc.PingService/PingResolved method descriptor:rpc Ping ( .google.protobuf.Empty ) returns ( .google.protobuf.Empty );Request metadata to send:(empty)Response headers received:content-type: application/grpcdate: Fri, 15 Oct 2021 05:16:59 GMTserver: istio-envoyx-envoy-decorator-operation: ping-grpc.istio.svc.cluster.local:10005/*x-envoy-upstream-service-time: 0Response contents:{}Response trailers received:(empty)Sent 1 request and received 1 response[root@node01 istio-grpc-http1-reverse-bridge]# grpcurl -v -proto ./proto/SP/Rpc/ping_service.proto -plaintext -import-path ./proto -d '{}' 10.68.117.193:8888 sp.rpc.PingService/PingResolved method descriptor:rpc Ping ( .google.protobuf.Empty ) returns ( .google.protobuf.Empty );Request metadata to send:(empty)Response headers received:content-type: application/grpcdate: Fri, 15 Oct 2021 05:23:09 GMTserver: istio-envoyx-envoy-decorator-operation: ping-http.istio.svc.cluster.local:8888/*x-envoy-upstream-service-time: 0Response contents:{}Response trailers received:(empty)Sent 1 request and received 1 response
3.3gRPC statistics
例子来自:https://github.com/envoyproxy/envoy/tree/main/examples/grpc-bridge
bridge-deploy.yaml
kubectl apply -f bridge-deploy.yaml -n istio
---apiVersion: apps/v1kind: Deploymentmetadata:name: grpc-serverlabels:app: grpc-serverspec:selector:matchLabels:app: grpc-serverreplicas: 1template:metadata:labels:app: grpc-serverversion: v1spec:containers:- name: csrfimage: registry.cn-beijing.aliyuncs.com/hxpdocker/grpc-bridge-server:latestimagePullPolicy: Alwaysports:- containerPort: 8081---apiVersion: v1kind: Servicemetadata:name: grpc-serverspec:selector:app: grpc-serverports:- name: grpc-serverprotocol: TCPport: 8081targetPort: 8081---apiVersion: apps/v1kind: Deploymentmetadata:name: grpc-clientlabels:app: grpc-clientspec:selector:matchLabels:app: grpc-clientreplicas: 1template:metadata:labels:app: grpc-clientversion: v1spec:containers:- name: csrfimage: registry.cn-beijing.aliyuncs.com/hxpdocker/grpc-bridge-client:latestimagePullPolicy: Alwaysenv:- name: CLIENT_PROXYvalue: http://grpc-server:8081
ef-statistics-client.yaml
kubectl apply -f ef-statistics-client.yaml -n istio
apiVersion: networking.istio.io/v1alpha3kind: EnvoyFiltermetadata:name: grpc-clientspec:workloadSelector:labels:app: grpc-clientconfigPatches:- applyTo: HTTP_FILTERmatch:context: SIDECAR_OUTBOUNDlistener:name: 0.0.0.0_8081filterChain:filter:name: envoy.filters.network.http_connection_managersubFilter:name: envoy.filters.http.routerpatch:operation: INSERT_BEFOREvalue:name: envoy.filters.http.grpc_http1_bridgetyped_config:"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_http1_bridge.v3.Config- applyTo: HTTP_FILTERmatch:context: SIDECAR_OUTBOUNDlistener:name: 0.0.0.0_8081filterChain:filter:name: envoy.filters.network.http_connection_managersubFilter:name: envoy.filters.http.routerpatch:operation: INSERT_BEFOREvalue:name: envoy.filters.http.grpc_statstyped_config:"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfigemit_filter_state: truestats_for_all_methods: trueenable_upstream_stats: true
3.4grpc web
web-grpc-deploy.yaml
kubectl apply -f web-grpc-deploy.yaml -n istio
---apiVersion: apps/v1kind: Deploymentmetadata:name: web-grpclabels:app: web-grpcspec:selector:matchLabels:app: web-grpcreplicas: 1template:metadata:labels:app: web-grpcversion: v1spec:containers:- name: csrfimage: registry.cn-hangzhou.aliyuncs.com/hxpdocker/server:latestimagePullPolicy: Alwaysports:- containerPort: 50051---apiVersion: v1kind: Servicemetadata:name: web-grpcspec:selector:app: web-grpcports:- name: grpc-web-grpcprotocol: TCPport: 50051targetPort: 50051---apiVersion: apps/v1kind: Deploymentmetadata:name: web-grpc-clientlabels:app: web-grpc-clientspec:selector:matchLabels:app: web-grpc-clientreplicas: 1template:metadata:labels:app: web-grpc-clientversion: v1spec:containers:- name: csrfimage: registry.cn-hangzhou.aliyuncs.com/hxpdocker/client:latestimagePullPolicy: Alwaysports:- containerPort: 8080---apiVersion: v1kind: Servicemetadata:name: web-grpc-clientspec:selector:app: web-grpc-clientports:- name: http-web-grpc-clientprotocol: TCPport: 8080targetPort: 8080
注意svc的port的名字grpc-web-grpc,表名用的是grpc协议
vs
vs-web-grpc.yaml
kubectl apply -f vs-web-grpc.yaml -n istio
apiVersion: networking.istio.io/v1beta1kind: VirtualServicemetadata:name: web-grpcspec:hosts:- "*"gateways:- bookinfo-gatewayhttp:- match:- uri:prefix: /s12.examplecorsPolicy:allowOrigins:- exact: http://192.168.198.154:30986- exact: http://192.168.198.154:8081allowMethods:- GET- OPTIONS- POST- PUT- DELETEmaxAge: "1m"allowHeaders:- keep-alive- user-agent- cache-control- content-type- content-transfer-encoding- custom-header-1- x-accept-content-transfer-encoding- x-accept-response-streaming- x-user-agent- x-grpc-web- grpc-timeoutexposeHeaders:- custom-header-1- grpc-status- grpc-messageroute:- destination:host: web-grpc.istio.svc.cluster.localport:number: 50051
vs-web-grpc-client.yaml
kubectl apply -f vs-web-grpc-client.yaml -n istio
apiVersion: networking.istio.io/v1beta1kind: VirtualServicemetadata:name: bookinfospec:hosts:- "*"gateways:- bookinfo-gatewayhttp:- match:- uri:prefix: /route:- destination:host: web-grpc-client.istio.svc.cluster.localport:number: 8080
ef-web-grpc.yaml
kubectl apply -f ef-web-grpc.yaml -n istio
apiVersion: networking.istio.io/v1alpha3kind: EnvoyFiltermetadata:name: grpcspec:workloadSelector:labels:app: web-grpcconfigPatches:- applyTo: HTTP_FILTERmatch:listener:filterChain:destinationPort: 50051transportProtocol: "tls"filter:name: envoy.filters.network.http_connection_managersubFilter:name: istio.metadata_exchangepatch:operation: INSERT_BEFOREvalue:name: envoy.filters.http.grpc_webtyped_config:"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
访问:
http://192.168.198.154:30986/
3.5gRPC-JSON transcoder
wind.proto
syntax = "proto3";import "google/api/annotations.proto";package wind_power;service WindServer {rpc wind_predict(Request) returns (Response) {option (google.api.http) = {get: "/predict"};}rpc send_data(Request) returns (Response) {option (google.api.http) = {post: "/send",body: "*"};}}message Request {string content = 1;}message Response {string msg = 1;int32 code = 2;}
生成pb
python -m grpc_tools.protoc -I../../googleapis-master -I. \--include_imports --include_source_info --descriptor_set_out=proto.pb \--python_out=.. --grpc_python_out=.. wind.proto
需要先将googleapis这个googleapis项目下载都指定的路径下,并将上述命令中的第一个-I替换成googleapis所在的路径。
服务端代码:
import grpcimport loggingfrom concurrent import futuresimport proto.wind_pb2 as wind_pb2import proto.wind_pb2_grpc as wind_pb2_grpcclass WindPredictSrv(wind_pb2_grpc.WindServerServicer):def wind_predict(self, request, context):print("call wind_predict")return wind_pb2.Response(msg='%s!' % request.content)def send_data(self, request, context):print("call send_data")return wind_pb2.Response(msg='%s!' % request.content)def server():grpc_server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))wind_pb2_grpc.add_WindServerServicer_to_server(WindPredictSrv(), grpc_server)grpc_server.add_insecure_port('[::]:50052')grpc_server.start()grpc_server.wait_for_termination()if __name__ == '__main__':logging.basicConfig()server()
客户端代码:
import grpcimport loggingimport timeimport sysimport proto.wind_pb2 as wind_pb2import proto.wind_pb2_grpc as wind_pb2_grpcdef run():option = [('grpc.keepalive_timeout_ms', 10000)]while True:with grpc.insecure_channel(target='wind-server:50052', options=option) as channel:stub = wind_pb2_grpc.WindServerStub(channel)request = wind_pb2.Request(content='hello grpc')response = stub.wind_predict(request, timeout=10)print("Greeter client received: " + response.msg)sys.stdout.flush()time.sleep(2)if __name__ == '__main__':logging.basicConfig()run()
部署文件
grpc-json-deploy.yaml
kubectl apply -f grpc-json-deploy.yaml -n istio
---apiVersion: apps/v1kind: Deploymentmetadata:name: wind-serverlabels:app: wind-serverspec:selector:matchLabels:app: wind-serverreplicas: 1template:metadata:labels:app: wind-serverversion: v1spec:containers:- name: csrfimage: registry.cn-beijing.aliyuncs.com/hxpdocker/wind-server:latestimagePullPolicy: Alwaysports:- containerPort: 50052---apiVersion: v1kind: Servicemetadata:name: wind-serverspec:selector:app: wind-serverports:- name: grpc-wind-serverprotocol: TCPport: 50052targetPort: 50052---apiVersion: apps/v1kind: Deploymentmetadata:name: wind-clientlabels:app: wind-clientspec:selector:matchLabels:app: wind-clientreplicas: 1template:metadata:labels:app: wind-clientversion: v1annotation:sidecar.istio.io/userVolume: '[{"name":"proto-file","hostPath":{"path":"/var/lib/"}}]’sidecar.istio.io/userVolumeMount: '[{"mountPath":"/etc/envoy/","name":"proto-file"}]'spec:containers:- name: csrfimage: registry.cn-beijing.aliyuncs.com/hxpdocker/wind-client:latestimagePullPolicy: Always
client 使用了hostPath,这个目录放pb文件
grpc-json-client.yaml
kubectl apply -f grpc-json-client.yaml -n istio
apiVersion: networking.istio.io/v1alpha3kind: EnvoyFiltermetadata:name: grpcspec:workloadSelector:labels:app: wind-clientconfigPatches:- applyTo: NETWORK_FILTERmatch:context: SIDECAR_OUTBOUNDlistener:name: 0.0.0.0_50052filterChain:filter:name: envoy.filters.network.http_connection_managerpatch:operation: MERGEvalue:name: envoy.filters.network.http_connection_managertypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManagerstat_prefix: grpc_jsoncodec_type: AUTOroute_config:name: local_routevirtual_hosts:- name: local_servicedomains: ["*"]routes:- match:prefix: "/wind_power.WindServer"route:cluster: outbound|50052||wind-server.istio.svc.cluster.localtimeout: 60s- applyTo: HTTP_FILTERmatch:context: SIDECAR_OUTBOUNDlistener:name: 0.0.0.0_50052filterChain:filter:name: envoy.filters.network.http_connection_managersubFilter:name: envoy.filters.http.routerpatch:operation: INSERT_BEFOREvalue:name: envoy.filters.http.grpc_json_transcodertyped_config:"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoderproto_descriptor: "/etc/envoy/proto.pb"services: ["wind_power.WindServer"]print_options:add_whitespace: truealways_print_primitive_fields: truealways_print_enums_as_ints: falsepreserve_proto_field_names: false
本文例子来自:
https://www.jianshu.com/p/a7e86058bf21




