【问题标题】:containerized .net core app cannot connect to containerized mongo db容器化的 .net 核心应用程序无法连接到容器化的 mongo db
【发布时间】:2020-11-01 18:54:07
【问题描述】:

我正在本地计算机上运行 .net 核心应用程序。 以下是连接mongo db的代码

public BookService(IBookstoreDatabaseSettings settings)
        {
            var client = new MongoClient("mongodb://admin:password@localhost:27017");
            var database = client.GetDatabase("BookstoreDb");

            _books = database.GetCollection<Book>(settings.BooksCollectionName);
        }

此外,我正在运行以下 docker compose 文件

version: '3'
services: 
        mongodb:
        image: mongo
        ports:
            - 27017:27017
        environment:
            - MONGO_INITDB_ROOT_USERNAME=admin
            - MONGO_INITDB_ROOT_PASSWORD=password
    mongo-express:
        image: mongo-express
        ports:
            - 8081:8081
        environment:
            - ME_CONFIG_MONGODB_ADMINUSERNAME=admin
            - ME_CONFIG_MONGODB_ADMINPASSWORD=password
            - ME_CONFIG_MONGODB_SERVER=mongodb

当我使用 dotnet run 运行应用程序,然后请求 http://localhost:5001/api/books。一切正常,api 可以访问 mongo db。

接下来,我将使用标准 .net 核心 Docker 文件将我的应用程序容器化

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "BooksApi.dll"]

接下来我通过运行创建 Docker 映像

docker build -t sample:1.0 .  

然后我通过添加扩展 docker-compose

sampleapp:
        image: sample:1.0
        ports:
            - 5001:80

我正在运行 docker-compose -f .\mongo.yaml up

docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
86ae717ef475        mongo-express       "tini -- /docker-ent…"   About an hour ago   Up About an hour    0.0.0.0:8081->8081/tcp     sampleapp_mongo-express_1
3c068306c6e2        mongo               "docker-entrypoint.s…"   About an hour ago   Up About an hour    0.0.0.0:27017->27017/tcp   sampleapp_mongodb_1
f275479d2467        sample:1.0          "dotnet BooksApi.dll"    About an hour ago   Up About an hour    0.0.0.0:5001->80/tcp       sampleapp_sampleapp_1

在浏览器 http://localhost:5001/api/books 中请求 api 返回 500

docker logs f275479d2467 返回

Hosting environment: Production
Content root path: /app
Now listening on: http://[::]:80
Application started. Press Ctrl+C to shut down.
fail: Microsoft.AspNetCore.Server.Kestrel[13]
      Connection id "0HM3UHJ593UOV", Request id "0HM3UHJ593UOV:00000001": An unhandled exception was thrown by the application.
System.TimeoutException: A timeout occured after 30000ms selecting a server using CompositeServerSelector{ Selectors = MongoDB.Driver.MongoClient+AreSessionsSupportedServerSelector, LatencyLimitingServerSelector{ AllowedLatencyRange = 00:00:00.0150000 } }. Client view of cluster state is { ClusterId : "1", ConnectionMode : "Automatic", Type : "Unknown", State : "Disconnected", Servers : [{ ServerId: "{ ClusterId : 1, EndPoint : "Unspecified/localhost:27017" }", EndPoint: "Unspecified/localhost:27017", State: "Disconnected", Type: "Unknown", HeartbeatException: "MongoDB.Driver.MongoConnectionException: An exception occurred while opening a connection to the server.
 ---> System.Net.Sockets.SocketException (99): Cannot assign requested address
   at System.Net.Sockets.Socket.BeginConnectEx(EndPoint remoteEP, Boolean flowContext, AsyncCallback callback, Object state)
   at System.Net.Sockets.Socket.ConnectAsync(EndPoint remoteEP)
   at MongoDB.Driver.Core.Connections.TcpStreamFactory.ConnectAsync(Socket socket, EndPoint endPoint, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Connections.TcpStreamFactory.CreateStreamAsync(EndPoint endPoint, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Connections.BinaryConnection.OpenHelperAsync(CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at MongoDB.Driver.Core.Connections.BinaryConnection.OpenHelperAsync(CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Servers.ServerMonitor.HeartbeatAsync(CancellationToken cancellationToken)", LastUpdateTimestamp: "2020-11-01T17:38:08.7321465Z" }] }.
   at MongoDB.Driver.Core.Clusters.Cluster.ThrowTimeoutException(IServerSelector selector, ClusterDescription description)
   at MongoDB.Driver.Core.Clusters.Cluster.WaitForDescriptionChangedHelper.HandleCompletedTask(Task completedTask)
   at MongoDB.Driver.Core.Clusters.Cluster.WaitForDescriptionChanged(IServerSelector selector, ClusterDescription description, Task descriptionChangedTask, TimeSpan timeout, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Clusters.Cluster.SelectServer(IServerSelector selector, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoClient.AreSessionsSupportedAfterServerSelection(CancellationToken cancellationToken)
   at MongoDB.Driver.MongoClient.AreSessionsSupported(CancellationToken cancellationToken)
   at MongoDB.Driver.MongoClient.StartImplicitSession(CancellationToken cancellationToken)
   at MongoDB.Driver.OperationExecutor.StartImplicitSession(CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSession[TResult](Func`2 func, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.FindSync[TProjection](FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken)
   at MongoDB.Driver.FindFluent`2.ToCursor(CancellationToken cancellationToken)
   at MongoDB.Driver.IAsyncCursorSourceExtensions.ToList[TDocument](IAsyncCursorSource`1 source, CancellationToken cancellationToken)
   at BooksApi.Services.BookService.Get() in /app/Services/BookService.cs:line 24
   at lambda_method(Closure , Object , Object[] )
   at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

【问题讨论】:

  • 将 mongo uri 更改为 mongodb://admin:password@mongodb:27017 并重建。另请记住,此类信息应通过某些属性或环境变量注入,而不是硬编码。
  • 非常感谢,确实解决了这个问题。您能否提供一些上下文,为什么它在容器中运行时需要指向 mongodb。关于您的第二条评论,我完全同意我为自己做的只是 POC,因此一切都是硬编码的。还有一件事,你不想适当地回答这个问题,而不是通过 cmets。

标签: c# mongodb docker .net-core


【解决方案1】:

简答

将 mongo uri 更改为 mongodb://admin:password@mongodb:27017 并重建图像。

长答案

当您将应用程序放入 docker 容器中时,localhost 不再指代您的主机,而是指容器的 localhost。显然你的 mongodb 并没有在那里运行,而是在单独的容器中。

当您从 docker-compose 运行容器时,它们都连接到由 compose 创建的公共 docker 网络。然后,您撰写中的服务名称是一个 DNS 名称,可以通过该网络解析为容器的 IP。这就是为什么在您的情况下,您应该在连接字符串中使用 mongodb 作为 mongodb 的主机。您可以在docker-compose networking docs 阅读更多相关信息。

如上所述,连接字符串应取自环境,而不是硬编码。

【讨论】:

    猜你喜欢
    • 2020-12-23
    • 2020-02-01
    • 2021-12-16
    • 1970-01-01
    • 2021-09-22
    • 2019-06-21
    • 2019-11-15
    • 1970-01-01
    相关资源
    最近更新 更多