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

Posted

技术标签:

【中文标题】使用 Docker Compose 的容器化 .net 核心应用程序无法解析 MongoDb 容器名称【英文标题】:Containerized .net core application using Docker Compose does not resolve MongoDb container name 【发布时间】:2020-02-01 19:18:35 【问题描述】:

我在 Visual Studio 2017(版本 15.9.16)中开发了一个简单的 .Net Core 2.2 单元测试项目,该项目连接到启用容器编排支持的 MongoDb 实例。我的目的是运行一个带有 MongoDb 实例的容器,只要从测试资源管理器窗口启动单元测试,它们就会连接到该容器。我面临的问题是从单元测试代码中我无法连接到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 实例,则会收到以下异常:

在选择服务器 30000 毫秒后发生超时 CompositeServerSelector 选择器 = MongoDB.Driver.MongoClient+AreSessionsSupportedServerSelector, LatencyLimitingServerSelector AllowedLatencyRange = 00:00:00.0150000 。集群状态的客户端视图是 ClusterId : "1", ConnectionMode :“自动”,类型:“未知”,状态:“断开连接”,服务器:[ ServerId: " ClusterId : 1, EndPoint : "Unspecified/mongo:27017" ", 端点:“未指定/mongo:27017”,状态:“断开连接”,类型: “未知”,心跳异常: “MongoDB.Driver.MongoConnectionException:发生异常时 打开与服务器的连接。 ---> System.Net.Sockets.SocketException:未知主机位于 System.Net.Dns.HostResolutionEndHelper(IAsyncResult asyncResult) 在 System.Net.Dns.EndGetHostAddresses(IAsyncResult asyncResult) 在 System.Net.Dns.c.b__25_1(IAsyncResult asyncResult) 在 System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar,Func`2 endFunction,Action`1 endAction,Task`1 承诺,布尔 需要同步) --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 MongoDB.Driver.Core.Connections.TcpStreamFactory.ResolveEndPointsAsync(端点 初始)在 MongoDB.Driver.Core.Connections.TcpStreamFactory.CreateStreamAsync(端点 endPoint,CancellationToken 取消令牌)在 MongoDB.Driver.Core.Connections.BinaryConnection.OpenHelperAsync(CancellationToken cancelToken) --- 内部异常堆栈跟踪结束 --- at MongoDB.Driver.Core.Connections.BinaryConnection.OpenHelperAsync(CancellationToken 取消令牌)在 MongoDB.Driver.Core.Servers.ServerMonitor.HeartbeatAsync(CancellationToken cancelToken)", LastUpdateTimestamp: “2019-10-03T10:00:40.7989018Z”] 。'

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

System.Net.SocketException: '未知主机'

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

【问题讨论】:

【参考方案1】:

您可以为每个服务声明一个网络并关联一个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");

【讨论】:

感谢您的帮助!我是 Docker 的新手,不知道可以为容器设置固定的 IP 地址。但是,正如我在回答中提到的那样,这无法解决我报告的问题,因为原因仅仅是容器没有从测试资源管理器窗口运行。【参考方案2】:

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

【讨论】:

以上是关于使用 Docker Compose 的容器化 .net 核心应用程序无法解析 MongoDb 容器名称的主要内容,如果未能解决你的问题,请参考以下文章

.NET Core容器化之多容器应用部署@Docker-Compose

docker与docker-compose介绍,对比与使用

研发环境容器化实施过程(docker + docker-compose + jenkins)

Docker-compose使用

10-Docker-Docker Compose

docker-compose