React + gRPC 未到达特使容器
React + gRPC don't reach envoy container
我试图在 React 中构建一个非常基本的网页,它将 gRPC 请求发送到用 Rust 编写的后端。
我遵循了这些指南:
https://daily.dev/blog/build-a-chat-app-using-grpc-and-reactjs
https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway/examples/helloworld
但是,我无法获得到达 docker 容器中的 envoy 代理的 gRPC 请求(到目前为止,envoy 是容器中唯一的组件 运行)。
这是我的原型文件:
syntax = "proto3";
package Base;
service Hello {
rpc HelloWorld(HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {}
message HelloResponse {
string message = 1;
}
这是我的 App.js 文件(基本上它是由 React 引导程序创建的,我只是添加了功能和按钮)
import logo from './logo.svg';
import './App.css';
import { HelloClient } from './base_grpc_web_pb';
import { HelloRequest } from './base_pb';
const client = new HelloClient("http://" + window.location.hostname + ":8080", null, null);
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
<button
onClick={sendRequest}
style={{
padding: "7px 38px",
fontSize: "1.2em",
boxSizing: "content-box",
borderRadius: "4px",
}}
>
Join
</button>
</div>
);
}
function sendRequest() {
const request = new HelloRequest();
console.log("CLICK");
client.helloWorld(request, {}, (err, response) => {
if (err) return console.log("BBBBB error", err);
console.log("AAAAA RESPONSE", response.getMessage());
});
}
export default App;
这是我的 envoy 配置(我在 Ubuntu 22.04,所以不需要用 host.docker.internal
覆盖地址):
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: proxy
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.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: hellors
timeout: 0s
max_stream_duration:
grpc_timeout_header_max: 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
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
- name: envoy.filters.http.cors
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: hellors
connect_timeout: 0.25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
# win/mac hosts: Use address: host.docker.internal instead of address: localhost in the line below
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 0.0.0.0
port_value: 9090
特使的 Dockerfile:
FROM envoyproxy/envoy-dev:latest
COPY envoy.yaml /etc/envoy/envoy.yaml
RUN chmod go+r /etc/envoy/envoy.yaml
在控制台中,单击按钮后出现以下错误消息:
http://localhost:8080/Base.Hello/HelloWorld [HTTP/1.1 503 Service Unavailable 5ms]
其次是
message: "Http response at 400 or 500 level", [...]
如果我尝试 curl 端口,它似乎没有在监听:
>$ curl -v http://localhost:8080
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 503 Service Unavailable
< content-length: 145
< content-type: text/plain
< date: Thu, 28 Apr 2022 16:03:55 GMT
< server: envoy
<
* Connection #0 to host localhost left intact
upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: delayed connect error: 111
到这里我就卡住了,所有的配置文件似乎都没问题,但我仍然无法访问 envoy 代理。有什么建议吗?
我偶然发现 建议使用 nginx,但是我不明白为什么需要它,特别是因为我正在查看的 gRPC 示例没有使用它。
在您的情况下,Http response at 400 or 500 level
可能是由于您的 gRPC 服务无法从 Envoy 访问。
您说 Envoy 运行 装在 Docker 容器中。如果是这样,您的 Envoy 配置中的集群 hellors
:
clusters:
- name: hellors
load_assignment:
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 0.0.0.0
port_value: 9090
无法访问,因为您指定了地址 0.0.0.0
。 Docker 容器使用它们自己的网络,因此在该网络内,0.0.0.0:9090
未定义,因为您的 gRPC 服务 运行 在您的主机上运行。
您可能想在您的主机网络 (--net=host) 中尝试 运行ning Envoy。
或者如果您的 gRPC 服务可以容器化,您可以 运行 Envoy 和 在同一个 Docker 网络中的 gRPC 服务。
我试图在 React 中构建一个非常基本的网页,它将 gRPC 请求发送到用 Rust 编写的后端。
我遵循了这些指南:
https://daily.dev/blog/build-a-chat-app-using-grpc-and-reactjs
https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway/examples/helloworld
但是,我无法获得到达 docker 容器中的 envoy 代理的 gRPC 请求(到目前为止,envoy 是容器中唯一的组件 运行)。
这是我的原型文件:
syntax = "proto3";
package Base;
service Hello {
rpc HelloWorld(HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {}
message HelloResponse {
string message = 1;
}
这是我的 App.js 文件(基本上它是由 React 引导程序创建的,我只是添加了功能和按钮)
import logo from './logo.svg';
import './App.css';
import { HelloClient } from './base_grpc_web_pb';
import { HelloRequest } from './base_pb';
const client = new HelloClient("http://" + window.location.hostname + ":8080", null, null);
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
<button
onClick={sendRequest}
style={{
padding: "7px 38px",
fontSize: "1.2em",
boxSizing: "content-box",
borderRadius: "4px",
}}
>
Join
</button>
</div>
);
}
function sendRequest() {
const request = new HelloRequest();
console.log("CLICK");
client.helloWorld(request, {}, (err, response) => {
if (err) return console.log("BBBBB error", err);
console.log("AAAAA RESPONSE", response.getMessage());
});
}
export default App;
这是我的 envoy 配置(我在 Ubuntu 22.04,所以不需要用 host.docker.internal
覆盖地址):
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: proxy
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.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: hellors
timeout: 0s
max_stream_duration:
grpc_timeout_header_max: 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
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
- name: envoy.filters.http.cors
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: hellors
connect_timeout: 0.25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
# win/mac hosts: Use address: host.docker.internal instead of address: localhost in the line below
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 0.0.0.0
port_value: 9090
特使的 Dockerfile:
FROM envoyproxy/envoy-dev:latest
COPY envoy.yaml /etc/envoy/envoy.yaml
RUN chmod go+r /etc/envoy/envoy.yaml
在控制台中,单击按钮后出现以下错误消息:
http://localhost:8080/Base.Hello/HelloWorld [HTTP/1.1 503 Service Unavailable 5ms]
其次是
message: "Http response at 400 or 500 level", [...]
如果我尝试 curl 端口,它似乎没有在监听:
>$ curl -v http://localhost:8080
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 503 Service Unavailable
< content-length: 145
< content-type: text/plain
< date: Thu, 28 Apr 2022 16:03:55 GMT
< server: envoy
<
* Connection #0 to host localhost left intact
upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: delayed connect error: 111
到这里我就卡住了,所有的配置文件似乎都没问题,但我仍然无法访问 envoy 代理。有什么建议吗?
我偶然发现
在您的情况下,Http response at 400 or 500 level
可能是由于您的 gRPC 服务无法从 Envoy 访问。
您说 Envoy 运行 装在 Docker 容器中。如果是这样,您的 Envoy 配置中的集群 hellors
:
clusters:
- name: hellors
load_assignment:
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 0.0.0.0
port_value: 9090
无法访问,因为您指定了地址 0.0.0.0
。 Docker 容器使用它们自己的网络,因此在该网络内,0.0.0.0:9090
未定义,因为您的 gRPC 服务 运行 在您的主机上运行。
您可能想在您的主机网络 (--net=host) 中尝试 运行ning Envoy。
或者如果您的 gRPC 服务可以容器化,您可以 运行 Envoy 和 在同一个 Docker 网络中的 gRPC 服务。