2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

envoyのgrpc-jsonを試す

2
Posted at

背景

gRPCを直接たたけないclientがいるので、HTTPリクエストを変換してrpcをinvokeするのを試す

インストール

Mac:

brew install envoy

Other: https://www.envoyproxy.io/docs/envoy/latest/start/install#

Version

envoy --version

envoy  version: c919bdec19d79e97f4f56e4095706f8e6a383f1c/1.22.2/Modified/RELEASE/BoringSSL

gRPC-JSON transcoder

1. Protobuf作成

syntax = "proto3";

package helloworld;

option go_package = "github.com/nakamasato/envoy-training/grpc-json";

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello(HelloRequest) returns (HelloReply) {
  }
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

2. bufでコード生成

buf.yaml
version: v1
name: buf.build/nakamasato/grpc-json
buf.gen.yaml
version: v1
plugins:
  - name: go
    out: .
    opt: paths=source_relative
  - name: go-grpc
    out: .
    opt: paths=source_relative,require_unimplemented_servers=false
buf generate

これで、helloworld_grpc.pb.gohelloworld.pb.go が生成される

3. main.go作成

package main

import (
    "context"
    "log"
    "net"

    "google.golang.org/grpc"

    helloworldpb "github.com/nakamasato/envoy-training/grpc-json/protos"
)

type server struct {
    helloworldpb.UnimplementedGreeterServer
}

func NewServer() *server {
    return &server{}
}

func (s *server) SayHello(ctx context.Context, in *helloworldpb.HelloRequest) (*helloworldpb.HelloReply, error) {
    return &helloworldpb.HelloReply{Message: in.Name + " world"}, nil
}

func main() {
    // Create a listener on TCP port
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalln("Failed to listen:", err)
    }

    // Create a gRPC server object
    s := grpc.NewServer()
    // Attach the Greeter service to the server
    helloworldpb.RegisterGreeterServer(s, &server{})
    // Serve gRPC Server
    log.Println("Serving gRPC on 0.0.0.0:50051")
    log.Fatal(s.Serve(lis))
}

4. gRPC server起動

go run main.go

5. grpcurlでコール

grpcurl -d '{"name": "naka"}' -import-path ./protos -proto protos/helloworld.proto -plaintext localhost:50051 helloworld.Greeter/SayHello
{
  "message": "naka world"
}

6. protoの更新

以下を追加:

import "google/api/annotations.proto";
option (google.api.http) = {
  post: "/say"
  body: "*"
};

最終的なprotoはこちら

helloworld.proto
syntax = "proto3";

package helloworld;

import "google/api/annotations.proto";

option go_package = "github.com/nakamasato/envoy-training/grpc-json";

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello(HelloRequest) returns (HelloReply) {
    option (google.api.http) = {
      post : "/say"
      body : "*"
    };
  }
}

// The request message containing the user's name.
message HelloRequest { string name = 1; }

// The response message containing the greetings
message HelloReply { string message = 1; }

7. bufでコード生成

buf.yaml
version: v1
name: buf.build/nakamasato/grpc-json
deps:
  - buf.build/googleapis/googleapis
buf mod update
buf build --as-file-descriptor-set -o helloworld.pb

grpc-json transcoderがproto descriptorを必要とするのでoutputしておく

8. grpcurlとproto descriptorで確認

grpcurl -d '{"name": "naka"}' -protoset protos/helloworld.pb -plaintext localhost:50051 helloworld.Greeter/SayHello

9. envoy config準備

ほぼsample-exampleを使用

admin:
  address:
    socket_address: {address: 0.0.0.0, port_value: 9901}

static_resources:
  listeners:
  - name: listener1
    address:
      socket_address: {address: 0.0.0.0, port_value: 51051}
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: grpc_json
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              # NOTE: by default, matching happens based on the gRPC route, and not on the incoming request path.
              # Reference: https://envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/grpc_json_transcoder_filter#route-configs-for-transcoded-requests
              - match: {prefix: "/helloworld.Greeter"}
                route: {cluster: grpc, timeout: 60s}
          http_filters:
          - name: envoy.filters.http.grpc_json_transcoder
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder
              proto_descriptor: "protos/helloworld.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.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
  - name: grpc
    type: LOGICAL_DNS
    lb_policy: ROUND_ROBIN
    dns_lookup_family: V4_ONLY
    typed_extension_protocol_options:
      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
        explicit_http_config:
          http2_protocol_options: {}
    load_assignment:
      cluster_name: grpc
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: localhost
                port_value: 50051

10. envoy起動

envoy -c envoy.yaml

11. HTTP requestを確認

curl -d '{"name": "naka"}' http://localhost:51051/say
{
 "message": "naka world"
}

参考

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?