.Net Core Dockerized WebAPI 无法向 Eureka 服务器注册

问题描述

我有一个 .Net Core 3.1 WebAPI 作为 Docker 容器运行 + Eureka 服务器也作为 Docker 运行。当我从 Visual Studio 运行 API 时,它成功注册到 Eureka Docker 实例,我可以在 Eureka 控制台中看到该服务。但是一旦我对 API 进行 dockerize 并运行它,我就会收到如下连接错误

fail: Steeltoe.discovery.Eureka.Transport.EurekaHttpClient[0]
productsapi_1   |       Registerasync Failed
productsapi_1   | System.Net.Http.HttpRequestException: Connection refused
productsapi_1   |  ---> System.Net.sockets.socketException (111): Connection refused
productsapi_1   |    at System.Net.Http.ConnectHelper.ConnectAsync(String host,Int32 port,CancellationToken cancellationToken)
productsapi_1   |    --- End of inner exception stack trace ---
productsapi_1   |    at System.Net.Http.ConnectHelper.ConnectAsync(String host,CancellationToken cancellationToken)
......
productsapi_1   |    at Steeltoe.discovery.Eureka.Transport.EurekaHttpClient.Registerasync(InstanceInfo info)
productsapi_1   | fail: Steeltoe.discovery.Eureka.discoveryClient[0]
productsapi_1   |       Register Failed
productsapi_1   | System.Net.Http.HttpRequestException: Connection refused
productsapi_1   |  ---> System.Net.sockets.socketException (111): Connection refused
productsapi_1   |    at System.Net.Http.ConnectHelper.ConnectAsync(String host,CancellationToken cancellationToken)
.....
productsapi_1   |    at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
productsapi_1   |    at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask,HttpRequestMessage request,CancellationTokenSource cts,Boolean 
disposeCts)
productsapi_1   |    at Steeltoe.discovery.Eureka.Transport.EurekaHttpClient.Registerasync(InstanceInfo info)
productsapi_1   |    at Steeltoe.discovery.Eureka.discoveryClient.Registerasync()
productsapi_1   | info: Steeltoe.discovery.Eureka.discoveryClient[0]
productsapi_1   |       Registartion fail. HeartBeat not start
productsapi_1   | fail: Steeltoe.discovery.Eureka.Transport.EurekaHttpClient[0]
productsapi_1   |       DoGetApplicationsAsync Failed
productsapi_1   | System.Net.Http.HttpRequestException: Connection refused
productsapi_1   |  ---> System.Net.sockets.socketException (111): Connection refused
.....

这是在运行 docker-compose up 之后。Eureaka 和 API 容器都已启动,但服务似乎没有注册。 这是我的 WebAPI 的样子:

Startup.cs

 public void ConfigureServices(IServiceCollection services)
    {
        .....       
        services.AddDbContext<ApplicationDbContext>(o => o.UseMysqL(Configuration.GetConnectionString("MysqLconnection")));
        services.AdddiscoveryClient(Configuration);
    }
    
    public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
    {        
       .....
        app.UseHttpsRedirection();
        app.UseRouting();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
        app.UsediscoveryClient();
    }

Docker 组合

version: '3.4'
services:
  productsapi:
    build: .
    ports: 
      - "5050:5000"
    depends_on:
      - eurekaserver
   
  eurekaserver:
    image: steeltoeoss/eureka-server:latest
    ports:
      - '8761:8761'

Appsettings.json

     {
     ...
  "AllowedHosts": "*",...
  "eureka": {
    "client": {
      "shouldRegisterWithEureka": true,"serviceUrl": "http://eurekaserver:8761/eureka","ValidateCertificates": false
    },"instance": {
      "appName": "ProductService","port": "5050","hostName": "localhost"
    }
  }
}

我错过了什么?

解决方法

我认为很有可能 Eureka 还没有准备好接收请求,这就是连接拒绝错误的原因。根据我的经验,Eureka 启动需要 7-15(ish) 秒。 Docker compose 将按依赖顺序启动容器,但不会在启动下一个之前等待第一个容器的就绪状态。有 options 可以更改启动行为,或者可以构建您的应用程序来处理这种性质的瞬时故障。

Steeltoe 旨在处理此类故障,并将尝试(默认情况下每 30 秒)向 Eureka 发送心跳。如果第一个请求失败(因为 Eureka 还没有启动),下一个应该会成功。

您分享的错误消息(以及您打开的 github issue)表明您使用的是 Steeltoe 2.1.1,该版本发布于近 3 年前(在 .NET Core 3.1 之前)。我不认为这可能是问题的根本原因,但我强烈建议使用较新的版本。

,

终于通过这个 OSS 调整让它工作了。我的 appsettings.json 现在看起来像这样:

 {
  "Logging": {
    "LogLevel": {
      "Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"
    }
  },"AllowedHosts": "*","ConnectionStrings": {
    "mysqlconnection": "server=mysqldata;port=3306;database=ProductsDB;userid=xxxx;password=xxxx;"
  },"PaymentsServiceUri": "http://PaymentService/api/payment","spring": {
    "application": {
      "name": "ProductService"
    }
  },"eureka": {
    "client": {
      "shouldRegisterWithEureka": true,"serviceUrl": "http://eurekaserver:8761/eureka","ValidateCertificates": false,"RegistryFetchIntervalSeconds": "15"
    },"instance": {
      "appName": "ProductService","port": "5050","hostName": "localhost","LeaseRenewalIntervalInSeconds": "15"
    }
    }
  }