-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Michal Witkowski
committed
Feb 28, 2017
1 parent
f457856
commit d654141
Showing
2 changed files
with
46 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,59 @@ | ||
# gRPC Proxy | ||
|
||
This is an implementation of a [gRPC](http://www.grpc.io/) Proxying Server in Golang, based on [grpc-go](https://github.com/grpc/grpc-go). Features: | ||
|
||
* full support for all Streams: Unitary RPCs and Streams: One-Many, Many-One, Many-Many | ||
* pass-through mode: no overhead of encoding/decoding messages | ||
* customizable `StreamDirector` routing based on `context.Context` of the `Stream`, allowing users to return | ||
a `grpc.ClientConn` after dialing the backend of choice based on: | ||
- inspection of service and method name | ||
- inspection of user credentials in `authorization` header | ||
- inspection of custom user-features | ||
- inspection of TLS client cert credentials | ||
* integration tests | ||
|
||
## Example Use | ||
|
||
```go | ||
[](https://travis-ci.org/mwitkow/go-proxy) | ||
[](https://goreportcard.com/report/github.com/mwitkow/go-proxy) | ||
[](https://godoc.org/github.com/mwitkow/go-proxy) | ||
[](LICENSE) | ||
|
||
director := func(ctx context.Context) (*grpc.ClientConn, error) { | ||
if err := CheckBearerToken(ctx); err != nil { | ||
return nil, grpc.Errorf(codes.PermissionDenied, "unauthorized access: %v", err) | ||
} | ||
stream, _ := transport.StreamFromContext(ctx) | ||
backend, found := PreDialledBackends[stream.Method()]; | ||
if !found { | ||
return nil, grpc.Errorf(codes.Unimplemented, "the service %v is not implemented", stream.Method) | ||
} | ||
return backend, nil | ||
} | ||
[gRPC Go](https://github.com/grpc/grpc-go) Proxy server | ||
|
||
proxy := grpcproxy.NewProxy(director) | ||
proxy.Server(boundListener) | ||
``` | ||
## Project Goal | ||
|
||
## Status | ||
Build a transparent reverse proxy for gRPC targets that will make it easy to expose gRPC services | ||
over the internet. This includes: | ||
* no needed knowledge of the semantics of requests exchanged in the call (independent rollouts) | ||
* easy, declarative definition of backends and their mappings to frontends | ||
* simple round-robin load balancing of inbound requests from a single connection to multiple backends | ||
|
||
This is *alpha* software, written as a proof of concept. It has been integration-tested, but please expect bugs. | ||
The project now exists as a **proof of concept**, with the key piece being the `proxy` package that | ||
is a generic gRPC reverse proxy handler. | ||
|
||
The current implementation depends on a public interface to `ClientConn.Picker()`, which hopefully will be upstreamed in [grpc-go#397](https://github.com/grpc/grpc-go/pull/397). | ||
|
||
## Proxy Handler | ||
|
||
## Contributors | ||
The package [`proxy`](proxy/) contains a generic gRPC reverse proxy handler that allows a gRPC server to | ||
not know about registered handlers or their data types. Please consult the docs, here's an exaple usage. | ||
|
||
Names in no particular order: | ||
Defining a `StreamDirector` that decides where (if at all) to send the request | ||
```go | ||
director = func(ctx context.Context, fullMethodName string) (*grpc.ClientConn, error) { | ||
// Make sure we never forward internal services. | ||
if strings.HasPrefix(fullMethodName, "/com.example.internal.") { | ||
return nil, grpc.Errorf(codes.Unimplemented, "Unknown method") | ||
} | ||
md, ok := metadata.FromContext(ctx) | ||
if ok { | ||
// Decide on which backend to dial | ||
if val, exists := md[":authority"]; exists && val[0] == "staging.api.example.com" { | ||
// Make sure we use DialContext so the dialing can be cancelled/time out together with the context. | ||
return grpc.DialContext(ctx, "api-service.staging.svc.local", grpc.WithCodec(proxy.Codec())) | ||
} else if val, exists := md[":authority"]; exists && val[0] == "api.example.com" { | ||
return grpc.DialContext(ctx, "api-service.prod.svc.local", grpc.WithCodec(proxy.Codec())) | ||
} | ||
} | ||
return nil, grpc.Errorf(codes.Unimplemented, "Unknown method") | ||
} | ||
``` | ||
Then you need to register it with a `grpc.Server`. The server may have other handlers that will be served | ||
locally: | ||
|
||
* [mwitkow](https://github.com/mwitkow) | ||
```go | ||
server := grpc.NewServer( | ||
grpc.CustomCodec(proxy.Codec()), | ||
grpc.UnknownServiceHandler(proxy.TransparentHandler(director))) | ||
pb_test.RegisterTestServiceServer(server, &testImpl{}) | ||
``` | ||
|
||
## License | ||
|
||
`grpc-proxy` is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/mwitkow-io/blob/grpcproxy/LICENSE.txt). | ||
|
||
`grpc-proxy` is released under the Apache 2.0 license. See [LICENSE.txt](LICENSE.txt). | ||
|
||
Part of the main server loop are lifted from the [grpc-go](https://github.com/grpc/grpc-go) `Server`, which is copyrighted Google Inc. and licensed under MIT license. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters