×
Community Blog Request gRPC Services in the Mesh by HTTP through ASM Ingress Gateway

Request gRPC Services in the Mesh by HTTP through ASM Ingress Gateway

This article introduces the protocol transcoding capability of ASM Ingress Gateway.

Overview

This article introduces the protocol transcoding capability of ASM Ingress Gateway. This capability enables users and their clients to access Google Remote Procedure Call (gRPC) services in the service mesh through HTTP or JSON.

ASM Ingress Gateway can transcode HTTP and JSON requests to access gRPC services. The following figure shows the complete process of the HTTP request, gRPC transcoding, and gRPC request.

1

  1. The ASM control layer delivers EnvoyFilter (for gRPC transcoding) and Gateway and VirtualService (rule configuration for routing to the gRPC service port) to ASM Ingress Gateway. ASM Ingress Gateway loads them and takes effect after receiving them.
  2. After receiving an HTTP request from a user or client, ASM Ingress Gateway performs routing rule matching and protocol conversion. Then, it requests gRPC services in the service mesh based on the gRPC protocol.
  3. Ingress Gateway receives the gRPC response from the backend service, converts the response into an HTTP response, and returns it to the requester.

Principles and Objectives

As a proxy component of the ASM data layer, Envoy provides multiple built-in HTTP filters. This article describes a transcoder among these filters that transcode HTTP requests to gRPC requests. Envoy defines the corresponding filter protocol called config.filter.http.transcoder.v2.GrpcJsonTranscoder to enable this filter. Therefore, in the ServiceMesh control layer, an EnvoyFilter must be defined to declare the phase and place where the filter is enabled. Then, the EnvoyFilter is delivered to enable the transcoder in a specified phase. The transcoder needs to know the specific protocol of gRPC services, including the Proto Descriptors file that describes gRPC services and the full name list of gRPC services.

Envoy is the core component of ASM Ingress Gateway. Therefore, for Ingress Gateway transcoding, the key is to generate the EnvoyFilter for gRPC transcoding.

It is time-consuming and error-prone to write an EnvoyFilter because its definition is complex. This article provides an automatic EnvoyFilter generation tool, grpc-transcoder. This tool can generate the correct EnvoyFilter and save time.

Practice

1. gRPC Services

Normally, gRPC services of users begin with the definition of gRPC service protocol files in the protobuf format (.proto), as shown in the following figure. grpc-service-project implements gRPC services after encapsulating the gRPC interface. The subsequent steps include image building and Deployment writing. Finally, gRPC services are deployed to an ACK cluster as a pod through ASM.

2

A definition that supports transcoding in .proto needs to be confirmed to support gRPC transcoding. The following code is an example of the proto in hello-servicemesh-grpc.

import "google/api/annotations.proto";
service LandingService {
  //Unary RPC
  rpc talk (TalkRequest) returns (TalkResponse) {
    option(google.api.http) = {
      get: "/v1/talk/{data}/{meta}"
    };
  }
...
}

message TalkRequest {
  string data = 1;
  string meta = 2;
}

Code from Line 5 to 7 is an added declaration for supporting the transcoding, and Line 1 introduces the .proto declaration of corresponding capability. If there is no corresponding declaration in .proto, please add it. The addition of declaration aims to generate Proto Descriptors (PD) files but does not affect grpc-service-project and subsequent steps.

2. PD Files Generation

Take hello-servicemesh-grpc as an example. The protoc commands are used to generate the landing.proto-descriptor file from landing.proto. If protoc is not installed, you can download it here.

# https://github.com/AliyunContainerService/hello-servicemesh-grpc
proto_path={path/to/hello-servicemesh-grpc}/proto
# https://github.com/grpc-ecosystem/grpc-gateway/tree/master/third_party/
proto_dep_path={path/to/third_party}
protoc \
    --proto_path=${proto_path} \
    --proto_path=${proto_dep_path} \
    --include_imports \
    --include_source_info \
    --descriptor_set_out=landing.proto-descriptor \
    "${proto_path}"/landing.proto

3. EnvoyFilter Generation

Now, the PD file "landing.proto-descriptor" is generated. Next, generate EnvoyFilter through grpc-transcoder. The sample request for calling the interface is listed below:

grpc-transcoder \
--version 1.7 \
-- service_port 9996 \
-- service_name grpc-server-svc \
--proto_pkg org.feuyeux.grpc \
--proto_svc LandingService \
--descriptor landing.proto-descriptor

Parameter Description:

  • version: This parameter is required. ASM clusters are hosted clusters, so the version upgrades should not affect EnvoyFilter.
  • service_port: This parameter specifies the corresponding gRPC service port, as shown in the following figure.
  • service_name: This parameter specifies the corresponding gRPC service name, as shown in the following figure.
  • proto_pkg: This parameter specifies the package name definition in the gRPC service .proto.
  • proto_svc: This parameter specifies the service name definition in the gRPC service .proto.
  • descriptor: This parameter specifies the local path of the PD file.

3

Use the request above to automatically generate EnvoyFilter (grpc-transcoder-envoyfilter.yaml) as shown in the following code:

#Generated by ASM(http://servicemesh.console.aliyun.com)
#GRPC Transcoder EnvoyFilter[1.7]
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: grpc-transcoder-grpc-server-svc
spec:
  workloadSelector:
    labels:
      app: istio-ingressgateway
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          portNumber: 9996
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
              subFilter:
                name: "envoy.filters.http.router"
        proxy:
          proxyVersion: ^1\.7.*
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.grpc_json_transcoder
          typed_config:
            '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder
            proto_descriptor_bin: Ctl4ChVnb29nbGUvYXBpL2h0dHAucHJ...
            services: 
            - org.feuyeux.grpc.LandingService
            print_options:
              add_whitespace: true
              always_print_primitive_fields: true
              always_print_enums_as_ints: false
              preserve_proto_field_names: false

4. Transcoder Enabled by ASM Ingress Gateway

After generating the EnvoyFilter using the tool, submit the generated EnvoyFilter (grpc-transcoder-envoyfilter.yaml) on the ASM console. The transcoder takes effect immediately.

4

The preceding step is equivalent to running the "kubectl --kubeconfig mes_config -f grpc-transcoder-envoyfilter.yaml -n istio-system" command. At this point, the configuration is completed. The complete flow diagram is shown below:

5

5. Envoy Configuration Verification

Next, check whether the Envoy configuration of Ingress Gateway is available. Run the following commands in sequence to check whether the configuration of transcoder GrpcJsonTranscoder is contained in the Envoy dynamic configuration.

# Obtain the pod name of Ingress Gateway
ingressgateway_pod=$(kubectl get pod -l app="istio-ingressgateway" -n istio-system -o jsonpath='{.items[0].metadata.name}')
# Timestamp
timestamp=$(date "+%Y%m%d-%H%M%S")
# Obtain the Envoy dynamic configuration and save it to dynamic_listeners-"$timestamp".json
kubectl -n istio-system exec $ingressgateway_pod \
  -c istio-proxy \
  -- curl -s "http://localhost:15000/config_dump?resource=dynamic_listeners" >dynamic_listeners-"$timestamp".json
# Check whether GrpcJsonTranscoder exists in the configuration
grep -B3 -A7 GrpcJsonTranscoder dynamic_listeners-"$timestamp".json

Envoy dynamic configuration should contain the configuration similar to the following example:

{
  "name": "envoy.grpc_json_transcoder",
  "typed_config": {
    "@type": "type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder",
    "services": [
      "org.feuyeux.grpc.LandingService"
    ],
    "print_options": {
      "add_whitespace": true,
      "always_print_primitive_fields": true
    },
    ...

6. Function Verification

The last step is to verify the function of requesting for the gRPC service in the mesh through HTTP.

The following statement is the definition of the gRPC service interface.

rpc talk (TalkRequest) returns (TalkResponse) {
  option(google.api.http) = {
    get: "/v1/talk/{data}/{meta}"
  };
}

A response declaration defined in .proto to verify the response:

message TalkResponse {
  int32 status = 1;
  repeated TalkResult results = 2;
}

message TalkResult {
  //timestamp
  int64 id = 1;
  //enum
  ResultType type = 2;
  // id:result uuid
  // idx:language index
  // data: hello
  // meta: serverside language
  map kv = 3;
}

enum ResultType {
  OK = 0;
  FAIL = 1;
}

Execute the following commands in sequence to verify whether the gRPC service interface can be called through the HTTP request in Ingress Gateway:

# Obtain the IP address of Ingress Gateway
INGRESS_IP=$(k -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
# HTTP requests for port 9996 and path /v1/talk/{data}/{meta} of Ingress Gateway
curl http://$INGRESS_IP:9996/v1/talk/0/java

The response should be like this:

{
 "status": 200,
 "results": [
  {
   "id": "699882576081691",
   "type": "OK",
   "kv": {
    "data": "Hello",
    "meta": "JAVA",
    "id": "8c175d5c-d8a3-4197-a7f8-6e3e0ab1fe59",
    "idx": "0"
   }
  }
 ]
}
0 0 0
Share on

feuyeux

6 posts | 0 followers

You may also like

Comments

feuyeux

6 posts | 0 followers

Related Products