【问题标题】:Unable to connect to net core gRPC service hosted in Docker无法连接到 Docker 中托管的网络核心 gRPC 服务
【发布时间】:2020-10-19 09:44:49
【问题描述】:

我对 gRPC 服务比较陌生。

我正在尝试将 Net core gRPC 服务部署到 Linux docker 容器中,并从 VS 控制台应用程序本地访问它。

我想让事情尽可能简单,因此 docker 文件与 VS 中 docker compose 指向的 Net core gRPC docker 文件相同。直接在 VS 中运行 gRPC 服务时,控制台应用可以访问该服务,只是不能在 docker 容器中访问。

gRPC 启动设置

{
  "profiles": {
    "TrafficGrpc": {
      "commandName": "Project",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "https://localhost:5001"
    },
    "Docker": {
      "commandName": "Docker",
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
      "publishAllPorts": true,
      "useSSL": true
    }
  }
}

gRPC 应用设置

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "Http2"
    }
  }
}

Docker 文件

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["gRPC/TrafficGrpc/TrafficGrpc.csproj", "TrafficGrpc/"]
RUN dotnet restore "TrafficGrpc/TrafficGrpc.csproj"
COPY . .
WORKDIR "/src/gRPC/TrafficGrpc"
RUN dotnet build "TrafficGrpc.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "TrafficGrpc.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TrafficGrpc.dll"]

Docker 编写文件

version: "3.7"
services:

  # Traffic service
  traffic:
    container_name: traffic
    build:
      context: .
      dockerfile: Dockerfile-traffic
    networks:
      grpc_network:
    environment:
      - SERVICE_NAME=1
    expose:
      - "80"
      - "443"
    ports:
      - "0.0.0.0:32773:80"
      - "0.0.0.0:32774:443"
      
networks:
  grpc_network:

控制台应用程序,VS

string trafficUrl = "http://localhost:32773";
//string trafficUrl = "https://localhost:32774";

Traffic traffic = new Traffic
{
    Date = DateTime.Now.AddDays(1),
    Area = Areas[rng.Next(Areas.Length)],
    Condition = Conditions[rng.Next(Conditions.Length)]
};

GrpcChannel tChannel = GrpcChannel.ForAddress(trafficUrl);
TrafficCheckerClient tClient = new TrafficCheckerClient(tChannel);
TrafficConditionResponse tReply = await tClient.CheckTrafficConditionAsync(
    new TrafficConditionRequest { Condition = traffic.Condition }); // <-- ERROR here

运行 docker-compose 文件后,控制台应用程序无法连接到 gRPC。

使用http,我得到这个错误:

Grpc.Core.RpcException
  HResult=0x80131500
  Message=Status(StatusCode=Internal, Detail="Error starting gRPC call. HttpRequestException: An error occurred while sending the request. IOException: The response ended prematurely.")
  Source=System.Private.CoreLib
  StackTrace:
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ConsoleTestgRPC.Program.<Main>d__5.MoveNext() in D:\Workspace-GW-EV\CL\ConsoleTestgRPC\Program.cs:line 61

使用 https,我收到此错误:

Grpc.Core.RpcException
  HResult=0x80131500
  Message=Status(StatusCode=Internal, Detail="Error starting gRPC call. HttpRequestException: The SSL connection could not be established, see inner exception. IOException: Authentication failed because the remote party has closed the transport stream.")
  Source=System.Private.CoreLib
  StackTrace:
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ConsoleTestgRPC.Program.<Main>d__5.MoveNext() in D:\Workspace-GW-EV\CL\ConsoleTestgRPC\Program.cs:line 61

目前不知道是docker网络还是gRPC配置问题。

我需要帮助来指引我正确的方向。

谢谢你

【问题讨论】:

  • 我看到正在使用 localhost,它在本地运行时应该可以工作,但我不相信当您部署到容器中时会出现这种情况。如果您在容器中的 0.0.0.0 上公开服务,它将在所有容器接口上公开它。我只在 Windows 容器中这样做过,但我假设 Linux 也是如此
  • 我也无法让它工作。下面的评论看起来很有希望,但我仍然无法让它发挥作用

标签: c# docker .net-core grpc


【解决方案1】:

我在 Kubernetes 上运行映像时遇到了一些问题。修复:

1 - 要公开端口,我必须更改图像和应用程序并公开环境变量(但也只有 EXPOSE 有效)。

强制端口

2 - 我的问题是 TLS 协议上的证书(我没有)。我已经在我的 github 上发布了我如何在没有证书的情况下修复它。但是要注意环境。此示例只能应用于与 ClusterIp 的内部通信。公开展示是一种不安全的实施方式。 ??

链接修复(示例) https://github.com/davidsonsilvadev/grpc-core3.1-docker-kubernetes-without-certificate

【讨论】:

    【解决方案2】:

    我今天遇到了一个熟悉的问题。

    你在dockerfile中设置了EXPOSE 80,所以你需要让grpc去监听绑定到它的端口。

    所以在我的例子中,grpc 监听 8099,并将其暴露给主机端口:32812,然后客户端创建通道。并且有效。

    在dockerfile中:

    FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
    WORKDIR /app
    EXPOSE 8099
    EXPOSE 443
    

    在服务器监听端口:

    public static IWebHostBuilder CreateHostBuilder(string[] args) =>
                WebHost.CreateDefaultBuilder(args)
                    .ConfigureKestrel(options =>
                    {
                        options.ListenAnyIP(
                            8099,
                            listenOptions => { listenOptions.Protocols = HttpProtocols.Http2; }
                        );
                    })
                    .UseStartup<Startup>();
    

    在客户端创建频道:

    GrpcClientFactory.AllowUnencryptedHttp2 = true;
    
    using var http = GrpcChannel.ForAddress("http://localhost:32812");
    

    Binding port

    希望对你有帮助,祝你好运~

    【讨论】:

    • 请将您的代码作为文本包含在您的答案中,而不是截图
    • 您可以在此处提供更多详细信息吗?您使用的 docker run 命令是什么? 443有什么意义?不能去掉吗? AllowUnencryptedHttp2 不再存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-15
    • 2019-02-26
    • 1970-01-01
    • 2018-09-16
    • 1970-01-01
    • 2020-09-29
    • 1970-01-01
    相关资源
    最近更新 更多