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

问题描述 投票:0回答:2

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

我正在使用 Windows 10 专业版。

我正在尝试对这个应用程序进行 docker 化,将 MongoDB 容器基于官方

mongo:5
图像。

为了实现此目的,我需要一种将数据库初始化为副本集的自动化方法。我发现的教程依赖于

exec
进入容器并从
rs.initiate()
运行
mongosh
(或类似的方法),这是我想避免的手动工作。或者他们使用像
wait-for-it.sh
这样的黑客作为这里

我觉得必须有一个更好的解决方案,以某种方式基于docs中的“初始化一个新实例”段落。

它描述了

当容器第一次启动时,它将执行在

.sh
中找到的扩展名为
.js
/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
下使用。这让我觉得这段代码在所有其他初始化逻辑(网络)完成之前运行得太早了。

另一种方法是放置一个通过

mongosh
执行代码的 bash 脚本。这是我尝试过的:

#!/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镜像可以改进以允许这样的初始化逻辑吗?

mongodb docker initialization replicaset
2个回答
3
投票

我刚刚通过一次疯狂的实验让它发挥作用。意味着我只是在 JS 脚本中省略了对

rs.initiate()
的调用中的配置。由于某种原因,脚本成功运行并且更改流可供我的 NodeJS 后端使用。

我将发布运行启用更改流的 MongoDB docker 所需的所有内容:

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

0
投票

您能否解释一下为什么这种方法不起作用

因为初始化仅在第一次运行docker镜像时发生(即init脚本找不到数据库文件)。

当发生这种情况时,它会以隐形模式运行 MongoDB,监听器仅绑定到本地主机地址。

要执行集群初始化,运行

rs.initiate

的节点需要能够访问所有副本,包括其自身,但这显然不会发生。

这个 Github 问题中有更详细的讨论。

是否有另一种更好的自动化方法来初始化副本集?

是的,在这个

要点中。

我只保留要点链接,因为我不确定我是否有权在此处复制脚本主体。

© www.soinside.com 2019 - 2024. All rights reserved.