Docker Run MongoDB replica set.., how is it working? - mongodb

So I'm creating some softwaare that makes heavy use of mongo transactions.
So far, I've tried only with testcontainers mongo, and pure unit testing.
Now I'm moving to test it manually and I get an error that says something like: Transaction numbers are only allowed on a replica set ..., yet that error doesn't happen during unit tests.
I read that this error happens because transactions are only possible on a replica set, but then, how is testcontainers working? I checked docker ps during running of tests and only one mongo docker container is up.
I checked the args passed by testcontainers, and it resulted they pass --replSet docker-rs. So I did, but then I get this error: NotYetInitialized: Cannot use non-local read concern until replica set is finished initializing.
I'm scratching my head bad, wondering how is testcontainers running a ONE mongo docker container that behaves like a replica set.

Assuming you're using Tescontainers MongoDB module, the missing part in your manual setup is most probably the mongo replica set initiation.
This is mentioned in the testcontainers module docs as:
Initialize a single replica set via executing a proper command
Also feel free to take a look at the module sources itself to dig into implementation details. For example, initReplicaSet() part.

Related

Automatically initialize replica set for mongoDB in docker fails

I have a NodeJS Express App that depends on MongoDB change streams. For them to be available, MongoDB has to be configured to run as a replica set (even if there is only one node in that set).
I'm working on Windows 10 pro.
I'm trying to dockerize this App, basing the MongoDB container off the official mongo:5 image.
For this to work, I want an automated way of initializing the DB as a replica set. Tutorials I've found rely on either execing into the container and running rs.initiate() from mongosh (or similar approaches), which is manual work I want to avoid. Or they use hacks like wait-for-it.sh as here.
I feel there must be a better solution, based somehow on the paragraph "Initializing a fresh instance", from the docs.
It describes that
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.
When exactly in the container lifecycle does that happen? After the container is initialized? Or after the DB is ready? Because this seems to be the perfect place for this initialization logic, which runs flawlessly when executed manually, from within the container.
However, placing
// initReplSet.js
print('Script running');
config={"_id":"rs0", "members":[{"_id":0,"host":"app-db:27017"}]};
print(JSON.stringify(rs.initiate(config)));
print('Script end');
fails with the error {"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"}, yet the database is available under the hostname app-db from other containers. This makes me feel that this code runs too early, before all other initialization logic (networking) is done.
Another approach is to place a bash script that executes code via mongosh. Here's what I've tried:
#!/bin/bash
mongosh "mongodb://app-db:27017/app_db" "initiateReplSet"
where initiateReplSet is
config={"_id":"rs0", "members":[{"_id":0,"host":"app-db:27017"}]}
rs.initiate(config)
exit
but this crashes the container with the error
/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
Only the first and the last three lines seem to really belong to the bash script, the second line is repeated constantly.
I'm not sure whether the error originates at the permission denied issue, or whether the DB really can't be accessed. However, specifying
RUN mkdir -p /home/mongodb/.mongodb
RUN chown -R 777 /home/mongodb
in the Dockerfile did not improve the situation (same error nevertheless).
Could you please explain either why this approach can not work, or how to make it work? Is there another, better, automated way to initialize the replica set? Could the docker image be improved to allow such initialization logic?
I just made it work with a wild experiment. Means I simply left out the config in my call to rs.initiate(), from the JS script. For some reason, the script then runs successfully and change streams become available to my NodeJS backend.
I will post everything that's needed to run a MongoDB docker with change streams enabled:
# Dockerfile
From mongo
WORKDIR .
COPY initiateReplSet.js ./docker-entrypoint-initdb.d/
CMD ["-replSet", "rs0"]
// initiateReplSet.js
rs.initiate()

How to monitor mongo db replica status and reconfiguring repluica

We are using mongodb cluster with set of 3 members , and all consumers are able to read/write data.
Use mongo.conf file to create cluster && configure replica set, which are executed in ansible script as part of system restart.
Our system does heavy writes/read operation on mongo clusters ,and sometime replica get broken.
Then it is no longer feasible to restore replica without deleting data from one of the corrupted server.
Here are my queries:
what is better way to notify when replica is broken using script/some code?We can not use Mongo atlas
etc.
What is efficient way to restore data on corrupted member.
What is better way to notify when replica is broken using script/some code?
Use the replSetGetStatus database command.
You can run this command from any driver or the shell. Among other things, it returns the state (primary/secondary/startup/recovery/unreachable) and last applied operation time for each member.
What is efficient way to restore data on corrupted member.
Check out the docs for a few options: https://docs.mongodb.com/manual/tutorial/resync-replica-set-member/#resync-a-member-of-a-replica-set

How to check the state of rs.initiate

I have an existing system using replica set of 3 members already running, I am trying to add another member, but I saw in the Doc that I need to run this command rs.initiate() fist before I can add another member rs.add(“hostname03:27017”)
Do I need to run rs.initiate() ? I am assuming that I don't need to since I already have a replica set up & running. How do I check the status of rs.initiate if it has already been initiated.. Thanks.
You don't need to. The rs.initiate() command is not much more than telling the instance you are connected to that it should set up everything for a replica set. In your case, this has already be done. So simply connect to the primary of your replica set and add the member.
Disclaimer: The following comes of the top of my head and I don't have the means of checking its correctness on my tablet.
Iirc, rs.initiate() is a shell helper. So you might be able to see what it is actually doing by issuing
rs.initiate
(Note the missing parenthesises) in the mongo shell.

MongoDB Replica Sets Not Syncing?

I've been following the steps on the tutorial for deploying a replica set to a development/test environment: http://docs.mongodb.org/manual/tutorial/deploy-replica-set/#deploy-a-development-or-test-replica-set
I have three instances of mongod.exe running, and all three are able to connect properly.
I wanted to verify that the Secondaries are properly syncing up to the Primary when an Insert happens, but when I do an Insert, there doesn't seem to be any indication that the Secondaries are following through.
For instance, I have a MongoShell connected to the Primary and I run the commands:
db.createCollection("testCol")
db.testCol.insert( { item: "card", qty: 15 } )
This creates the 'testCol' collection and inserts a value into it.
When I do:
show collections
The 'testCol' collection shows up fine, and the item I inserted is present.
My question is: Shouldn't the Secondaries sync up with the Primary and copy the Collection and Item over?
Starting up another MongoShell and connecting to one of the Secondaries, I see that the collection I created on the Primary is not showing up.
Am I just misunderstanding how Replica Sets work, or is there something else that I need to set in order for the Secondaries to copy Insert actions?
I followed the instructions in the link I gave in the beginning, so any configurations that I have set up are exactly the same.
Well that's embarrassing.
Turns out that I was looking at the incorrect database on my side. The way that I'd configured, I needed to be using a database named test but I had been doing inserts on local.
Looking back at the setup instructions for Replica Sets, I'm not quite sure where I configured MongoShell to connect to test, but connecting to that database and making a change on the Primary seemed to fix everything.
Here's how my MongoShell connected to the Primary looked like:
MongoDB shell version: 2.4.5
connecting to: 127.0.0.1.27017/test
Maybe the connection to test was configured when I first set up MongoDB? Not too sure right now.
Doing a little more looking around, it seems like when you connect with MongoShell, it's automatically connecting to the test database. Not sure how to change parameters in the shortcut I'm using in order to have it point to a different database.
http://docs.mongodb.org/manual/reference/mongo-shell/#basic-shell-javascript-operations
In the mongo shell, db is the variable that references the current
database. The variable is automatically set to the default database
test or is set when you use the use to switch current database.
I guess this means there's no parameter you can pass in, and you have to do a use <db> manually?
Found it!
If you set up a shortcut to mongo.exe, set this as your Target:
C:\mongodb\bin\mongo.exe <db name> --host <host> --port <port>
Previously I only had the --port parameter, but adding in the rest allowed me to start directly in a specific database.

Mongo Java Replica Set - Can't find master

I'm having problem with connecting to Mongo Replica Set in production. Replica Set has master on one machine, and secundary + arbiter on other machine.
When I run my application locally it connects and uses Replica Set properly. I'm using Windows OS.
Mongo URI is like this:
mongodb://192.168.2.95:20000,192.168.2.96:20000/testDatabase
I'm using Java Driver 2.10.1.
When I deploy application in production server, It can't use replica set. Error is "can't find master".
When I change mongo URI to use single node, like this:
mongodb://192.168.2.95:20000/testDatabase
then it works!
What's the problem? I have search the web and I found few people with similar problem but I didn't found any proper solution...