无法使 Python GCP Cloud Run gRPC 服务响应。

huangapple go评论55阅读模式
英文:

Can't get Python GCP Cloud Run gRPC service to respond

问题

我正在开发一个聊天应用程序,目前有三个主要组件。我将描述工作中的本地开发环境的“架构”:

  • 在 vite 中运行的 SolidJS 客户端,使用 nice-grpc-web(一个小型的 TypeScript gRPC-web 库)
  • 在 Docker 容器中运行的 Envoy 代理
  • 一个 Python gRPC 服务器,从 Haystack 的 PromptNode 中流式传输响应,直接在我的计算机上运行,但也经过测试并可以在 Docker 容器中运行

这一切在本地都正常工作 👍

为了将其迁移到云端,我将 Python 应用程序部署为 GCP 上的 Cloud Run 服务的 Docker 容器。

现在,这个服务正在愉快地运行,并且记录着它的愉快并且正在响应健康检查。所以我认为一切都很好。

然而,重新配置我的 Envoy 代理以指向这个服务,而不是我的本地 Python gRPC 服务器,会导致整个系统崩溃。我收到了来自 Envoy 的消息,告诉我无法访问端点:
> ClientError: /ChatBot/AskQuestion UNAVAILABLE: upstream connect error or disconnect/reset before headers. reset reason: connection failure

所以要么是 Envoy 配置使其不愉快,要么是 Cloud Run 服务使其不愉快。我已经阅读了大量关于这两者的资料,但无法解决问题。

可能导致问题的因素包括:

  • 协议不同。现在它在 https 上运行,我是否需要添加更多的配置来支持 Envoy?
  • 我不得不在 Cloud Run 上覆盖端口(标准端口是 8080,我使用的是 50051)。虽然它在这个端口上对来自 GCP 的健康检查响应,但是否需要进行进一步的配置?
  • 可能是跨域资源共享(CORS)的问题?但我希望响应会反映出来
  • 尽管我已经检查确保它对互联网可用,而不仅仅是内部可用,但这是否可能引起问题?

我遇到的唯一一篇稍微有帮助的文章是这篇文章,但也没有起作用。

以下是我的 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.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: chat_service
                          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: chat_service
      type: logical_dns
      dns_lookup_family: V4_ONLY
      connect_timeout: 20s
      http2_protocol_options: {}
      lb_policy: round_robin
      typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          explicit_http_config:
            http2_protocol_options: { }
      load_assignment:
        cluster_name: cluster_0
        endpoints:
          - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: myapp.a.run.app
                    port_value: 50051

Dockerfile

FROM envoyproxy/envoy:v1.26.1

COPY envoy.yaml /etc/envoy/envoy.yaml

EXPOSE 9901
EXPOSE 50051
EXPOSE 50052
EXPOSE 8080

ENTRYPOINT [ "/usr/local/bin/envoy" ]
CMD [ "-c /etc/envoy/envoy.yaml", "-l trace", "--log-path /tmp/envoy_info.log" ]

请提供建议!

英文:

I am developing a chat app that has three main components (so far). I shall described the "architecture" of the working local development environment:

  • a client in SolidJS running in vite, using nice-grpc-web (a little TypeScript gRPC-web library)
  • an Envoy proxy running in a Docker container
  • a Python gRPC server that streams responses from Haystack's PromptNode, running directly on my machine but also tested and happy to run in a Docker container

This is all working fine locally 👍

With a view to moving it into the cloud, I deployed the Python app in a Docker container as a Cloud Run service on GCP.

Now, this service is running happily and is looging that it is happy and is responding to health checks. So I think that is all good.

However, reconfiguring my Envoy proxy to point to this service, rather than my local Python gRPC server, causes the whole thing to break. I get messages from Envoy telling me that the endpoints can't be reached:
> ClientError: /ChatBot/AskQuestion UNAVAILABLE: upstream connect error or disconnect/reset before headers. reset reason: connection failure

So it is either the Envoy config that is making it unhappy, or the Cloud Run service that is making it unhappy. I have done lots of reading around both, but can't work it out.

Things that I imagine might be causing it:

  • the protocol is different. Now it is running over https, might I need to add more config to Envoy to support this?
  • I had to override the port on Cloud Run (standard is 8080, I am using 50051). Although it is responding on this port to the health checks from GCP, is there some further config I need to do?
  • perhaps a CORS issue? But I would expect the response to reflect that
  • although I have checked to make sure it is available to the internet and not just internally, could this be causing an issue?

The only even vaguely helpful article I have come across is this one, but that doesn't work either.

Here is my envoy.yaml, actual service name elided:

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.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: chat_service
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: chat_service
type: logical_dns
dns_lookup_family: V4_ONLY
connect_timeout: 20s
http2_protocol_options: {}
lb_policy: round_robin
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options: { }
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: myapp.a.run.app
port_value: 50051

Dockerfile

FROM envoyproxy/envoy:v1.26.1
COPY envoy.yaml /etc/envoy/envoy.yaml
EXPOSE 9901
EXPOSE 50051
EXPOSE 50052
EXPOSE 8080
ENTRYPOINT [ "/usr/local/bin/envoy" ]
CMD [ "-c /etc/envoy/envoy.yaml", "-l trace", "--log-path /tmp/envoy_info.log" ]

Suggestions please!

答案1

得分: 1

您的 envoy 代理需要连接到您的 Cloud Run URL 的 443 端口。在您的应用程序和互联网之间有几层代理,因此您的应用程序运行的端口不会公开暴露。

英文:

Your envoy proxy needs to connect to your Cloud Run URL on port 443. There's a few layers of proxies in between your app and the Internet, so the port your application runs on isn't exposed publicly.

huangapple
  • 本文由 发表于 2023年5月28日 05:27:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76349120.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定