首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在坞-组合中访问GRPC服务

在坞-组合中访问GRPC服务
EN

Stack Overflow用户
提问于 2021-08-26 22:34:09
回答 1查看 934关注 0票数 0

目前,我正在学习eShopOnContainers教程,并决定尝试测试GRPC功能,类似于该项目。

我试图构建的是GRPC客户端和GRPC服务,它们都托管在docker上,并且可以相互通信。现在,我设法使它正常工作,如果您在GRPC客户端中查找一个Startup.cs,这个Uri http://host.docker.internal:5104成功地进行了调用并获得了响应。

但是,最初的eshopOnContainers项目使用了http://basket-api:81路径,这要好得多,而且在我看来更易于维护。它还使用更少的组件和一些配置:

  1. GRPC服务在Startup.cs中使用以下内容: app.UsePathBase("/basket-api") 原工程 并在Program.cs中进行一些配置,以侦听端口:
代码语言:javascript
复制
BuildWebHost
...
.ConfigureKestrel(options =>
        {
            var ports = GetDefinedPorts(configuration);
            options.Listen(IPAddress.Any, ports.httpPort, listenOptions =>
            {
                listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
            });

            options.Listen(IPAddress.Any, ports.grpcPort, listenOptions =>
            {
                listenOptions.Protocols = HttpProtocols.Http2;
            });

        })
...

原工程 httpPort的端口为80,grpcPort为81。

  1. GRPC客户端使用以下Uri进行http://basket-api:81调用
  2. 此外,还部署了一个特使代理,它具有如下规则,但我认为最重要的部分是规则b-shortb-long和集群basket,我认为这将导致最终的URL为basket-api:80 (根据集群配置)。

我真的不明白,如果它最终调用了GRPC服务,它为什么需要端口81,但是如果有更多的知识可以解释的话,那就太好了。

代码语言:javascript
复制
admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8001
static_resources:
  listeners:
  - address:
      socket_address:
        address: 0.0.0.0
        port_value: 80
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: eshop_backend_route
            virtual_hosts:
            - name: eshop_backend
              domains:
              - "*"
              routes:
              - name: "c-short"
                match:
                  prefix: "/c/"
                route:
                  auto_host_rewrite: true
                  prefix_rewrite: "/catalog-api/"
                  cluster: catalog
              - name: "c-long"
                match:
                  prefix: "/catalog-api/"
                route:
                  auto_host_rewrite: true
                  cluster: catalog
              - name: "o-short"
                match:
                  prefix: "/o/"
                route:
                  auto_host_rewrite: true
                  prefix_rewrite: "/ordering-api/"
                  cluster: ordering
              - name: "o-long"
                match:
                  prefix: "/ordering-api/"
                route:
                  auto_host_rewrite: true
                  cluster: ordering
              - name: "h-long"
                match:
                  prefix: "/hub/notificationhub"
                route:
                  auto_host_rewrite: true
                  cluster: signalr-hub
                  timeout: 300s
                  upgrade_configs:
                    upgrade_type: "websocket"
                    enabled: true
              - name: "b-short"
                match:
                  prefix: "/b/"
                route:
                  auto_host_rewrite: true
                  prefix_rewrite: "/basket-api/"
                  cluster: basket
              - name: "b-long"
                match:
                  prefix: "/basket-api/"
                route:
                  auto_host_rewrite: true
                  cluster: basket
              - name: "agg"
                match:
                  prefix: "/"
                route:
                  auto_host_rewrite: true
                  prefix_rewrite: "/"
                  cluster: shoppingagg
          http_filters:
          - name: envoy.router
          access_log:
          - name: envoy.file_access_log
            filter:
              not_health_check_filter: {}
            config:
              json_format:
                time: "%START_TIME%"
                protocol: "%PROTOCOL%"
                duration: "%DURATION%"
                request_method: "%REQ(:METHOD)%"
                request_host: "%REQ(HOST)%"
                path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
                response_flags: "%RESPONSE_FLAGS%"
                route_name: "%ROUTE_NAME%"
                upstream_host: "%UPSTREAM_HOST%"
                upstream_cluster: "%UPSTREAM_CLUSTER%"
                upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%"
              path: "/tmp/access.log"
  clusters:
  - name: shoppingagg
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    hosts:
    - socket_address:
        address: webshoppingagg
        port_value: 80
  - name: catalog
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    hosts:
    - socket_address:
        address: catalog-api
        port_value: 80
  - name: basket
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    hosts:
    - socket_address:
        address: basket-api
        port_value: 80
  - name: ordering
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    hosts:
    - socket_address:
        address: ordering-api
        port_value: 80
  - name: signalr-hub
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    hosts:
    - socket_address:
        address: ordering-signalrhub
        port_value: 80

问题

在我的方法中,我假设如果我完全跳过特使代理组件,并使用http://basket-api:80调用服务,它将设法找到它,但不幸的是没有运气。现在,我不确定我的端口是坏的还是URI是坏的,但是我相信我采用的方法类似于在最初的项目中跳过代理。

我可能也误解了我的Docker配置,但我没有看到任何可疑的元素。

错误堆栈:

代码语言:javascript
复制
RpcException: Status(StatusCode="Unavailable", Detail="Error starting gRPC call. HttpRequestException: Resource temporarily unavailable (basket-api:81) SocketException: Resource temporarily unavailable", DebugException="System.Net.Http.HttpRequestException: Resource temporarily unavailable (basket-api:81)
---> System.Net.Sockets.SocketException (11): Resource temporarily unavailable
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|283_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.DefaultConnectAsync(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
at System.Net.Http.ConnectHelper.ConnectAsync(Func`3 callback, DnsEndPoint endPoint, HttpRequestMessage requestMessage, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.ConnectAsync(Func`3 callback, DnsEndPoint endPoint, HttpRequestMessage requestMessage, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttp2ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at Grpc.Shared.TelemetryHeaderHandler.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Grpc.Net.Client.Internal.GrpcCall`2.RunCall(HttpRequestMessage request, Nullable`1 timeout)")

代码

GRPC客户端

Index.cshtml.cs

代码语言:javascript
复制
 public void OnGet()
        {
            var response = _greeterClient.SayHello(new HelloRequest
            {
                Name = "Bob"
            });
            Debug.WriteLine(response.Message);
        }

Startup.cs

代码语言:javascript
复制
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddGrpcClient<Greeter.GreeterClient>((services, options) =>
            {
                // This one works
                //options.Address = new Uri("http://host.docker.internal:5104");

                // This one doesn't
                options.Address = new Uri("http://basket-api:80");
            });
        }

GRPC服务(带有小调整的默认GRPC模板)

Program.cs

代码语言:javascript
复制
 public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.ConfigureKestrel(options =>
                    {
                        options.Listen(IPAddress.Any, 80, listenOptions =>
                        {
                            listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
                        });
                        options.Listen(IPAddress.Any, 81, listenOptions =>
                        {
                            listenOptions.Protocols = HttpProtocols.Http2;
                        });
                    });
                    webBuilder.UseStartup<Startup>();
                });

Startup.cs

代码语言:javascript
复制
public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddGrpc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UsePathBase("/basket-api");

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGrpcService<GreeterService>();

                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
                });
            });
        }
    }

码头组成

docker-compose.yml

代码语言:javascript
复制
version: '3.4'

services:
  grpcserver:
    image: ${DOCKER_REGISTRY-}grpcserver
    build:
      context: .
      dockerfile: GrpcServer/Dockerfile

  grpcclient:
    image: ${DOCKER_REGISTRY-}grpcclient
    build:
      context: .
      dockerfile: GrpcClient/Dockerfile

docker-compose.override.yml

代码语言:javascript
复制
version: '3.4'

services:
  grpcserver:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=http://0.0.0.0:80
    ports:
      - "5103:80"
      - "5104:81"
    volumes:
      - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
      - ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
  grpcclient:
    environment: 
      - ASPNETCORE_ENVIRONMENT=Development
    ports:
      - "5121:80"
    volumes:
      - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
      - ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-08-27 01:04:12

您应该能够使用您的docker生成的DNS名称从您的停靠-撰写文件。您的GRPC客户端应该能够到达http://grpcserver:5103上的服务器。

使用docker,您可以简单地使用服务的名称和容器中公开的端口在容器之间进行对话。

编辑删除了路径中的扩展,因为UsePathBase()

添加从请求路径中提取指定路径基并将其推迟到请求路径库的中间件。

UsePathBase

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68946046

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档