This is the "latest" release of Envoy Gateway, which contains the most recent commits from the main branch.
This release might not be stable.
Please refer to the /docs documentation for the most current information.
gRPC-JSON Transcoding
5 minute read
This task shows how to use HTTPRouteFilter to convert JSON/HTTP requests to gRPC requests, so REST clients can call a gRPC backend.
The JSON/HTTP API is defined by the google.api.http options in your proto files.
The filter can only be used in the rule filters of an HTTPRoute. It is not supported in a GRPCRoute
or in the filters of a backendRef.
Prerequisites
Follow the steps below to install Envoy Gateway and the example manifest. Before proceeding, you should be able to query the example backend using HTTP.
Expand for instructions
Install the Gateway API CRDs and Envoy Gateway using Helm:
Gateway API CRD compatibilityThis command installs Gateway API CRDs. If your Kubernetes provider already manages compatible Gateway API CRDs for the cluster, use the provider-managed Gateway API CRD install steps instead.
helm install eg oci://docker.io/envoyproxy/gateway-helm --version v0.0.0-latest -n envoy-gateway-system --create-namespaceInstall the GatewayClass, Gateway, HTTPRoute and example app:
kubectl apply -f https://github.com/envoyproxy/gateway/releases/download/latest/quickstart.yaml -n defaultVerify Connectivity:
Get the External IP of the Gateway:
export GATEWAY_HOST=$(kubectl get gateway/eg -o jsonpath='{.status.addresses[0].value}')Curl the example app through Envoy proxy:
curl --verbose --header "Host: www.example.com" http://$GATEWAY_HOST/getThe above command should succeed with status code 200.
Get the name of the Envoy service created the by the example Gateway:
export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')Get the deployment of the Envoy service created the by the example Gateway:
export ENVOY_DEPLOYMENT=$(kubectl get deploy -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')Port forward to the Envoy service:
kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8888:80 &Curl the example app through Envoy proxy:
curl --verbose --header "Host: www.example.com" http://localhost:8888/getThe above command should succeed with status code 200.
Generate the Proto Descriptor
The transcoder needs the protobuf descriptor set of your services. Generate it with --include_imports, so the
imported proto files are included:
protoc --include_imports --descriptor_set_out=proto-descriptor.pb path/to/your.proto
Store it in a ConfigMap in the same namespace as the HTTPRoute:
kubectl create configmap greeter-proto-descriptor --from-file=proto-descriptor=proto-descriptor.pb
The descriptor set is read from the proto-descriptor key, either in binaryData or in data, where it can be
base64-encoded. If the ConfigMap has no data and only one binaryData entry, that entry is used.
Backend
The transcoded request is a gRPC request, so Envoy Gateway connects to the backend over HTTP/2, like the backend of a
GRPCRoute. No appProtocol is needed. A backend with a WebSocket app protocol, like appProtocol: kubernetes.io/ws,
can’t be used, because it needs HTTP/1.1.
Note: don’t set useClientProtocol in a BackendTrafficPolicy for the route. The client of the transcoder uses
HTTP/1.1 most of the time, so Envoy would send the gRPC requests over HTTP/1.1 and they would fail.
Configuration
Create an HTTPRouteFilter that references the ConfigMap, and use it in the HTTPRoute rule:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: HTTPRouteFilter
metadata:
name: grpc-transcoder
spec:
grpcJSONTranscoder:
protoDescriptor:
valueRef:
group: ""
kind: ConfigMap
name: greeter-proto-descriptor
services:
- example.Greeter
printOptions:
alwaysPrintPrimitiveFields: true
ignoreUnknownQueryParameters: true
convertGRPCStatus: true
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: grpc-route
spec:
parentRefs:
- name: eg
hostnames:
- grpc.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /v1/hello
filters:
- type: ExtensionRef
extensionRef:
group: gateway.envoyproxy.io
kind: HTTPRouteFilter
name: grpc-transcoder
backendRefs:
- name: grpc-service
port: 9000
Then call the JSON API:
curl -H "Host: grpc.example.com" http://${GATEWAY_HOST}/v1/hello/world
If services is not specified, all the services in the descriptor set are transcoded, except the ones that come from
imported files.
Policies and Routing
The transcoder changes the path of the request to the gRPC method, for example /example.Greeter/SayHello, but the
request is not matched to another route. The backend and the policies of the HTTPRoute are used for the transcoded
request, so attach the policies, like authentication and rate limiting, to the HTTPRoute. The policies of a GRPCRoute
for the same service are not applied.
Note: if EnvoyProxy.spec.filterOrder moves a filter that clears the route cache after the transcoder, like ExtAuth or
JWT with recomputeRoute, the transcoded request may be matched to another route.
The following filters can’t be used in the same rule with the transcoder, because they use the path of the request:
URLRewritewith a path modifierURLRewritewith aPathRegexhostnameRequestRedirectDirectResponse
Such a rule is not accepted and returns 500.
Note: a RequestMirror in the same rule sends the transcoded gRPC request to the mirror backend, over HTTP/2.
Troubleshooting
The descriptor set is validated when the route is translated. If it is invalid, the rule returns 500 and the reason is
in the Accepted condition of the HTTPRoute:
kubectl get httproute grpc-route -o yaml
These problems are reported:
- The descriptor set can’t be parsed, or an imported file is missing.
- An imported file comes after the file that imports it.
- A service in
servicesis not in the descriptor set. - The
bodyorresponse_bodyof agoogle.api.httpoption is not a field of the message, or aresponse_bodyis not agoogle.api.HttpBodyfield. - The path template of a
google.api.httpoption is invalid, for examplev1/hellowithout the leading/. - With
convertGRPCStatus, the descriptor set conflicts with thegoogle/protobuf/any.protoandgoogle/rpc/status.protothat Envoy adds. This happens whengoogle.protobuf.Anyis in another file, for example a vendoredthird_party/google/protobuf/any.proto.
Note: the descriptor set should be generated by protoc. Envoy may still reject a descriptor set made by another tool
that protoc wouldn’t produce, for example with two fields that have the same JSON name. In that case, the whole
listener is rejected.
Clean-Up
Follow the steps from the Quickstart to uninstall Envoy Gateway and the example manifest.
kubectl delete httproutefilter/grpc-transcoder
kubectl delete configmap/greeter-proto-descriptor
Next Steps
Check out the Developer Guide to get involved in the project.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.