NGINX 代理 gRPC 请求

我的博客服务器开放了两个端口,一个用于服务 HTTP 请求,一个用于服务客户端的 gRPC 请求。

后来对 gRPC 了解更深入之后,发现其底层的传输层协议其实是基于 HTTP/2 的。同时,看到了 NGINX 官方的 gRPC 支持。 于是想用 NGINX 代理 gRPC 请求,这样就不用再考虑 gRPC 的安全问题了(但 HTTP/2 并非一定是 HTTPS 的)。

安全问题是其一,最大的好处,我觉得是:

不用在配置文件中区别对待 HTTP 和 gRPC 地址了

检测 NGINX 是否支持

NGINX 从版本 v1.13.10 开始支持 gRPC 代理系列指令(参考:nginx_http_grpc_module),并且开始了ngx_http_v2_module模块。

可以以下方式查看:

$ nginx -vV
nginx version: nginx/1.17.8
...
--with-http_v2_module
...

可以看到我的版本高于 v1.13.10 并且有 http_v2_module

NGINX 的简单配置

然后就可以像下面这样一句话实现代理 gRPC 请求:

server {
    # 省略其它配置

    location / {
        grpc_pass grpc://localhost:2563;
    }
}

grpc_passproxy_pass 的用法非常类似。 其中,grpc:// 是可选的,如果 gRPC 是安全连接,则应该用grpcs://

gRPC 客户端的配置

然后修改你的 gRPC 客户端的代码,把原来的 gRPC 地址改成 NGINX 的地址即可。 注意::gRPC 的地址是没有协议头的,即应去掉 NGINX 地址中的 http://https://,但是端口却是必填的。比如:

  • 你的 nginx 地址是 http://example.com,则 gRPC 地址:example.com:80
  • 你的 nginx 地址是 https://example.com,则 gRPC 地址:example.com:443
  • 你的 nginx 地址是 http://example.com:8080,则 gRPC 地址:example.com:8080

对于 gRPC 客户端,如果 nginx 是不安全连接(非 HTTPS),则应该使用类似下面的代码:

conn, err := grpc.Dial(
    endpoint,
    grpc.WithInsecure(),
)

而如果是安全的(使用了有效的 HTTPS 证书):

conn, err := grpc.Dial(
    endpoint,
    grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})),
)

而如果是使用了自签(或过期等)证书,并且想忽略安全检测:

conn, err := grpc.Dial(
    endpoint,
    grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
        InsecureSkipVerify: true,
    })),
)

也可以客户端自己添加服务端证书以校验,本文从略,有需要再添加。(考虑到应该少有 nginx 服务器使用不安全的证书)

NGINX 根据 gRPC 方法路由代理

首先,需要知道你的 Protocol Buffer 包的方法全称

打开你的 PB 生成的RPC 服务对应的*.pb.go文件,比如:service.pb.go。 然后搜索 Invoke 或者 FullMethod,你应该会看到类似/protocols.TaoBlog/ListComments的字符串,这些就是方法全称。 双斜杠//内的是包名.服务名,然后是方法名

如果要根据包名.服务名来路由,则可以像下面这样:

location /protocols.TaoBlog/ {
    grpc_pass grpc://192.168.20.11:50051;
}

location /helloworld.Greeter/ {
    grpc_pass grpc://192.168.20.11:50052;
}

NGINX 中 gRPC 服务器的负载均衡

gRPC 微服务很多,负载均衡无可避免。

使用 NGINX 自带的 upstream 即可。

upstream grpcservers {
    server 192.168.20.11:50051;
    server 192.168.20.12:50051;
}

server {
    # 省略其它常用配置

    location /helloworld.Greeter/ {
        grpc_pass grpc://grpcservers;
    }
}

其它

我只使用了nginx_http_grpc_module模块的一条指令完成了 NGINX 对 gRPC 的代理。 如果需要更多配置,请参阅 NGINX 相关文档。

参考

发表于:2020年4月18日 ,阅读量:206 ,标签:代理 · nginx · gRPC