api: Google gRPC client library configuration. (#398)

In support of https://github.com/envoyproxy/envoy/issues/2200 and some
Google internal needs, we are planning on adding support to Envoy to
allow a configuration (or possibly build) driven decision on whether to
using the existing Envoy in-built Grpc::AsyncClient or
the Google C++ gRPC client library (https://grpc.io/grpc/cpp/index.html).

To move in this direction, the idea is we have the xDS ApiConfigSources,
rate limit service config and other filter configurations point at a
GrpcService object. This can be configured to use an Envoy cluster,
where Grpc::AsyncClient will orchestrate communication, or to contain
the config needed to establish a channel in Google C++ gRPC client
library.

Signed-off-by: Harvey Tuch <htuch@google.com>
pull/403/head
htuch 7 years ago committed by GitHub
parent 7901f02031
commit b796da4964
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 50
      api/BUILD
  2. 56
      api/base.proto
  3. 22
      api/bootstrap.proto
  4. 1
      api/cds.proto
  5. 79
      api/config_source.proto
  6. 2
      api/filter/accesslog/BUILD
  7. 6
      api/filter/accesslog/accesslog.proto
  8. 2
      api/filter/http/BUILD
  9. 4
      api/filter/http/ext_authz.proto
  10. 3
      api/filter/network/BUILD
  11. 4
      api/filter/network/ext_authz.proto
  12. 1
      api/filter/network/http_connection_manager.proto
  13. 19
      api/grpc_cluster.proto
  14. 81
      api/grpc_service.proto
  15. 4
      api/metrics_service.proto
  16. 1
      api/sds.proto
  17. 2
      docs/build.sh
  18. 2
      docs/root/api-v2/api.rst
  19. 42
      docs/root/intro/arch_overview/grpc.rst

@ -48,6 +48,8 @@ api_proto_library(
":address",
":base",
":cds",
":config_source",
":grpc_service",
":lds",
":sds",
":stats",
@ -64,6 +66,8 @@ go_proto_library(
":address_go_proto",
":base_go_proto",
":cds_go_grpc",
":config_source_go_proto",
":grpc_service_go_proto",
":lds_go_grpc",
":sds_go_grpc",
":stats_go_proto",
@ -100,6 +104,7 @@ api_proto_library(
deps = [
":address",
":base",
":config_source",
":discovery",
":health_check",
":protocol",
@ -115,6 +120,7 @@ go_grpc_library(
deps = [
":address_go_proto",
":base_go_proto",
":config_source_go_proto",
":discovery_go_grpc",
":health_check_go_proto",
":protocol_go_proto",
@ -128,6 +134,29 @@ go_grpc_library(
],
)
api_proto_library(
name = "config_source",
srcs = ["config_source.proto"],
deps = [
":base",
":grpc_service",
],
)
go_proto_library(
name = "config_source_go_proto",
importpath = "github.com/envoyproxy/data-plane-api/api/config_source",
proto = ":config_source",
visibility = ["//visibility:public"],
deps = [
":base_go_proto",
":grpc_service_go_proto",
"@com_github_gogo_protobuf//:gogo_proto_go",
"@com_github_golang_protobuf//ptypes/duration:go_default_library",
"@com_lyft_protoc_gen_validate//validate:go_default_library",
],
)
api_proto_library(
name = "discovery",
srcs = ["discovery.proto"],
@ -176,8 +205,21 @@ go_grpc_library(
)
api_proto_library(
name = "grpc_cluster",
srcs = ["grpc_cluster.proto"],
name = "grpc_service",
srcs = ["grpc_service.proto"],
deps = [":base"],
)
go_proto_library(
name = "grpc_service_go_proto",
importpath = "github.com/envoyproxy/data-plane-api/api/grpc_service",
proto = ":grpc_service",
visibility = ["//visibility:public"],
deps = [
":base_go_proto",
"@com_github_golang_protobuf//ptypes/duration:go_default_library",
"@com_lyft_protoc_gen_validate//validate:go_default_library",
],
)
api_proto_library(
@ -239,7 +281,7 @@ api_proto_library(
require_py = 0,
deps = [
":base",
":grpc_cluster",
":grpc_service",
"@promotheus_metrics_model//:client_model",
],
)
@ -310,6 +352,7 @@ api_proto_library(
has_services = 1,
deps = [
":base",
":config_source",
":discovery",
],
)
@ -321,6 +364,7 @@ go_grpc_library(
visibility = ["//visibility:public"],
deps = [
":base_go_proto",
":config_source_go_proto",
":discovery_go_grpc",
"@com_github_golang_protobuf//ptypes/wrappers:go_default_library",
"@com_lyft_protoc_gen_validate//validate:go_default_library",

@ -173,62 +173,6 @@ message DataSource {
}
}
// API configuration source. This identifies the API type and cluster that Envoy
// will use to fetch an xDS API.
message ApiConfigSource {
// APIs may be fetched via either REST or gRPC.
enum ApiType {
// REST-JSON legacy corresponds to the v1 API.
REST_LEGACY = 0;
// REST-JSON v2 API. The `canonical JSON encoding
// <https://developers.google.com/protocol-buffers/docs/proto3#json>`_ for
// the v2 protos is used.
REST = 1;
// gRPC v2 API.
GRPC = 2;
}
ApiType api_type = 1 [(validate.rules).enum.defined_only = true];
// Multiple cluster names may be provided. If > 1 cluster is defined, clusters
// will be cycled through if any kind of failure occurs.
//
// .. note::
//
// The cluster with name ``cluster_name`` must be statically defined and its
// type must not be ``EDS``.
repeated string cluster_name = 2 [(validate.rules).repeated .min_items = 1];
// For REST APIs, the delay between successive polls.
google.protobuf.Duration refresh_delay = 3 [(gogoproto.stdduration) = true];
}
// Aggregated Discovery Service (ADS) options. This is currently empty, but when
// set in :ref:`ConfigSource <envoy_api_msg_ConfigSource>` can be used to
// specify that ADS is to be used.
message AggregatedConfigSource {
}
// Configuration for :ref:`listeners <config_listeners>`, :ref:`clusters
// <config_cluster_manager_cluster>`, :ref:`routes
// <config_http_conn_man_route_table>`, :ref:`endpoints
// <arch_overview_service_discovery>` etc. may either be sourced from the
// filesystem or from an xDS API source. Filesystem configs are watched with
// inotify for updates.
message ConfigSource {
oneof config_source_specifier {
option (validate.required) = true;
// Path on the filesystem to source and watch for configuration updates.
//
// .. note::
//
// The path to the source must exist at config load time.
string path = 1;
// API configuration source.
ApiConfigSource api_config_source = 2;
// When set, ADS will be used to fetch resources. The ADS API configuration
// source in the bootstrap configuration is used.
AggregatedConfigSource ads = 3;
}
}
// Configuration for transport socket in :ref:`listeners <config_listeners>` and
// :ref:`clusters <config_cluster_manager_cluster>`. If the configuration is
// empty, a default transport socket implementation and configuration will be

@ -9,7 +9,9 @@ package envoy.api.v2;
import "api/address.proto";
import "api/base.proto";
import "api/config_source.proto";
import "api/cds.proto";
import "api/grpc_service.proto";
import "api/lds.proto";
import "api/sds.proto";
import "api/stats.proto";
@ -208,8 +210,20 @@ message Runtime {
// Rate limit :ref:`configuration overview <config_rate_limit_service>`.
message RateLimitServiceConfig {
// Specifies the cluster manager cluster name that hosts the rate limit
// service. The client will connect to this cluster when it needs to make rate
// limit service requests.
string cluster_name = 1 [(validate.rules).string.min_bytes = 1];
oneof service_specifier {
option (validate.required) = true;
// Specifies the cluster manager cluster name that hosts the rate limit
// service. The client will connect to this cluster when it needs to make
// rate limit service requests. This field is deprecated and `grpc_service`
// should be used instead. The :ref:`Envoy gRPC client
// <envoy_api_field_GrpcService.envoy_grpc>` will be used when this field is
// specified.
string cluster_name = 1 [(validate.rules).string.min_bytes = 1, deprecated = true];
// Specifies the gRPC service that hosts the rate limit service. The client
// will connect to this cluster when it needs to make rate limit service
// requests.
GrpcService grpc_service = 2;
}
}

@ -4,6 +4,7 @@ package envoy.api.v2;
import "api/address.proto";
import "api/base.proto";
import "api/config_source.proto";
import "api/discovery.proto";
import "api/health_check.proto";
import "api/protocol.proto";

@ -0,0 +1,79 @@
syntax = "proto3";
package envoy.api.v2;
import "api/grpc_service.proto";
import "google/protobuf/duration.proto";
import "validate/validate.proto";
import "gogoproto/gogo.proto";
// [#protodoc-title: Configuration sources]
// API configuration source. This identifies the API type and cluster that Envoy
// will use to fetch an xDS API.
message ApiConfigSource {
// APIs may be fetched via either REST or gRPC.
enum ApiType {
// REST-JSON legacy corresponds to the v1 API.
REST_LEGACY = 0;
// REST-JSON v2 API. The `canonical JSON encoding
// <https://developers.google.com/protocol-buffers/docs/proto3#json>`_ for
// the v2 protos is used.
REST = 1;
// gRPC v2 API.
GRPC = 2;
}
ApiType api_type = 1 [(validate.rules).enum.defined_only = true];
// Multiple cluster names may be provided for REST_LEGACY/REST. If > 1
// cluster is defined, clusters will be cycled through if any kind of failure
// occurs.
//
// .. note::
//
// The cluster with name ``cluster_name`` must be statically defined and its
// type must not be ``EDS``.
repeated string cluster_names = 2;
// Multiple gRPC services be provided for GRPC. If > 1 cluster is defined,
// services will be cycled through if any kind of failure occurs.
//
// .. note::
//
// If a gRPC service points to a ``cluster_name``, it must be statically
// defined and its type must not be ``EDS``.
repeated GrpcService grpc_services = 4;
// For REST APIs, the delay between successive polls.
google.protobuf.Duration refresh_delay = 3 [(gogoproto.stdduration) = true];
}
// Aggregated Discovery Service (ADS) options. This is currently empty, but when
// set in :ref:`ConfigSource <envoy_api_msg_ConfigSource>` can be used to
// specify that ADS is to be used.
message AggregatedConfigSource {
}
// Configuration for :ref:`listeners <config_listeners>`, :ref:`clusters
// <config_cluster_manager_cluster>`, :ref:`routes
// <config_http_conn_man_route_table>`, :ref:`endpoints
// <arch_overview_service_discovery>` etc. may either be sourced from the
// filesystem or from an xDS API source. Filesystem configs are watched with
// inotify for updates.
message ConfigSource {
oneof config_source_specifier {
option (validate.required) = true;
// Path on the filesystem to source and watch for configuration updates.
//
// .. note::
//
// The path to the source must exist at config load time.
string path = 1;
// API configuration source.
ApiConfigSource api_config_source = 2;
// When set, ADS will be used to fetch resources. The ADS API configuration
// source in the bootstrap configuration is used.
AggregatedConfigSource ads = 3;
}
}

@ -7,6 +7,6 @@ api_proto_library(
deps = [
"//api:address",
"//api:base",
"//api:grpc_cluster",
"//api:grpc_service",
],
)

@ -5,7 +5,7 @@ option go_package = "accesslog";
import "api/address.proto";
import "api/base.proto";
import "api/grpc_cluster.proto";
import "api/grpc_service.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
@ -432,8 +432,8 @@ message CommonGrpcAccessLogConfig {
// same Envoy.
string log_name = 1 [(validate.rules).string.min_bytes = 1];
// The upstream gRPC cluster that hosts the access log service.
GrpcCluster cluster = 2 [(validate.rules).message.required = true];
// The gRPC service for the access log service.
GrpcService grpc_service = 2 [(validate.rules).message.required = true];
}
// [#proto-status: experimental]

@ -61,5 +61,5 @@ api_proto_library(
api_proto_library(
name = "ext_authz",
srcs = ["ext_authz.proto"],
deps = ["//api:grpc_cluster"],
deps = ["//api:grpc_service"],
)

@ -2,7 +2,7 @@ syntax = "proto3";
package envoy.api.v2.filter.http;
import "api/grpc_cluster.proto";
import "api/grpc_service.proto";
import "validate/validate.proto";
@ -13,7 +13,7 @@ import "validate/validate.proto";
message ExtAuthz {
// The external authorization gRPC service configuration.
GrpcCluster grpc_cluster = 1;
GrpcService grpc_service = 1;
// The filter's behaviour in case the external authorization service does
// not respond back. If set to true then in case of failure to get a

@ -7,6 +7,7 @@ api_proto_library(
srcs = ["http_connection_manager.proto"],
deps = [
"//api:base",
"//api:config_source",
"//api:protocol",
"//api:rds",
"//api/filter/accesslog",
@ -48,5 +49,5 @@ api_proto_library(
api_proto_library(
name = "ext_authz",
srcs = ["ext_authz.proto"],
deps = ["//api:grpc_cluster"],
deps = ["//api:grpc_service"],
)

@ -2,7 +2,7 @@ syntax = "proto3";
package envoy.api.v2.filter.network;
import "api/grpc_cluster.proto";
import "api/grpc_service.proto";
import "validate/validate.proto";
@ -15,7 +15,7 @@ message ExtAuthz {
string stat_prefix = 1 [(validate.rules).string.min_bytes = 1];
// The external authorization gRPC service configuration.
GrpcCluster grpc_cluster = 2;
GrpcService grpc_service = 2;
// The filter's behaviour in case the external authorization service does
// not respond back. If set to true then in case of failure to get a

@ -4,6 +4,7 @@ package envoy.api.v2.filter.network;
option go_package = "network";
import "api/base.proto";
import "api/config_source.proto";
import "api/protocol.proto";
import "api/rds.proto";
import "api/filter/accesslog/accesslog.proto";

@ -1,19 +0,0 @@
syntax = "proto3";
package envoy.api.v2;
import "google/protobuf/duration.proto";
import "validate/validate.proto";
// [#not-implemented-hide:]
// GrpcCluster is used to expose generic gRPC cluster configuration that may
// be used by filters to interface with a gRPC service.
message GrpcCluster {
// The name of the upstream gRPC cluster.
string cluster_name = 1 [(validate.rules).string.min_bytes = 1];
// The timeout for the gRPC request. This is the timeout for a specific
// request.
google.protobuf.Duration timeout = 2;
}

@ -0,0 +1,81 @@
syntax = "proto3";
package envoy.api.v2;
import "api/base.proto";
import "google/protobuf/duration.proto";
import "validate/validate.proto";
// [#protodoc-title: gRPC services]
// [#proto-status: draft]
// gRPC service configuration. This is used by :ref:`ApiConfigSource
// <envoy_api_msg_ApiConfigSource>` and filter configurations.
message GrpcService {
message EnvoyGrpc {
// The name of the upstream gRPC cluster. SSL credentials will be supplied
// in the :ref:`Cluster <envoy_api_msg_Cluster>` :ref:`tls_context
// <envoy_api_field_Cluster.tls_context>`.
string cluster_name = 1 [(validate.rules).string.min_bytes = 1];
}
message GoogleGrpc {
// The target URI when using the `Google C++ gRPC client
// <https://github.com/grpc/grpc>`_. SSL credentials will be supplied in
// :ref:`credentials <envoy_api_field_GrpcService.credentials>`.
string target_uri = 1 [(validate.rules).string.min_bytes = 1];
// See https://grpc.io/grpc/cpp/structgrpc_1_1_ssl_credentials_options.html.
message SslCredentials {
// PEM encoded server root certificates.
DataSource root_certs = 1;
// PEM encoded client private key.
DataSource private_key = 2;
// PEM encoded client certificate chain.
DataSource cert_chain = 3;
}
SslCredentials ssl_credentials = 2;
}
oneof target_specifier {
option (validate.required) = true;
// Envoy's in-built gRPC client.
// See the :ref:`gRPC services overview <arch_overview_grpc_services>`
// documentation for discussion on gRPC client selection.
EnvoyGrpc envoy_grpc = 1;
// `Google C++ gRPC client <https://github.com/grpc/grpc>`_
// See the :ref:`gRPC services overview <arch_overview_grpc_services>`
// documentation for discussion on gRPC client selection.
GoogleGrpc google_grpc = 2;
}
// The timeout for the gRPC request. This is the timeout for a specific
// request.
google.protobuf.Duration timeout = 3;
// gRPC credentials as described at
// https://grpc.io/docs/guides/auth.html#credential-types.
//
// .. note::
//
// Credentials are only currently implemented for the Google gRPC client.
message Credentials {
oneof credential_specifier {
option (validate.required) = true;
// OAuth2 access token, see
// https://grpc.io/grpc/cpp/namespacegrpc.html#ad3a80da696ffdaea943f0f858d7a360d.
string access_token = 1;
// [#comment: TODO(htuch): other gRPC auth types, e.g. IAM credentials, JWT, etc.]
}
}
// A set of credentials that will be composed to form the `channel credentials
// <https://grpc.io/docs/guides/auth.html#credential-types>`_.
repeated Credentials credentials = 4;
}

@ -5,7 +5,7 @@ syntax = "proto3";
package envoy.api.v2;
import "api/base.proto";
import "api/grpc_cluster.proto";
import "api/grpc_service.proto";
import "metrics.proto";
@ -41,5 +41,5 @@ message StreamMetricsMessage {
// opaque configuration that will be used to create Metrics Service.
message MetricsServiceConfig {
// The upstream gRPC cluster that hosts the metrics service.
GrpcCluster cluster = 1 [(validate.rules).message.required = true];
GrpcService grpc_service = 1 [(validate.rules).message.required = true];
}

@ -3,6 +3,7 @@ syntax = "proto3";
package envoy.api.v2;
import "api/base.proto";
import "api/config_source.proto";
import "api/discovery.proto";
import "google/api/annotations.proto";

@ -30,8 +30,10 @@ PROTO_RST="
/api/base/api/base.proto.rst
/api/bootstrap/api/bootstrap.proto.rst
/api/cds/api/cds.proto.rst
/api/config_source/api/config_source.proto.rst
/api/discovery/api/discovery.proto.rst
/api/eds/api/eds.proto.rst
/api/grpc_service/api/grpc_service.proto.rst
/api/health_check/api/health_check.proto.rst
/api/lds/api/lds.proto.rst
/api/rds/api/rds.proto.rst

@ -8,6 +8,8 @@ v2 API reference
:maxdepth: 2
bootstrap.proto
config_source.proto
grpc_service.proto
lds.proto
cds.proto
eds.proto

@ -24,3 +24,45 @@ application layer:
* gRPC-JSON transcoder is supported by a :ref:`filter <config_http_filters_grpc_json_transcoder>`
that allows a RESTful JSON API client to send requests to Envoy over HTTP and get proxied to a
gRPC service.
.. _arch_overview_grpc_services:
gRPC services
-------------
In addition to proxying gRPC on the data plane, Envoy make use of gRPC for its
control plane, where it :ref:`fetches configuration from management server(s)
<config_overview_v2>` and also in filters, for example for :ref:`rate limiting
<config_http_filters_rate_limit>` or authorization checks. We refer to these as
*gRPC services*.
When specifying gRPC services, it's necessary to specify the use of either the
:ref:`Envoy gRPC client <envoy_api_field_GrpcService.envoy_grpc>` or the
:ref:`Google C++ gRPC client <envoy_api_field_GrpcSErvice.google_grpc>`. We
discuss the tradeoffs in this choice below.
The Envoy gRPC client is a minimal custom implementation of gRPC that makes use
of Envoy's HTTP/2 upstream connection management. Services are specified as
regular Envoy :ref:`clusters <arch_overview_cluster_manager>`, with regular
treatment of :ref:`timeouts, retries <arch_overview_http_conn_man>`, endpoint
:ref:`discovery <arch_overview_dynamic_config_sds>`/:ref:`load
balancing/failover <arch_overview_load_balancing>`/load reporting, :ref:`circuit
breaking <arch_overview_circuit_break>`, :ref:`health checks
<arch_overview_health_checking>`, :ref:`outlier detection
<arch_overview_outlier_detection>`. They share the same :ref:`connection pooling
<arch_overview_conn_pool>` mechanism as the Envoy data plane. Similarly, cluster
:ref:`statistics <arch_overview_statistics>` are available for gRPC services.
Since the client is minimal, it does not include advanced gRPC features such as
`OAuth2 <https://oauth.net/2/>`_ or `gRPC-LB
<https://grpc.io/blog/loadbalancing>`_ lookaside.
The Google C++ gRPC client is based on the reference implementation of gRPC
provided by Google at https://github.com/grpc/grpc. It provides advanced gRPC
features that are missing in the Envoy gRPC client. The Google C++ gRPC client
performs its own load balancing, retries, timeouts, endpoint management, etc,
independent of Envoy's cluster management.
It is recommended to use the Envoy gRPC client in most cases, where the advanced
features in the Google C++ gRPC client are not required. This provides
configuration and monitoring simplicity. Where necessary features are missing
in the Envoy gRPC client, the Google G++ gRPC client should be used instead.

Loading…
Cancel
Save