基于云原生API网关实现gRPC服务的路由转发

gRPC使用HTTP/2协议,支持双向流、头部压缩和多路复用等特性,从而提高了网络传输的效率。本文介绍如何在容器服务 Kubernetes 版集群部署gRPC应用,并使用云原生API网关实现gRPC服务的路由转发。

前提条件

步骤一:使用容器服务部署gRPC应用

应用部署的具体操作,请参见创建无状态工作负载Deployment

在本示例中,使用容器服务K8s原生的服务发现方式,即通过声明式Service API资源将后端服务注册到CoreDNS。本示例中使用grpcbin应用作为后端服务示例,该应用提供了多个gRPC服务的实现。在容器服务ACK中应用如下资源。

说明

gRPC服务在Kubernetes service中port字段下的name必须包含grpc。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: grpcbin
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grpcbin
  template:
    metadata:
      labels:
        app: grpcbin
    spec:
      serviceAccountName: grpcbin
      containers:
      - image: docker.io/moul/grpcbin
        imagePullPolicy: IfNotPresent
        name: grpcbin
        ports:
        - containerPort: 9000
        - containerPort: 9001
        resources:
            requests:
              cpu: '1'
              memory: 2Gi
            limit:
              cpu: '1'
              memory: 2Gi
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: grpcbin
---
apiVersion: v1
kind: Service
metadata:
  name: grpcbin-grpc
  labels:
    app: grpcbin
spec:
  ports:
  - name: grpc
    port: 9000
    targetPort: 9000
  selector:
    app: grpcbin

以下代码展示该gRPC服务的proto定义。

syntax = "proto3";

package grpcbin;

service GRPCBin {
  rpc Index(EmptyMessage) returns (IndexReply) {}
  // 无参数调用的方法,调用后回返回一个空响应
  rpc Empty(EmptyMessage) returns (EmptyMessage) {}
  // 响应会返回请求的参数
  rpc DummyUnary(DummyMessage) returns (DummyMessage) {}
  // 响应为流式的调用,会分10次响应消息
  rpc DummyServerStream(DummyMessage) returns (stream DummyMessage) {}
  // 请求为流式的调用,会接受10次请求并返回最后一次的body
  rpc DummyClientStream(stream DummyMessage) returns (DummyMessage) {}
  // 请求响应都为流式的方法
  rpc DummyBidirectionalStreamStream(stream DummyMessage) returns (stream DummyMessage) {}
  // 该方法会返回指定的grpc错误
  rpc SpecificError(SpecificErrorRequest) returns (EmptyMessage) {}
  // 该方法调用会随机返回一个错误
  rpc RandomError(EmptyMessage) returns (EmptyMessage) {}
  // 该方法调用会返回header
  rpc HeadersUnary(EmptyMessage) returns (HeadersMessage) {}
  // 该方法调用不会返回响应
  rpc NoResponseUnary(EmptyMessage) returns (EmptyMessage) {}
}

message HeadersMessage {
  message Values {
    repeated string values = 1;
  }
  map<string, Values> Metadata = 1;
}

message SpecificErrorRequest {
  uint32 code = 1;
  string reason = 2;
}

message EmptyMessage {}

message DummyMessage {
  message Sub {
    string f_string = 1;
  }
  enum Enum {
    ENUM_0 = 0;
    ENUM_1 = 1;
    ENUM_2 = 2;
  }
  string f_string = 1;
  repeated string f_strings = 2;
  int32 f_int32 = 3;
  repeated int32 f_int32s = 4;
  Enum f_enum = 5;
  repeated Enum f_enums = 6;
  Sub f_sub = 7;
  repeated Sub f_subs = 8;
  bool f_bool = 9;
  repeated bool f_bools = 10;
  int64 f_int64 = 11;
  repeated int64 f_int64s= 12;
  bytes f_bytes = 13;
  repeated bytes f_bytess = 14;
  float f_float = 15;
  repeated float f_floats = 16;
}

message IndexReply {
  message Endpoint {
    string path = 1;
    string description = 2;
  }
  string description = 1;
  repeated Endpoint endpoints = 2;
}

gRPC服务底层基于HTTP/2协议,其路径格式为{包名}.{服务名}/{方法名}。基于此,云原生API网关可以在Path字段中实现对gRPC协议的路由。例如,如果使用gRPC访问grpcbin的Index方法,在协议中,该Path字段值为grpcbin.GRPCBin/Index。

步骤二:使用云原生API网关作为gRPC的路由分发

添加ACK集群作为网关的服务来源并添加grpcbin服务。

添加服务来源

  1. 登录云原生API网关控制台

  2. 在左侧导航栏,选择实例,并在顶部菜单栏选择地域。

  3. 实例页面,单击目标网关实例名称。

  4. 在左侧导航栏,选择服务,并单击来源页签。

  5. 单击创建来源。在创建来源面板,服务来源选择容器服务,配置相关参数,然后单击确定

    配置项

    说明

    ACK/ACK Serverless 集群

    选择后端服务所在的集群。

    说明

    您在创建网关时需要选择和后端集群相同的VPC,那么服务来源添加时会自动获取该VPC下的集群。

    监听K8s Ingress

    • 开启监听Ingress配置后,云原生API网关会自动监听Ingress资源的变化,并使Ingress资源中域名、路由的相关配置生效。

    • 关闭监听Ingress配置后,云原生API网关会放弃监听Ingress资源,并失效之前已监听的Ingress资源中的域名、路由相关配置,请您谨慎操作。

    重要

    通过管控手动配置的域名、路由的相关配置,其优先级高于Ingress资源。

    IngressClass

    监听关联指定IngressClass的Ingress资源。

    • 当配置成空值时,监听集群中所有的Ingress资源。

    • 当配置成具体值时(仅支持单个值,暂不支持批量配置),监听集群中带有class注解或者Spec.IngressClassName的值与配置值一致的Ingress资源。例如,当配置成nginx时,监听的Ingress资源包括:IngressClass为nginx或者未关联任何IngressClass的Ingress资源。

    监听命名空间

    监听指定命名空间的Ingress资源。

    • 当配置成空值时,监听集群中所有命名空间中的Ingress资源。

    • 当配置成具体值时(仅支持单个值,暂不支持批量配置),监听集群中指定命名空间中的Ingress资源。

    更新IngressStatus

    开启更新IngressStatus后,被监听的Ingress的Status中IP地址会被修改为云原生API网关关联的SLB IP地址。

    说明

    网关版本为1.2.9及以上才能修改此行为。

    安全组授权

    容器集群的节点池上配置有安全组。通常情况下,集群外的组件要想访问到集群内的服务,就必须在安全组上开放服务所需的全部端口。

    您可以对安全组进行修改。具体操作,请参见设置安全组规则

添加服务

  1. 登录云原生API网关控制台

  2. 在左侧导航栏,选择实例,并在顶部菜单栏选择地域。

  3. 实例页面,单击目标网关实例名称。

  4. 在左侧导航栏,选择服务,并单击服务页签。

  5. 单击创建服务并配置面板中的相关参数,然后单击确定

    配置项

    说明

    服务来源

    选择容器服务

    命名空间

    选择目标集群的命名空间。

    服务列表

    在服务列表中选择服务。

添加网关到grpcbin服务的路由

  1. 创建HTTP API,具体操作,请参见创建HTTP API

  2. 单击目标API,在左上角单击创建路由

  3. 创建路由页面,配置路由相关参数,然后单击保存并发布。具体操作,请参见创建路由

    配置项

    说明

    路由名称

    设置为grpc。

    域名

    选择默认域名*。

    路径

    选择匹配条件为前缀是,Path以/grpcbin.GRPCBin开头。

    说明

    gRPC服务的路径名格式为{包名}.{服务名}/{方法名},因此可以配置对应的前缀路由。

    使用场景

    选择该路由的使用场景为单服务

    后端服务

    选择目标服务以及服务端口。

结果验证

使用bloomrpc测试gRPC服务的可用性,若服务端正常返回响应,则表示gRPC服务可用。

同时您也可以使用其他gRPC客户端进行测试。测试gRPC服务可用性