探秘高效通信:grpc-http-proxy

探秘高效通信:grpc-http-proxy

:警告:这不是生产就绪的版本

grpc-http-proxy 是一个反向代理,它能够将JSON HTTP请求无缝转换为gRPC调用,几乎无需配置。特别设计用于Kubernetes集群中运行,它利用Kubernetes API通过自定义注解找到提供所需gRPC服务的内部服务器。

背景

尽管已存在如gRPC-gateway这样的解决方案,可以生成将JSON HTTP请求转化为gRPC调用的反向代理,但它们通常需要以下操作:

  • 手动在gRPC服务定义中添加自定义注解以定义HTTP端点到gRPC方法的映射。
  • 针对每个gRPC服务生成单独的反向代理。

随着gRPC服务规模的增长和更多服务的创建,这变得难以管理。

grpc-http-proxy 的目标是成为一个单一的反向代理,适用于所有gRPC服务,并避免繁琐的手动映射。这使得可以通过HTTP请求轻松访问gRPC服务。

工作原理

grpc-http-proxy 端点 /v1/<service>/<method> 发送请求,代理将会调用 <service> 中的 <method> 方法。

只要知道服务名称和服务方法,gRPC调用就可以按以下步骤进行:

  1. 使用gRPC服务器反射协议获取gRPC服务支持的方法以及消息格式的信息。
  2. 根据获取的信息,按照Proto3到JSON映射规范,将JSON请求体转换为Protobuf消息。
  3. 向上游服务发起gRPC调用。
  4. 将响应转换为JSON并返回给调用者。

如果HTTP请求头中的键以 Grpc-Metadata- 开头,则会将元数据传递给上游。

此外,grpc-http-proxy 可以通过设置访问令牌进行配置。如果有指定的访问令牌,只有包含在 X-Access-Token 头中的请求才会被处理。

通过自定义注解,在Kubernetes服务资源中定义gRPC服务名与上游Kubernetes服务之间的映射。监听Kubernetes API并保持这些映射的更新。

安装

使用Helm部署到Kubernetes集群:

$ git clone https://github.com/mercari/grpc-http-proxy && cd ./grpc-http-proxy
$ helm install --name grpc-http-proxy helm/grpc-http-proxy --namespace kube-system

默认在 kube-system 命名空间中无访问令牌部署。若需设置,可执行以下命令:

$ helm install --set accessToken SUPER_SECRET --name grpc-http-proxy helm/grpc-http-proxy --namespace kube-system

也有 values.yaml 文件供更详细的配置。

注意:目前Helm图表不支持RBAC,所以默认的pod ServiceAccount应该有权访问集群内的所有服务。

配置

安装后,需要一些配置让grpc-http-proxy找到你的服务。

启用gRPC反射

在你的gRPC服务器上启用服务器反射,请遵循这里的说明。

集群侧Kubernetes API服务发现设置

服务发现依赖于具有特定注解的Kubernetes服务。为了使grpc-http-proxy找到你的gRPC服务器,做以下操作:

1. 添加 grpc-service 注解

在Service上放置 grpc-http-proxy.alpha.mercari.com/grpc-service 注解。如果你的gRPC服务的全限定名为 my.package.MyService,则添加注解 grpc-http-proxy.alpha.mercari.com/grpc-service: my.package.MyService

  kind: Service
  apiVersion: v1
  metadata:
    name: my-service
    annotations:
+     grpc-http-proxy.alpha.mercari.com/grpc-service: my.package.MyService

如果你的gRPC服务器导出多个服务,可以用逗号(,)分隔列出它们。

  kind: Service
  apiVersion: v1
  metadata:
    name: my-service
    annotation:
+     grpc-http-proxy.alpha.mercari.com/grpc-service: my.package.MyService,my.anotherpackage.OtherService
2. 以 'grpc' 开头命名端口

grpc-http-proxy 将向名字以 'grpc' 开头的端口发送请求。如果有多个匹配的端口,会选择第一个。

如果打算使用的端口是Kubernetes Service暴露的唯一端口,这一步可以跳过。

  kind: Service
  apiVersion: v1
  metadata:
    name: my-service
    annotations:
      grpc-http-proxy.alpha.mercari.com/grpc-service: my.package.MyService
  spec:
    ports:
-   - name: foo
+   - name: grpc-foo
      port: 5000
      protocol: TCP
      targetPort: 5000
3. [可选] 添加 grpc-service-version 注解

如果你打算通过grpc-http-proxy调用多个版本的gRPC服务器,那么在Service上添加 grpc-http-proxy.alpha.mercari.com/grpc-service-version 注解。版本可以是你喜欢的任何字符串。

    annotations:
+    grpc-http-proxy.alpha.mercari.com/grpc-service-version: pr-42

示例

以下示例中,grpc-http-proxy 运行在 grpc-http-proxy.example.com,并且访问令牌设置为 foo。gRPC服务 Echo 如下.proto文件定义:

syntax = "proto3";

package com.example;

service Echo {
    rpc Say(EchoMessage) returns (EchoMessage) {};
}

message EchoMessage {
    string message_body = 1;
}

单一版本服务

Kubernetes Service清单如下:

kind: Service
apiVersion: v1
metadata:
  name: echo-service
  annotations:
    grpc-http-proxy.alpha.mercari.com/grpc-service: com.example.Echo
spec:
  ports:
  - name: grpc-echo
    port: 5000
    protocol: TCP
    targetPort: 5000

通过grpc-http-proxy调用Say及其响应如下:

$ curl -H'X-Access-Token: foo' -XPOST -d'{"message_body":"Hello, World!"}' grpc-http-proxy.example.com/v1/com.example.Echo/Say
{"message_body":"Hello, World!"}

多个版本的服务

假设你有同一个集群中的新版本 Echo 服务器,你想调用这个新版本。新服务器Service的清单应指定版本注解,如下所示:

kind: Service
apiVersion: v1
metadata:
  name: newer-echo-service
  annotations:
    grpc-http-proxy.alpha.mercari.com/grpc-service: com.example.Echo
    grpc-http-proxy.alpha.mercari.com/grpc-service-version: newer-version
spec:
  ports:
  - name: grpc-echo
    port: 5000
    protocol: TCP
    targetPort: 5000

选择新版本,只需在查询参数中添加注解中指定的版本名。调用新版本的 Say 和其响应如下:

$ curl -H'X-Access-Token: foo' -XPOST -d'{"message_body":"Hello, World!"}' grpc-http-proxy.example.com/v1/com.example.Echo/Say?version=newer-version
{"message_body":"Hello, World!"}

传递元数据到gRPC服务

要在调用 Echo 服务时传递键为 somekey 的元数据,像下面这样添加到HTTP请求中:

$ curl -H'X-Access-Token: foo' -H'Grpc-Metadata-somekey: value' -XPOST -d'{"message_body":"Hello, World!"}' grpc-http-proxy.example.com/v1/com.example.Echo/Say
{"message_body":"Hello, World!"}

待办事项

尚未实现的一些可能期望的功能包括:

  • 通过静态配置文件查找服务的能力。

欢迎贡献!

致谢

Tomoya TABUCHI (@tomoyat1) 是主要的开发者。

贡献指南

在提交您的贡献之前,请仔细阅读CLA。

https://www.mercari.com/cla/

许可证

版权2018年 Mercari, Inc.

授权MIT许可证。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

钟洁祺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值