grpc-web
grpc-web copied to clipboard
gRPC-Web Basics Tutorial is incomplete
I'm working on a proof-of-concept using gRPC-Web. I was able to get the Quick Start tutorial working. My next challenge is to adapt this demo by writing a gRPC-Web client in JavaScript that talks to my (very simple) gRPC server written in Python. Is this possible? I am following the Basics Tutorial but it is incomplete. In particular, some of the client-side Javascript code is missing, and the code snippet that is there is different from the corresponding code in the Docker containers from the Quick Start tutorial.
I am able to build the JavaScript stubs for my client. However, my gRPC server (Python) never sees any requests from the client (JavaScript). Not sure if this is due to a bug in my JavaScript, a bug in the Envoy proxy config, or something else. Troubleshooting is difficult because the Docker containers are based on a very minimal Linux install that is missing basic Unix tools.
I can offer to help document this once I get it working, but I would need some help from your team to get it working in the first place.
One reason why your Python server might not be receiving the requests could be because of how we set up the basic example.
So here https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway/examples/echo#run-the-envoy-proxy, you will notice that, from the Envoy's docker image's perspective, there's a docker image via the --link
parameter that's named node-server
. In the envoy.yaml
file, we are redirecting traffic to effectively to node-server:9090
here. Docker will resolve the true address of your node-server
docker image, which most likely is running somewhere in localhost
. So you might need to change that too.
Here is my envoy.yaml
:
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: demo_service
max_grpc_timeout: 0s
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
http_filters:
- name: envoy.filters.http.grpc_web
- name: envoy.filters.http.cors
- name: envoy.filters.http.router
clusters:
- name: demo_service
connect_timeout: 0.25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: host.docker.internal
port_value: 50051
In other words, my gRPC server (Python) is not running in a container, it's running directly on the host machine. Hence the address: host.docker.internal
. Let me know if you need any other info. Thanks for your help!
In that case, when you run the Envoy container, did you try adding --network=host
to the docker run
command?
So you are saying that this envoy.yaml
file works fine when the backend is in Node. The Node server does receive messages forwarded from Envoy. But if you swap the Node server with a Python server, but also listening on the same port 50051, then it doesn't work?
What if you set the environment variable GRPC_TRACE=all
and GRPC_VERBOSITY=debug
before you start the Python server?
I'm sorry to say that I'm on a Windows host (not my choice) and the host
networking driver only works on Linux hosts. However, if I'm reading the Docker docs correctly, host.docker.internal
should do the trick. Normally I would try pinging the host from inside the container, but unfortunately ping
is not available in this container. If you think it's worth installing Envoy on a more fully-featured Linux container, I can certainly try that. If there is already a more fully-featured Envoy image pre-built that I can use, please point me to it.
Re: environment variables: I can certainly try that. But I'm already printing a line of text whenever my Python server receives a request. When I connect with my Python client, the line is printed. When I try to connect with my Javascript gRPC-Web client, the line is not printed. Would it help if I shared the Envoy logfile?
If your example works end-to-end with a Node server, then it seems that your Envoy instance (and the forwarding) is done correctly. So it seems that the issue may be with your Python server. Does your Python server work in a separate way?
For Envoy, our testing uses the docker image published by the envoy team like this: https://github.com/grpc/grpc-web/blob/master/net/grpc/gateway/docker/envoy/Dockerfile#L15
The example that works is the one from the Quick Start tutorial, where there is a gRPC server written in Node that runs in a container. What I'm trying to achieve by following the Basics Tutorial is to write a JavaScript client (running in the browser) that talks to my own gRPC server written in Python (running on the host, not in a container). My Envoy Dockerfile looks very similar to yours. Bottom line: the information in the Basics Tutorial was insufficient for me to succeed at this. I would like to show a proof-of-concept using gRPC-Web, and I cannot.
I've installed Envoy in a full-featured ubuntu
container. I am able to access my gRPC server at host.docker.internal:50051
from that container, by using the telnet
command (see attached screenshot). So, in principle Envoy should also be able to access it. Please let me know next steps for troubleshooting this.
The host.docker.internal
address to be used inside a docker container is my understanding too. So you seem to be doing the correct thing here. I am at a loss here - if the node server examples works, then you are demonstrating that the grpc-web flows works end-to-end. If for some reason swapping out just the server it stops working, it seems like an isolated environment issue.
To be clear, I'm swapping out the Node server from the Quick Start tutorial with my own python server which implements different RPCs. So, the client code has also changed. I tried following the Basics Tutorial to make this work, but it seems there is not enough information there. I proposed to troubleshoot the Envoy config first, but it is possible the error is elsewhere (in my Javascript, for example). The only hypothesis I've eliminated so far is that my Python server is unreachable from the container running the Envoy proxy. The telnet
screenshot above shows that my server is reachable from the container, do you agree?
Just shooting in the dark here: if you are also swapping the service, perhaps you also have to match these lines? https://github.com/grpc/grpc-web/blob/master/net/grpc/gateway/examples/echo/envoy.yaml#L24-L26 Is the Envoy cluster name also matching up between L26 and L40? Is your new frontend still creating the client passing hostname
= localhost:8080
?
Yes, I define a new cluster called demo_service
: https://github.com/krzysztofmajewski/gRPC-demo/blob/master/web/envoy.yaml#L26
You can see the rest of the code here.
I started with the code in the Quick start and tried to hack it to match my gRPC service by following the Basics tutorial. I did my best, but the tutorial seems incomplete. For example, the Quick Start code contains echoapp.js
as well as client.js
, but the Basics Tutorial only mentions a client.js
.
@krzysztofmajewski I double checked the envoy.yaml
in your repo. I can confirm it is fine and it works. I actually copied your yaml in my working grpc-web project with go backend, and it works. If it helps, I have been using envoy straight via docker-compose file
version: '3.7'
services:
envoy:
image: envoyproxy/envoy:v1.14.3
ports:
- XX:XX
- XXX:XXX
volumes:
- ./envoy.yaml:/etc/envoy/envoy.yaml
Also I would suggest to test your grpc server with something like https://github.com/fullstorydev/grpcurl to make sure it is working as expected
I am strugling with the same issue. Cant connect Angular frontend to C++ gRPC server.
Thanks for testing @RohitRox but in the meantime we've decided not to go with gRPC. The front-end side of things didn't seem mature, based on the incomplete documentation.