通过Envoy将grpc转换为http json
转载自微信公众号:niceelegant
一/检查grpc安装
后端服务之间的通信使用gRPC是常规方案,通过proto文件定义交互接口,通过工具生成gRPC
原始proto文件(截取自 grpc/example/helloworld.proto)
21 package helloworld;
22
23 // The greeting service definition.
24 service Greeter {
25 // Sends a greeting
26 rpc SayHello (HelloRequest) returns (HelloReply) {}
27 }
28
29 // The request message containing the user's name.
30 message HelloRequest {
31 string name = 1;
32 }
33
34 // The response message containing the greetings
35 message HelloReply {
36 string message = 1;
37 }
首先检查grpc安装是否有问题,测试运行grpc example 是否正常
$ pwd
$GOPATH/src/google.golang.org/grpc/examples/helloworld
$ go run greeter_server/main.go
//另一个窗口 another terminal
$ pwd
$GOPATH/src/google.golang.org/grpc/examples/helloworld
$ go run greeter_client/main.go
2019/04/03 10:53:00 Greeting: Hello world
如果以上步骤 都正常 ,那么grpc本身安装是没有问题的,如果出现故障,那么请参考grpc安装的文档。
二/配置准备
2.1 安装GOOGLEAPIS包
$ pwd
$GOPATH/src/github.com/googleapis/
$ git clone https://github.com/googleapis/googleapis
GOOGLEAPIS_DIR=<your-local-googleapis-folder>
$ echo $GOOGLEAPIS_DIR
$GOPATH/src/github.com/googleapis/googleapis
配置环境变量 export GOOGLEAPIS_DIR= $GOPATH/src/github.com/googleapis/googleapis
2.2 修改proto文件
14
15 syntax = "proto3";
16
17 option java_multiple_files = true;
18 option java_package = "io.grpc.examples.helloworld";
19 option java_outer_classname = "HelloWorldProto";
20 import "google/api/annotations.proto"; // #add
21
22 package helloworld;
23
24 // The greeting service definition.
25 service Greeter {
26 // Sends a greeting
27 rpc SayHello (HelloRequest) returns (HelloReply) {
28 option (google.api.http) = { // #add
29 post: "/say" // #add
30 body: "*" // #add
31
32 }; // #add
33 }
34
35 }
36
增加了 import “google/api/annotations.proto”;
增加了 option (google.api.http) 部分,主要作用是http请求路径
三/ Envoy配置与运行
3.1 envoy yml配置 s2s-grpc-envoy.yaml
static_resources:
listeners:
- name: listener1
address:
socket_address: { address: 0.0.0.0, port_value: 51051 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
stat_prefix: grpc_json
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: grpc, timeout: { seconds: 60 } }
http_filters:
- name: envoy.grpc_json_transcoder
config:
proto_descriptor: "/data/envoy/proto.pb" #
services: ["helloworld.Greeter"] #
print_options:
add_whitespace: true
always_print_primitive_fields: true
always_print_enums_as_ints: false
preserve_proto_field_names: false
- name: envoy.router
clusters:
- name: grpc
connect_timeout: 1.25s
type: logical_dns
lb_policy: round_robin
dns_lookup_family: V4_ONLY
http2_protocol_options: {}
load_assignment:
cluster_name: grpc
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1 # host.docker.internal
port_value: 50051
3.2 docker 脚本
protoc -I$GOOGLEAPIS_DIR -I. --include_imports --include_source_info --descriptor_set_out=proto.pb helloworld.proto
echo "---------------------"
docker run -it --rm --name envoy --network="host" \
-v "$(pwd)/proto.pb:/data/envoy/proto.pb:ro" \
-v "$(pwd)/s2s-grpc-envoy.yaml:/etc/envoy/envoy.yaml:ro" \
envoyproxy/envoy
作用含义:
1/解析 helloworld.proto 输出为 proto.pb
2/ docker运行脚本 以host模式运行,可以访问本地服务 同时load proto.pb .yml
输出日志中有: starting main dispatch loop 基本说明配置ok
3.3 运行grpc client
开一个 terminal 运行
$ pwd
$GOPATH/src/google.golang.org/grpc/examples/helloworld
$ go run greeter_server/main.go
四 测试http 访问grpc接口
curl -X POST \
http://localhost:51051/say \
-H 'Content-Type: application/json' \
-d '{
"name":"banana"
}'
正常返回值
"message": "Hello banana"
五/错误处理
5.1 http header里面 关注以下两个
**grpc-status
**grpc-message
根据报错信息处理
5.2 no healthy upstream 错误
原因是 无法 访问到 上一级服务 gRPC server
主要检查yml中的 ip port是否正确 容器内是否能访问到gRPC server
clusters:
socket_address:
address: 127.0.0.1 # host.docker.internal
port_value: 50051
本文使用的模式 是
参考文档: