• Stars
    star
    371
  • Rank 115,103 (Top 3 %)
  • Language
    Go
  • License
    MIT License
  • Created about 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A reverse proxy server which translate JSON HTTP requests to gRPC calls based on protoreflect

grpc-http-proxy

CircleCI

⚠️ This is not production ready

grpc-http-proxy is a reverse proxy which converts JSON HTTP requests to gRPC calls without much configuration. It is designed to run in a Kubernetes cluster, and uses the Kubernetes API to find in-cluster servers that provide the desired gRPC service using custom Kubernetes annotations.

image

Background

Although existing solutions, such as grpc-gateway, generate reverse proxies that convert JSON HTTP requests to gRPC calls exist, they require the following to work:

  • Custom annotations to the gRPC service definitions must be manually be added to define the HTTP endpoint to gRPC method mappings.
  • The reverse proxy must be generated for each gRPC service.

As gRPC service definitions get larger, and more services are created, this can get unmanageable quickly.

grpc-http-proxy was created to be a single reverse proxy that works with all gRPC services, and without all the manual mapping. This enables gRPC services to be accessed through HTTP requests with less hassle than before.

How it works

image

A request to the grpc-http-proxy's endpoint /v1/<service>/<method> will make the proxy call the <method> method of the <service> gRPC service.

Given the service name and method name are known, the gRPC call is made in the following steps:

  1. The gRPC server reflection protocol is used to obtain information from the gRPC service on the supported methods and the format of messages.
  2. The JSON request body is converted, using the information obtained above, to the Protobuf message by following the Proto3 to JSON mapping specification.
  3. The gRPC call is made to the upstream service.
  4. The response is converted to JSON, and returned to the caller

Metadata is passed to the upstream if it is put in the HTTP request's header, with the key prefixed with Grpc-Metadata-.

Also, grpc-http-proxy itself can be configured with an access token. If so, only requests with the specified access token in the X-Access-Token header are handled.

Mappings between gRPC service names and the upstream Kubernetes Services are defined by a custom annotation in the Kubernetes Service resource. The Kubernetes API will be listened upon and the mapping will be kept up to date as Services with annotations are created, deleted, or updated.

Installation

Use Helm to deploy to a Kubernetes cluster.

$ 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

This will deploy grpc-http-proxy without an access token to the kube-system namespace . To specify one, set the accessToken value as follows:

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

Also, there is a values.yaml file for more in-depth configuration.

note: RBAC is currently not supported by the Helm chart, so the default pod ServiceAccount should have access to all services within the cluster.

Configuration

After installing grpc-http-proxy, some configuration is required to make it find your services.

Enable gRPC reflection

Enable server reflection in your gRPC servers by following the instructions found here.

Cluster side settings for Kubernetes API service discovery

The service discovery works by looking for Kubernetes Services with a specific annotation. In order to have it pick up the Kubernetes Service in front of your gRPC server, do the following.

1. Add the grpc-service annotation

Put the grpc-http-proxy.alpha.mercari.com/grpc-service annotation on the Service. If your gRPC service's fully qualified name is my.package.MyService, add the annotation 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

If your gRPC server exports multiple services, specify them in a list delimited by a comma (,).

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

2. Name your port with a name which begins with grpc.

grpc-http-proxy will send requests to the port whose name begins with grpc. If there are multiple matching ports, the first one will be selected. This step may be skipped if the port you intend to use is the only port exposed on the 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. [optional] Add the grpc-service-version annotation

If you intend to call multiple versions of your gRPC server through grpc-http-proxy, put the grpc-http-proxy.alpha.mercari.com/grpc-service-version annotation on the Service. The version can be any string you like.

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

Examples

In the following examples, grpc-http-proxy is running at grpc-http-proxy.example.com, and have the access token set to foo. The gRPC service Echo is called, which is defined by the following .proto file:

syntax = "proto3";

package com.example;

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

message EchoMessage {
    string message_body = 1;
}

Single version service

The Kubernetes Service manifest will look like this:

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

The request to call Say through grpc-http-proxy, and its response would be:

$ 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!"}

Passing metadata to the gRPC service

To pass metadata with the key somekey to Echo service, add the metadata to the HTTP request like below:

$ 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!"}

Multiple versions of a service

Let's say that you have a newer version of the Echo server in the same cluster that you would like to call . The Service manifest for the newer server should specify the version with an annotation, and would look like this:

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

In order to choose the new version, the version name specified in the annotation should be added as a query parameter. The request to call Say on the newer server, and its response would be:

$ 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!"}

TODOs

A non-exhaustive list of additional features that could be desired:

  • Ability to find services though a static configuration file.

Contributions are welcomed :)

Committers

Tomoya TABUCHI (@tomoyat1)

Contribution

Please read the CLA below carefully before submitting your contribution.

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

LICENSE

Copyright 2018 Mercari, Inc.

Licensed under the MIT License.

More Repositories

1

ml-system-design-pattern

System design patterns for machine learning
2,221
star
2

engineer-vocabulary-list

Engineer Vocabulary List in Japanese/English
1,770
star
3

gaurun

General push notification server in Go
Go
931
star
4

production-readiness-checklist

Production readiness checklist used for Mercari and Merpay microservices
844
star
5

tfnotify

A CLI command to parse Terraform execution result and notify it to GitHub
Go
619
star
6

Mew

The framework that support making MicroViewController.
Swift
485
star
7

tortoise

Tortoise: Shell-Shockingly-Good Kubernetes Autoscaling
Go
380
star
8

go-circuitbreaker

A context aware circuit breaker library in Go.
Go
358
star
9

mercari-microservices-example

Go
327
star
10

QRScanner

A simple QR Code scanner framework for iOS. Provides a similar scan effect to ios13+.
Swift
313
star
11

grpc-federation

gRPC Federation generates a gRPC server by writing a custom option in Protocol Buffers
Go
238
star
12

go-httpdoc

Golang package for generating API documentation from httptest. See example output
Go
228
star
13

datastore

(AE|Cloud) Datastore Wrapper
Go
214
star
14

mercari-slack-guidelines

Slack guidelines of Mercari.
202
star
15

ShimmerView

ShimmerView is a collection of APIs to construct Skelton View + Shimmering Effect type loading indicator on UIKit and SwiftUI.
Swift
195
star
16

mercari-engineering-ladder

Mercari's Expectations for Engineers in Various Stages of Their Career
163
star
17

mtc2018-app

The Official Conference App for Mercari Tech Conf 2018
Dart
134
star
18

go-grpc-interceptor

gRPC server insterceptor for golang
Go
124
star
19

go-dnscache

Go package for caching DNS lookup results in memory.
Go
121
star
20

certificate-expiry-monitor-controller

Certificate Expiry Monitor Controller monitors the expiration of TLS certificates used in Ingress.
Go
117
star
21

souzoh-recruitment

117
star
22

mtc2018-web

Mercari Tech Conf 2018
TypeScript
100
star
23

BottomHalfModal

A customizable bottom half modal used in merpay
Swift
95
star
24

kubetempura

Go
93
star
25

widebullet

Widebullet is an API gateway with JSON-RPC
Go
91
star
26

dietcube

The world super fly weight & flexible PHP framework.
PHP
79
star
27

docker-appengine-go

Projects has been moved
Dockerfile
74
star
28

spanner-autoscaler

Kubernetes Operator for Cloud Spanner autoscaling
Go
73
star
29

RxReduxK

Micro-framework for Redux implemented in Kotlin
Kotlin
67
star
30

testdeck

Testdeck is a framework for integration, end-to-end (E2E), and security testing of gRPC microservices written in Golang.
Go
65
star
31

DataflowTemplate

Mercari Dataflow Template
Java
64
star
32

go-emv-code

EMV® QR Code Encoder/Decoder for Go.
Go
64
star
33

hcledit

Go package to edit HCL configuration
Go
49
star
34

go-httpstats

Go package for reporting HTTP stats
Go
44
star
35

RemoteDataK

Algebraic data type (ADT) to represent the state of data that is loading from/to remote sources/destinations
Kotlin
44
star
36

fractal

Swift
36
star
37

go-bps

Go package to manage the basis point
Go
36
star
38

mtc2018-app-SwiftUI

Project to rewrite MTC2018 App by SwiftUI
Swift
33
star
39

siberi-android

A/B testing library for Android
Java
33
star
40

BalloonView

Makes balloon-like view with an arrow pointing to another view. Useful for onboarding tutorials
Swift
25
star
41

DataflowTemplates

Convenient Dataflow pipelines for transforming data between cloud data sources
Java
24
star
42

yasashii-wfh-comms

yasashii-WFH-Communication-Best-Practices
19
star
43

mercari-ml-merrec-pub-us

Python
18
star
44

swiftui-chart

Swift
17
star
45

honyakubot

Slack translation bot
Swift
14
star
46

github-app-token-generator

A simple github action written in go to retrieve an installation access token for an app installed into an organization.
Go
14
star
47

github-token-app

Github Token App is a package for generating short lived github tokens (expires in 1 hour) with minimum necessary permissions.
Python
13
star
48

terraform-provider-spinnaker

A Spinnaker provider for Terraform
Go
13
star
49

composer-diff-plugin

composer plugin to show library version diff at "composer update".
PHP
12
star
50

CFQIRBM

Collaborative Filtering Quantum Infinite Restricted Boltzmann Machine
Jupyter Notebook
12
star
51

Remi

Mascot
10
star
52

terraform-provider-openpgp

Terraform OpenPGP provider
Go
8
star
53

imageflux-cli

Go
8
star
54

eslint-config-mercari

JavaScript
7
star
55

universal-apk-plugin

Gradle Plugin allowing to create an Universal APK for debug purpose.
Kotlin
6
star
56

mkdocs-git-snippet

Python
6
star
57

commitver

Derive a semver version from the commit history in any repo.
Shell
6
star
58

kafka-connect-transform-kryptonite-gcp

Java
5
star
59

proto-to-type

A Node.js library that generates type definition for TypeScript from Protocol Buffer
TypeScript
4
star
60

stylelint-config-mercari

The shareable config for @stylelint by @mercari.
CSS
3
star
61

merlin

Merlin is an agent sends out alerts when kubernetes resources are misconfigured or not comply with custom rules.
Go
3
star
62

modserver

modserver is a simple Go module server.
Go
3
star
63

extract-primitives

extract-primitives extracts primitive values from TypeScript's declaration file(.d.ts).
TypeScript
2
star
64

Whitesource-Scan-Action

Shell
2
star
65

terraform-exfiltration-lab

HCL
2
star
66

merpay-netpayment-sdk-php

Merpay Online Payments SDK for PHP
PHP
1
star
67

pubsubloader

Archived. You can find a better way on https://github.com/GoogleCloudPlatform/DataflowTemplates/tree/master/v2/streaming-data-generator. Cloud Dataflow based Cloud Pub/Sub load generator and integration tester with custom data
Scala
1
star