问题描述
我有一个 .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"
}
}
}