为什么 Node.js 12 docker 应用程序通过 docker 网络连接到 MongoDB 4 会超时,而通过 public 网络的连接有效?

Why is a Node.js 12 docker app connection to MongoDB 4 via the docker network giving a timeout while a connection via the public network works?

我遇到了一个我根本无法解释的问题:

将 Meteor 应用程序升级到 v 1.9 后 Node.js 12,我们还必须将 docker 容器切换到基于 Node.js 12 的容器。在我们的例子中,我们使用 abernix/meteord:node-12-base (git).

启动更新后的应用程序后,我们在应用程序的 docker 容器中收到数据库超时:

/bundle/bundle/programs/server/node_modules/fibers/future.js:313
                                               throw(ex);
                                               ^

MongoTimeoutError: Server selection timed out after 10000 ms
    at Timeout._onTimeout (/bundle/bundle/programs/server/npm/node_modules/meteor/npm-mongo/node_modules/mongodb-core/lib/sdam/topology.js:773:16)
    at listOnTimeout (internal/timers.js:531:17)
    at processTimers (internal/timers.js:475:7) {
  name: 'MongoTimeoutError',
  [Symbol(mongoErrorContextSymbol)]: {}
}


以下 MONGO_URL:

会发生这种情况

❌ mongodb://root:OurPw@mongo-docker-alias:27017/meteor?authSource=admin

有趣的是,当我们在 MongoDB 容器中公开端口 27017 时,以下 MONGO_URL 就可以工作了:

✔️ mongodb://root:OurPw@docker-host:27017/meteor?authSource=admin


现在我认为我们遇到了 docker 问题,但如果我在 Node.js 12 meteord 容器内附加一个 bash,安装 MongoDB shell 并尝试联系:

✔️ mongo "mongodb://root:OurPw@mongo-docker-alias:27017/meteor?authSource=admin"

这也行得通。


现在我一无所知。我在 v4.0 和 4.2.3 以及 Node.js 12.14 和 12.10 之间尝试了多个 MongoDB docker 图像。而且我也试过一次没有 MongoDB auth 只是为了排除问题但结果总是一样的。

任何想法将不胜感激,因为我想避免必须通过暴露的端口和 docker 主机名进行连接,因为这显然容易出错...

检查网络绑定的/etc/mOngd.conf 文件。您可能需要允许它在所有网络接口上响应,因为网络在暴露(或不暴露)时可能会有所不同 ip/subnet,这可能解释了为什么它在某些情况下有效

tl;博士:

docker-compose.yml 中为后端设置 dns_search: ''(或通过 docker CLI 或其他方式)解决了这个问题。

更多信息:

Docker 似乎默认将主机 /etc/resolv.conf 的任何 search 指令添加到容器的 /etc/resolv.conf。但是,解析 mongo-docker-alias.actual-intranet-domain.tld 之类的内容可能会出现问题,因为外部网络和 DNS 不知道该子域。实际上,我们发现在我们的案例中它仍然在容器内得到解决,只需要几秒钟(通常 <1 毫秒)。而且由于后端尝试建立多个数据库连接,它总是会超时。

幸运的是,

Docker's DNS search option 允许偏离默认行为,包括设置空白值。知道这个问题后,另一个解决方法应该是使用带有点的 docker 别名,因为那时不应该使用 search,但我们还没有尝试过。

还有几个问题,但不是很重要。就像在我们的例子中,为什么 Meteor 更新会发生这种情况,也许真正的原因是主机上的 docker 版本也发生了变化,因为我们不会意识到基础设施的变化。一般来说,为什么 docker 将这些条目添加到 /etc/resolv.conf?它似乎不是很有用,但如果有用的话,一般来说可能有更好的方法吗?

davd.io 也发布了关于此事的非常有用的博客 post。