bounty 8小时后到期。此问题的答案有资格获得+500声望奖励。diegosasw希望吸引更多注意力这个问题:赏金赢家将是使用我创建的自定义副本集docker镜像的人,进行必要的更改(如果有的话),并成功地将其用作GitLab CI/CD服务,解释如何
我正在努力使用MongoDb 6副本集和CI/CD中的自动化测试。
我创建了一个带有副本集的docker镜像,用于开发和测试目的。
当在本地运行docker容器并对它运行测试时,这很好用。查看存储库https://gitlab.com/sunnyatticsoftware/sandbox/mongo-rs并查看公共存储库www.example.com中的docker镜像registry.gitlab.com/sunnyatticsoftware/sandbox/mongo-rs
它有一个dockerfile
FROM mongo:6.0.5-jammy as base
COPY ./init-mongodbs.sh ./init-replica.sh ./entry-point.sh /
RUN chmod +x /init-mongodbs.sh && \
chmod +x /init-replica.sh && \
chmod +x /entry-point.sh
# Data directory
ARG DB1_DATA_DIR=/var/lib/mongo1
ARG DB2_DATA_DIR=/var/lib/mongo2
ARG DB3_DATA_DIR=/var/lib/mongo3
# Log directory
ARG DB1_LOG_DIR=/var/log/mongodb1
ARG DB2_LOG_DIR=/var/log/mongodb2
ARG DB3_LOG_DIR=/var/log/mongodb3
# DB Ports
ARG DB1_PORT=27017
ARG DB1_PORT=27018
ARG DB1_PORT=27019
RUN mkdir -p ${DB1_DATA_DIR} && \
mkdir -p ${DB1_LOG_DIR} && \
mkdir -p ${DB2_DATA_DIR} && \
mkdir -p ${DB2_LOG_DIR} && \
mkdir -p ${DB3_DATA_DIR} && \
mkdir -p ${DB3_LOG_DIR} && \
chown `whoami` ${DB1_DATA_DIR} && \
chown `whoami` ${DB1_LOG_DIR} && \
chown `whoami` ${DB2_DATA_DIR} && \
chown `whoami` ${DB2_LOG_DIR} && \
chown `whoami` ${DB3_DATA_DIR} && \
chown `whoami` ${DB3_LOG_DIR}
EXPOSE ${DB1_PORT}
EXPOSE ${DB2_PORT}
EXPOSE ${DB3_PORT}
ENTRYPOINT [ "bash", "entry-point.sh" ]
它复制了一些在执行容器时运行的脚本entry-point.sh
#!/bin/bash
/bin/bash ./init-replica.sh &
/bin/bash ./init-mongodbs.sh
init-mongodbs.sh
#!/bin/bash
# Data directory
DB1_DATA_DIR="/var/lib/mongo1"
DB2_DATA_DIR="/var/lib/mongo2"
DB3_DATA_DIR="/var/lib/mongo3"
# Log directory
DB1_LOG_DIR="/var/log/mongodb1"
DB2_LOG_DIR="/var/log/mongodb2"
DB3_LOG_DIR="/var/log/mongodb3"
REPLICA_SET="${REPLICA_SET_NAME:-rs0}"
mongod --dbpath ${DB1_DATA_DIR} --logpath ${DB1_LOG_DIR}/mongod.log --fork --port 27017 --bind_ip_all --replSet $REPLICA_SET
mongod --dbpath ${DB2_DATA_DIR} --logpath ${DB2_LOG_DIR}/mongod.log --fork --port 27018 --bind_ip_all --replSet $REPLICA_SET
mongod --dbpath ${DB3_DATA_DIR} --logpath ${DB3_LOG_DIR}/mongod.log --port 27019 --bind_ip_all --replSet $REPLICA_SET
而init-replica.sh
#!/bin/bash
DB1_PORT=27017
DB2_PORT=27018
DB3_PORT=27019
LOCAL_HOST="${HOST:-localhost}"
REPLICA_SET="${REPLICA_SET_NAME:-rs0}"
SLEEP_INITIATE="${DELAY_INITIATE:-30}"
RS_MEMBER_1="{ \"_id\": 0, \"host\": \"${LOCAL_HOST}:${DB1_PORT}\", \"priority\": 2 }"
RS_MEMBER_2="{ \"_id\": 1, \"host\": \"${LOCAL_HOST}:${DB2_PORT}\", \"priority\": 0 }"
RS_MEMBER_3="{ \"_id\": 2, \"host\": \"${LOCAL_HOST}:${DB3_PORT}\", \"priority\": 0 }"
echo "Waiting ${SLEEP_INITIATE} seconds before initiating replica set"
sleep ${SLEEP_INITIATE}
mongosh --eval "rs.initiate({ \"_id\": \"${REPLICA_SET}\", \"members\": [${RS_MEMBER_1}, ${RS_MEMBER_2}, ${RS_MEMBER_3}] });"
echo "Replica set initiated"
echo "$(mongosh --eval "rs.status()")"
以便它可以作为
version: '3.8'
services:
mongors:
image: registry.gitlab.com/sunnyatticsoftware/sandbox/mongo-rs
container_name: mongors
environment:
HOST: mongors
DELAY_INITIATE: 40
ports:
- 27017:27017
- 27018:27018
- 27019:27019
注意,它接受一个环境变量HOST
,我可以用它来给予一个别名mongors
,这样在GitLab CI/CD中我就可以引用这个主机名。
我的应用程序连接字符串可能是这样的
mongodb://mongors:27017,mongors:27018,mongors:27019/?replicaSet=rs0&readPreference=primary&ssl=false
正如我所说的,当在本地将副本集作为docker容器运行时,这很好用(请参阅docker compose)。
**当它在GitLab CI/CD中运行时会超时。**我使用来自www.example.com的共享运行器GitLab.com,内置的。
运行gitlab-runner 16.1.0~beta.5.gf131a6a2(f131 a6 a2)
然而,连接似乎工作正常
$ nc -zv mongors 27017
Connection to mongors (172.17.0.4) 27017 port [tcp/*] succeeded!
$ nc -zv mongors 27018
Connection to mongors (172.17.0.4) 27018 port [tcp/*] succeeded!
$ nc -zv mongors 27019
Connection to mongors (172.17.0.4) 27019 port [tcp/*] succeeded!
所以连接是可以的,但我从我的应用程序中得到了这样的例外
System.TimeoutException: A timeout occurred after 30000ms selecting a server using CompositeServerSelector{ Selectors = MongoDB.Driver.MongoClient+AreSessionsSupportedServerSelector, LatencyLimitingServerSelector{ AllowedLatencyRange = 00:00:00.0150000 }, OperationsCountServerSelector }. Client view of cluster state is { ClusterId : "1", ConnectionMode : "ReplicaSet", Type : "ReplicaSet", State : "Connected", Servers : [{ ServerId: "{ ClusterId : 1, EndPoint : "Unspecified/mongors:27017" }", EndPoint: "Unspecified/mongors:27017", ReasonChanged: "Heartbeat", State: "Connected", ServerVersion: 6.0.0, TopologyVersion: { "processId" : ObjectId("646f9b54fb0fbb72cb9a3b70"), "counter" : NumberLong(0) }, Type: "ReplicaSetGhost", WireVersionRange: "[0, 17]", LastHeartbeatTimestamp: "2023-05-25T17:36:03.9519134Z", LastUpdateTimestamp: "2023-05-25T17:36:03.9519144Z" }] }.
提示副本集存在ReplicaSetGhost
或其他错误。
你知道为什么在GitLab CI/CD中,我不能让我的自动化集成测试连接到使用与我的HOST
env变量匹配的服务别名的连接字符串吗?
在某个时候我在痕迹中看到了这个
MongoServerError: No host described in new configuration with {version: 1, term: 0} for replica set rs0 maps to this node
因此,可能副本集内部不理解主机名mongors
?
**更新1(5月25日):**我创建了一个示例仓库,其中包含一个示例管道,该管道使用独立的mongoDB单示例和我创建的镜像mongo-rs来测试连接性。
https://gitlab.com/sunnyatticsoftware/sandbox/mongo-rs-tester
image: ubuntu:22.04
stages:
- test
test_mongors:
stage: test
services:
- name: registry.gitlab.com/sunnyatticsoftware/sandbox/mongo-rs
alias: mongors
variables:
# MongoDB
HOST: "mongors"
DELAY_INITIATE: "50"
before_script:
- apt-get update
- apt-get install -y curl
- apt-get install -y gnupg
- curl -fsSL https://www.mongodb.org/static/pgp/server-6.0.asc | tee /etc/apt/trusted.gpg.d/mongodb.asc > /dev/null
- echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-6.0.list
- apt-get update
- apt-get install -y mongodb-mongosh
- sleep 30
script: |
output=$(mongosh --host mongors:27017 --eval "db.stats()" 2>&1); if [ $? -eq 0 ]; then echo "OK"; else echo "ERROR: $output"; fi
test_mongo:
stage: test
services:
- name: mongo:6.0.5-jammy
alias: mongostandalone
variables:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: dummy
before_script:
- apt-get update
- apt-get install -y curl
- apt-get install -y gnupg
- curl -fsSL https://www.mongodb.org/static/pgp/server-6.0.asc | tee /etc/apt/trusted.gpg.d/mongodb.asc > /dev/null
- echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-6.0.list
- apt-get update
- apt-get install -y mongodb-mongosh
script: |
output=$(mongosh --host mongostandalone:27017 --username root --password dummy --eval "db.stats()" 2>&1); if [ $? -eq 0 ]; then echo "OK"; else echo "ERROR: $output"; fi
**更新2(5月29日):**将IP添加到/etc/hosts没有任何区别。
image: ubuntu:22.04
stages:
- test
test_mongors:
stage: test
services:
- name: registry.gitlab.com/sunnyatticsoftware/sandbox/mongo-rs
alias: mongors
variables:
# MongoDB
HOST: "mongors"
DELAY_INITIATE: "50"
before_script:
- apt-get update
- apt-get install -y curl
- apt-get install -y gnupg
- apt-get install -y dnsutils
- MONGORS_ALIAS="mongors"
- MONGORS_IP_ADDRESS=$(getent hosts $MONGORS_ALIAS | awk '{ print $1 }')
- echo "$MONGORS_IP_ADDRESS $MONGORS_ALIAS" >> /etc/hosts
- echo "MongoDB IP $MONGORS_IP_ADDRESS added"
- cat /etc/hosts
- curl -fsSL https://www.mongodb.org/static/pgp/server-6.0.asc | tee /etc/apt/trusted.gpg.d/mongodb.asc > /dev/null
- echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-6.0.list
- apt-get update
- apt-get install -y mongodb-mongosh
- sleep 30
script: |
output=$(mongosh --host mongors:27017 --eval "db.stats()" 2>&1); if [ $? -eq 0 ]; then echo "OK"; else echo "ERROR: $output"; fi
test_mongo:
stage: test
services:
- name: mongo:6.0.5-jammy
alias: mongostandalone
variables:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: dummy
before_script:
- apt-get update
- apt-get install -y curl
- apt-get install -y gnupg
- curl -fsSL https://www.mongodb.org/static/pgp/server-6.0.asc | tee /etc/apt/trusted.gpg.d/mongodb.asc > /dev/null
- echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-6.0.list
- apt-get update
- apt-get install -y mongodb-mongosh
script: |
output=$(mongosh --host mongostandalone:27017 --username root --password dummy --eval "db.stats()" 2>&1); if [ $? -eq 0 ]; then echo "OK"; else echo "ERROR: $output"; fi
更新3:30五月
为了简化,我创建了另一个存储库来测试我的MongoDB副本集映像
https://gitlab.com/sunnyatticsoftware/sandbox/mongo-rs-tester-dotnet
基本上,它是一个带有自动化测试的小型.NET应用程序,可以使用
dotnet test
我添加了一个docker-compose.yml
,其中包含一个用于复制集MongoDB映像的容器
version: '3.8'
services:
mongors:
image: registry.gitlab.com/sunnyatticsoftware/sandbox/mongo-rs
container_name: mongors
environment:
HOST: mongors
DELAY_INITIATE: 40
ports:
- 27017:27017
- 27018:27018
- 27019:27019
和.gitlab-ci.yml
的等价物,失败(我不知道为什么)
image: mcr.microsoft.com/dotnet/sdk:7.0
stages:
- test
test:
stage: test
services:
- name: registry.gitlab.com/sunnyatticsoftware/sandbox/mongo-rs
alias: mongors
variables:
HOST: "mongors"
DELAY_INITIATE: "40"
before_script:
- sleep 30
script:
- dotnet test
allow_failure: false
步骤如下:
要求
- .NET 7 SDK或运行时
- Docker和docker-compose
如何在本地运行
1.克隆存储库
1.在/etc/hosts
(或在Windows C:\Windows\System32\drivers\etc\hosts
中)中添加此条目,并使用localhost的别名
127.0.0.1 mongors
1.执行docker-compose up
以启动mongors
容器
1.使用dotnet test
运行测试
验证测试是否成功,并连接到Mongo副本集数据库
请注意,连接字符串是mongodb://mongors:27017,mongors:27018,mongors:27019/?replicaSet=rs0&readPreference=primary&ssl=false
,它使用别名mongors。
如何在GitLab CI/CD中运行
现在让我们在GitLab CI/CD中尝试等效的
1.运行CI/CD管道,这将启动别名为mongors
的容器服务,并将dotnet test命令作为脚本运行
1.如果测试正确连接到Mongo副本集数据库,请验证测试是否成功。
如果测试不成功并且管道失败,这是因为Mongo RS容器和测试在GitLab CI/CD中运行时的行为不同。为什么
它失败了
System.TimeoutException : A timeout occurred after 30000ms selecting a server using CompositeServerSelector{ Selectors = MongoDB.Driver.MongoClient+AreSessionsSupportedServerSelector, LatencyLimitingServerSelector{ AllowedLatencyRange = 00:00:00.0150000 }, OperationsCountServerSelector }. Client view of cluster state is { ClusterId : "1", ConnectionMode : "ReplicaSet", Type : "ReplicaSet", State : "Connected", Servers : [{ ServerId: "{ ClusterId : 1, EndPoint : "Unspecified/mongors:27017" }", EndPoint: "Unspecified/mongors:27017", ReasonChanged: "Heartbeat", State: "Connected", ServerVersion: 6.0.0, TopologyVersion: { "processId" : ObjectId("6475c89d5538f6657eda5c74"), "counter" : NumberLong(0) }, Type: "ReplicaSetGhost", WireVersionRange: "[0, 17]", LastHeartbeatTimestamp: "2023-05-30T09:59:11.3576006Z", LastUpdateTimestamp: "2023-05-30T09:59:11.3576012Z" }, { ServerId: "{ ClusterId : 1, EndPoint : "Unspecified/mongors:27018" }", EndPoint: "Unspecified/mongors:27018", ReasonChanged: "Heartbeat", State: "Connected", ServerVersion: 6.0.0, TopologyVersion: { "processId" : ObjectId("6475c89ea07e16061b09e4ec"), "counter" : NumberLong(0) }, Type: "ReplicaSetGhost", WireVersionRange: "[0, 17]", LastHeartbeatTimestamp: "2023-05-30T09:59:11.3575679Z", LastUpdateTimestamp: "2023-05-30T09:59:11.3576205Z" }, { ServerId: "{ ClusterId : 1, EndPoint : "Unspecified/mongors:27019" }", EndPoint: "Unspecified/mongors:27019", ReasonChanged: "Heartbeat", State: "Connected", ServerVersion: 6.0.0, TopologyVersion: { "processId" : ObjectId("6475c89e4cf3656cf898c899"), "counter" : NumberLong(0) }, Type: "ReplicaSetGhost", WireVersionRange: "[0, 17]", LastHeartbeatTimestamp: "2023-05-30T09:59:11.3496821Z", LastUpdateTimestamp: "2023-05-30T09:59:11.3496847Z" }] }
更新4:31五月
我已经禁用了共享的runner,并创建和注册了我自己的docker
类型的Linux runner。
有了这个转轮,测试成功了。
https://gitlab.com/sunnyatticsoftware/sandbox/mongo-rs-tester-dotnet/-/jobs/4385389688
我希望服务和CI/CD对跑步者是不可知的。
有没有什么解释为什么它不适用于共享跑步者?
1条答案
按热度按时间wn9m85ua1#
如果它在本地运行良好,这应该意味着设置本身是好的,但是GitLab CI/CD处理网络的方式和/或MongoDB副本集解析主机名的方式是有问题的。
错误消息
MongoServerError: No host described in new configuration with {version: 1, term: 0} for replica set rs0 maps to this node
表明主机名mongors
在MongoDB副本集中无法识别。默认情况下,MongoDB副本集成员使用指定为during the
rs.initiate()
command的主机名相互通信。当您在单独的机器上或使用localhost在单个机器上运行MongoDB示例时,这通常不是问题,但当您在Docker容器内运行MongoDB时,它可能会导致问题,其中容器内的主机名可能与容器外的主机名不同。在本例中,您使用HOST环境变量(设置为
mongors
)初始化MongoDB副本集,因此MongoDB节点应该使用mongors
别名进行节点间通信。但是,您看到的错误消息表明,在MongoDB节点中无法识别mongors
别名。当您启动MongoDB副本集时,您使用的主机名(或别名)存储在MongoDB的副本集配置中。MongoDB使用这些主机名(或别名)进行副本集内的节点间通信。
如果你使用了一个别名,比如
mongors
,并且这个别名在Docker容器中是正确的defined in the/etc/hosts
file(如果你在GitLab CI/CD中使用alias
功能,应该是这种情况),那么MongoDB应该能够使用这个别名进行节点间通信。(Note:对Kubernetes executor was introduced in GitLab Runner 12.8的别名支持,仅适用于Kubernetes版本1.7或更高版本。
然而,重要的是要注意,这取决于在Docker容器内正确定义的别名,以及MongoDB能够将此别名解析为IP地址。如果别名解析存在任何问题,这可能会导致您看到的问题。
此外,如果您的MongoDB节点在单独的Docker容器中运行(在副本集中通常是这种情况),则需要确保在每个容器的
/etc/hosts
文件中定义别名,并且每个容器可以将此别名解析为正确的IP地址。如果你使用的是Docker的默认桥接网络,这应该会自动发生。但是如果您使用的是自定义网络,则可能需要使用Docker的--add-host
选项手动添加别名。查看您的
.gitlab-ci.yml
:在GitLab CI/CD中,同一阶段的作业并行执行,但不同阶段的作业按顺序执行。
在你的管道中,test_mongo和test_mongors这两个作业都在同一个阶段,名为
test
。因此,默认情况下,它们将并行执行。但是一旦
test_mongo
运行,它的mongodb独立示例就不再存在了。GitLab CI/CD管道中的每个作业都在自己的隔离环境中运行。这意味着在作业中定义的服务,例如您的MongoDB示例,仅在作业运行时存在。作业完成后,其环境(包括已启动的任何服务)将被拆除。
因此,在管道中,当
test_mongors
作业启动时,在test_mongo
作业中启动的MongoDB示例将不再存在。如果
test_mongors
作业需要与test_mongo
作业中的MongoDB示例进行交互,它将无法进行交互,因为该示例将被关闭。我尝试在test_mongo仍在运行时为test_mongors添加必要的睡眠来测试访问,但it fails。
使用您的第二个gitlab-ci.yml,我尝试添加一个
mongosh --host $HOST --port 27017 --eval "db.stats()"
。我得到了:
在这个阶段,我将更新Docker镜像以启用HTTP接口:您需要在配置文件中使用
--httpinterface
选项或net.http.enabled: true
选项启动MongoDB。要启用RESTful接口,您需要在配置文件中使用
--rest
选项或net.http.RESTInterfaceEnabled: true
选项启动MongoDB。然后,您可以使用curl或wget向MongoDB发出HTTP请求。
我会在120秒内检查状态如何演变(每10秒),以尝试了解数据库集群状态。
来自评论:
当使用GitLab runner“on
sasw-linux
”执行时,它可以工作。但是当在green-1.shared.runners-manager.gitlab.com/default
上使用GitLab Runner执行时失败了。shared.runners-manager.gitlab.com/default
”将失败最近共享runner出现了一些问题,比如# 30944: unix socket errors when
NETWORK_PER_BUILD
is enabled on the Shared Runners。虽然它可能与手头的问题无关,但它说明了特定type of runner上缺乏稳定性。使用自己的跑步者手动注册似乎更安全。