为 docker 中的 mongoDB 自动初始化副本集失败

Automatically initialize replica set for mongoDB in docker fails

我有一个依赖 MongoDB 更改流的 NodeJS Express 应用程序。为了使它们可用,必须将 MongoDB 配置为 运行 作为副本集(即使该集合中只有一个节点)。

我正在研究 Windows 10 专业版。

我正在尝试 docker 化这个应用程序,MongoDB 容器基于官方 mongo:5 图像。

为此,我需要一种自动将数据库初始化为副本集的方法。我发现的教程依赖于 execing 进入容器和 运行ning rs.initiate() 来自 mongosh(或类似方法),这是我想避免的手动工作。或者他们使用像 wait-for-it.sh 作为 here.

这样的技巧

我觉得一定有更好的解决方案,以某种方式基于 docs.

中的“初始化新实例”段落

它描述了

When a container is started for the first time it will execute files with extensions .sh and .js that are found in /docker-entrypoint-initdb.d.

恰好 容器生命周期 中时,会发生这种情况吗?容器初始化后?或者在数据库准备好之后?因为这似乎是此初始化逻辑的完美位置,运行在容器内手动执行时完美无缺。

但是,放置

// initReplSet.js
print('Script running');
config={"_id":"rs0", "members":[{"_id":0,"host":"app-db:27017"}]};
print(JSON.stringify(rs.initiate(config)));
print('Script end');

失败并显示错误 {"ok":0,"errmsg":"No host described in new configuration with {version: 1, term: 0} for replica set rs0 maps to this node","code":93,"codeName":"InvalidReplicaSetConfig"},但该数据库在其他容器的主机名 app-db 下可用。这让我觉得这段代码 运行 太早了,在所有其他初始化逻辑(网络)完成之前。

另一种方法是放置一个 bash 脚本,通过 mongosh 执行代码。这是我尝试过的:

#!/bin/bash
mongosh "mongodb://app-db:27017/app_db" "initiateReplSet"

其中 initiateReplSet

config={"_id":"rs0", "members":[{"_id":0,"host":"app-db:27017"}]}
rs.initiate(config)
exit

但这会使容器崩溃并出现错误

/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/initiateReplSetWrapper.sh

{"t":{"$date":"2022-02-15T11:31:23.353+00:00"},"s":"I",  "c":"-",        "id":4939300, "ctx":"monitoring-keys-for-HMAC","msg":"Failed to refresh key cache","attr":{"error":"NotYetInitialized: Cannot use non-local read concern until replica set is finished initializing.","nextWakeupMillis":600}}

Warning: Could not access file: EACCES: permission denied, mkdir '/home/mongodb'

Current Mongosh Log ID: 620b8f0b04b7ad69b446768d

Connecting to: mongodb://app-db:27017/app_db?directConnection=true&appName=mongosh+1.1.9

只有第一和最后三行似乎真的属于bash脚本,第二行不断重复。

我不确定错误是否源于 permission denied 问题,或者是否真的无法访问数据库。但是,指定

RUN mkdir -p /home/mongodb/.mongodb
RUN chown -R 777 /home/mongodb

Dockerfile 中并没有改善这种情况(尽管如此还是同样的错误)。

能否请您解释一下为什么这种方法行不通,或者如何使它行得通?是否有另一种更好的自动化方式来初始化副本集?可以改进 docker 图像以允许这样的初始化逻辑吗?

我只是通过一个疯狂的实验让它工作。意味着我只是在从 JS 脚本调用 rs.initiate() 时省略了配置。出于某种原因,脚本然后 运行 成功并且更改流对我的 NodeJS 后端可用。

我会 post 运行 MongoDB docker 启用更改流所需的一切:

# Dockerfile
From mongo
WORKDIR .
COPY initiateReplSet.js ./docker-entrypoint-initdb.d/
CMD ["-replSet", "rs0"]
// initiateReplSet.js
rs.initiate()