使用 Docker Compose 的容器化 .net 核心应用程序无法解析 MongoDb 容器名称

Containerized .net core application using Docker Compose does not resolve MongoDb container name

我在 Visual Studio 2017(版本 15.9.16)中开发了一个简单的 .Net Core 2.2 单元测试项目,该项目连接到一个 MongoDb 实例,支持 Container Orchrestation 支持。我的目的是 运行 一个带有 MongoDb 实例的容器,只要从测试资源管理器 window 启动单元测试,它们就会连接到该实例。我面临的问题是,从单元测试代码我无法连接到MongoDb容器,无法解析docker-compose.yml中定义的服务名称。

以下是 docker-compose.yml 文件的内容:

version: '3.4'

services:
  myapp:
    image: ${DOCKER_REGISTRY-}myapp
    build:
      context: .
      dockerfile: myapp/Dockerfile
    depends_on:
      - mongo
  mongo:
    image: mongo:latest

应用的Dockerfile内容如下:

FROM microsoft/dotnet:2.2-runtime AS base
WORKDIR /app

FROM microsoft/dotnet:2.2-sdk AS build
WORKDIR /src
COPY myapp/myapp.csproj myapp/
RUN dotnet restore myapp/myapp.csproj
COPY . .
WORKDIR /src/myapp
RUN dotnet build myapp.csproj -c Release -o /app

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

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

在单元测试代码中,如果我在尝试写入数据库时​​尝试使用 var client = new MongoClient("mongodb://mongo:27017"); 连接到 MongoDb 实例,我会收到以下异常:

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/mongo:27017" }", EndPoint: "Unspecified/mongo:27017", State: "Disconnected", Type: "Unknown", HeartbeatException: "MongoDB.Driver.MongoConnectionException: An exception occurred while opening a connection to the server. ---> System.Net.Sockets.SocketException: Unknown host at System.Net.Dns.HostResolutionEndHelper(IAsyncResult asyncResult) at System.Net.Dns.EndGetHostAddresses(IAsyncResult asyncResult) at System.Net.Dns.<>c.b__25_1(IAsyncResult asyncResult) at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization) --- End of stack trace from previous location where exception was thrown --- at MongoDB.Driver.Core.Connections.TcpStreamFactory.ResolveEndPointsAsync(EndPoint initial) 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: "2019-10-03T10:00:40.7989018Z" }] }.'

如果我尝试使用 System.Net.Dns.GetHostEntry("mongo") 解析 MongoDb 容器服务名称,我会收到此异常:

System.Net.SocketException: 'Unknown host'

我很清楚单元测试容器内的 .Net Core 代码无法解析 docker-compose.yml 服务名称。另一方面,如果我在单元测试容器中启动一个会话,我可以成功地执行 ping mongotelnet mongo 27017。我还尝试确保 MongoDb 容器已按照 中的建议启动,但没有成功。我的代码或 docker 配置文件中必须缺少某些内容才能启用服务名称解析。任何帮助将不胜感激。

您可以声明一个网络并为每个服务关联一个 IP 地址,然后使用 mongo 服务的 IP 地址而不是解析其主机名:

version: '3.4'

services:
  myapp:
    image: ${DOCKER_REGISTRY-}myapp
    build:
      context: .
      dockerfile: myapp/Dockerfile
    depends_on:
      - mongo
    networks:
      mynetwork:
        ipv4_address: 178.25.0.3
  mongo:
    image: mongo:latest
    networks:
      mynetwork:
        ipv4_address: 178.25.0.2

networks:
  mynetwork:
    driver: bridge
    ipam:
      config:
      - subnet: 178.25.0.0/24

MongoClient("mongodb://178.25.0.2:27017");

最后我在我的单元测试代码中 运行 System.Net.Dns.GetHostName() 之后找到了这种行为的原因,并且看到返回的名称是主机名而不是容器名称。我忘了说我是 运行 我从测试资源管理器 window 进行的单元测试,这样就完全忽略了容器支持。与我的预期相反,Docker Compose 没有被调用,因此 MongoDb 容器和单元测试项目容器都没有启动,单元测试项目只是 运行 在主机内部。在 Visual Studio 中启用容器支持时,运行 容器中的单元测试功能已在 https://developercommunity.visualstudio.com/idea/554907/allow-running-unit-tests-in-docker.html 中提出。请为此功能投票!