-
Notifications
You must be signed in to change notification settings - Fork 632
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Creating a mongo image set with --replSet
#246
Comments
Hi @gioragutt. Have you resolved this ticket? |
@gioragutt @YashchenkoN same here |
I really don't see the problem guys. I did it like this. #!/usr/bin/env bash
mkdir -p data/{db1,db2,db3}
#Create docker network
docker network create mongonet
# Here we start our main MongoDB instances in 3.6.3
docker run -d -p 27017:27017 -v $(pwd)/data/db1:/data/db1 \
-u 1000:1000 -h mongo1 --network mongonet \
--network-alias mongo1 --name mongo1 \
mongo:3.6.3 --dbpath /data/db1 --replSet replicaTest --bind_ip_all --logpath /data/db1/mongod.log
docker run -d -p 27018:27017 -v $(pwd)/data/db2:/data/db2 \
-u 1000:1000 -h mongo2 --network mongonet \
--network-alias mongo2 --name mongo2 \
mongo:3.6.3 --dbpath /data/db2 --replSet replicaTest --bind_ip_all --logpath /data/db2/mongod.log
docker run -d -p 27019:27017 -v $(pwd)/data/db3:/data/db3 \
-u 1000:1000 -h mongo3 --network mongonet \
--network-alias mongo3 --name mongo3 \
mongo:3.6.3 --dbpath /data/db3 --replSet replicaTest --bind_ip_all --logpath /data/db3/mongod.log
sleep 1
# Here we initialize the replica
echo 'rs.initiate({
_id: "replicaTest",
members: [
{ _id: 0, host: "mongo1:27017" },
{ _id: 1, host: "mongo2:27017" },
{ _id: 2, host: "mongo3:27017", arbiterOnly:true }]});' | mongo Most of the options on my You could also create your own image (with a Dockerfile) and insert a new YML conf file and use it to start your MongoDB. |
@MaBeuLux88 this is a script. Our question is how do we create a Dockerfile for an image that does this out of the box. |
Ok now I understand and here is my answer 2.0. Moreover, if I understood correctly your real problem : you want to run MongoDB on AWS and MongoDB already has a DBaaS : MongoDB Atlas. It's a fully managed service and as tons of advantages versus running it yourself on AWS. Example of features you would miss :
|
Since the data is normally in a volume ( FROM mongo:3.6
CMD [ "--dbpath", "/some/path/outside/data/db/", "--replSet", "myrepl" ] As far as embedding the data using a |
@yosifkit the only thing that is hard here is the part of running AFAIK, running commands on the |
If you don't want to commit the data to the image then this will work for your first cluster member (since the initdb.d scripts are only run when the data directory is empty). FROM mongo:3.6
RUN echo "rs.initiate();" > /docker-entrypoint-initdb.d/replica-init.js
CMD [ "--replSet", "myrepl" ] |
This will work only for a standalone node started as a ReplicaSet. |
@MaBeuLux88 that's basically all I needed for now (or to be correct, then, since I don't even work in the company anymore). @yosifkit can you elaborate on what's going on in the |
So yes, you will need something more complex for the other nodes. But no, my hurried Dockerfile will not actually work since the @gioragutt, There is an entrypoint script that checks the args for a flag (like When you do this (or the CMD from my Dockerfile above): $ docker run -d --name mongo mongo:3.6 --replSet myrepl What really is being run is the entrypoint script with the $ docker-entrypoint.sh --replSet myrepl
$ # which, after initialization, eventually ends with exec so that the bash process executing the shell script is replaced by mongod
$ # ie pid 1 of the contianer becomes mongod
$ exec mongod --replSet myrepl |
Docs on using a config file or flags added in docker-library/docs#1127. Adding automation for setting up a replica set is not something we want to add to the image since it requires an external service like This blog seems useful on setting up a replset (with Edit: this one seems pretty simple: https://medium.com/lucjuggery/mongodb-replica-set-on-swarm-mode-45d66bc9245 |
This should be in documentation. A lot of devs will start mongo in docker and change streams (that requires replica set) is feature by it self, without multiple nodes. |
@Lewik, as I mention later:
If I remember correctly, this would make the node inaccessible from other containers and only work from the Docker host with an exposed port on 27017 ( |
As I said:
Ability to listen database changes is feature. Even for one node. Developers will need only one node with change streams. In production we should setup multiple nodes, of course, But when we develop - one node is enough. And for small projects one db is enough even in prod. |
I've tried to set setup replica set to enable change stream for mogodb:3.6 but still not succeeded: |
FYI, the When scripts under
See #339 |
Replica set can be initialized on container startup.
replica.js:
|
The main problem with that is that it leaves `mongod` listening for
external connections for a short while before it's actually ready, then
shuts it down and starts it back up again (which can be quite disruptive
for external applications, especially those waiting for mongo to be ready).
|
External applications can check another indication about mongod readiness. |
i end up with this one https://gist.github.com/crapthings/71fb6156a8e9b31a2fa7946ebd7c4edc |
Wow, that's the real and proper solution right there. Great job! |
The only reason I'm here is that I want to use change streams in MongoDB locally (which requires using a replicaset). I don't want to run multiple replicas. Is there no way of doing this with a single docker image/container? |
@bergkvist Yes of course. Use a single RS. This should do the job no problemo. #!/usr/bin/env bash
docker run --rm -d -p 27017:27017 --name mongo mongo:4.2.3 --replSet=test
sleep 5
docker exec -it mongo mongo --quiet --eval "rs.initiate()"
docker exec -it mongo mongo --quiet |
@MaBeuLux88 How could I make this work with |
@bergkvist I just made this for you. Let me know if this works: https://github.com/MaBeuLux88/docker/tree/master/mongo-single-node-rs |
|
Do you happen to know why if I run it as a Dockerfile (and then try to reconnect to the container) everything is fine and the prompt says (in my case)
Is there a workaround to fix this and set the node as primary also when using docker-compose? |
I'd recommend running |
I did it and I get |
Here is a little wait-for-it pattern written if python is already installed on your test container and you don't want to install mongo straight in that container. May be useful for some. # Docker compose file for testing
version: "3.4"
services:
mongo:
image: mongo:4.2
container_name: mongo
network_mode: host
ports:
- 27017:27017
restart: always
command: --replSet replicaset
my_container:
image: my_image
container_name: my_container
network_mode: host
depends_on:
- mongo
command: python wait-for-mongo.py pytest -s #!/usr/local/bin/python
"""
Ping MongoDB endpoint until ready, then initialise replicaset, and run any
extra args as a subprocess.
"""
import subprocess
from pymongo import MongoClient
from pymongo.errors import OperationFailure, ServerSelectionTimeoutError
import sys
import time
MONGO_URI = "localhost:27017"
PING_RATE = 1
ATTEMPTS = 30
for _ in range(ATTEMPTS):
print("Attempting connection to {}...".format(MONGO_URI))
client = MongoClient(MONGO_URI, serverSelectionTimeoutMS=PING_RATE*1000)
try:
client.server_info()
except ServerSelectionTimeoutError:
continue
print("Connected!")
break
else:
print("Failed to connect after {} attempts".format(ATTEMPTS))
sys.exit(1)
print("Initialising replicaset...")
try:
client.admin.command("replSetInitiate")
except OperationFailure as e:
if "already initialized" in str(e):
pass
else:
print("OperationFailure: {}".format(e))
sys.exit(1)
print("Initialised!")
if "wait-for-mongo.py" in sys.argv[0]:
command = sys.argv[1:]
else:
command = sys.argv
if command:
print("Running command: {}".format(" ".join(command)))
process = subprocess.Popen(
command,
stdout=subprocess.PIPE,
universal_newlines=True,
)
while True:
output = process.stdout.readline().strip()
if output:
print(output)
return_code = process.poll()
if return_code is not None:
sys.exit(return_code) |
Here's another (probably cleaner than above) solution using a wait-for-it pattern. Idea is to mount the volume with # Docker compose file for testing
version: "3.4"
services:
mongo:
image: mongo:4.2
container_name: mongo
network_mode: host
ports:
- 27017:27017
restart: always
volumes:
- mongo-bin:/usr/bin
command: --replSet replicaset
my_container:
image: my_image
container_name: my_container
network_mode: host
depends_on:
- mongo
volumes:
- mongo-bin:/mongo-bin:ro
command: ./wait-for-mongo.sh pytest -s
volumes:
mongo-bin: #!/bin/sh
>&2 echo "Waiting for Mongo..."
until [ "$(/mongo-bin/mongo --host localhost --port 27017 --eval "db.stats().ok" | grep -E 'session')" ]; do
>&2 echo "Attempting connection..."
sleep 1
done
>&2 echo "Connected!"
>&2 echo "Initialising replicaset..."
>&2 echo $(/mongo-bin/mongo --host localhost --port 27017 --eval "rs.initiate({ _id: 'replicaset', members: [{ _id: 0, host: 'localhost:27017' }] })")
cmd="$@"
>&2 echo "Running command \"$cmd\"..."
exec $cmd |
Hi @yosifkit Is the below code can work with mongo:3.4.20 FROM mongo:3.4.20 it is not initialised by default as compared to 3.6? |
|
This gives me what I want. docker run -it --rm mongo:4.0.20@sha256:dd4cbe24eb8233db92b871cc556b77efcc7f9e67bc9516579796d4d08818273e bash -c "set -m ; mongod --bind_ip_all --replSet rs0 & while ! 2> /dev/null > '/dev/tcp/0.0.0.0/27017'; do sleep 1; done ; mongo --eval 'rs.initiate()' ; fg 1" |
I've tried this every which way to no avail. I'm looking for a docker-compose that can setup my app with replica set with the following: 1 - initdb - create some database that my app will use with its initial user I had 1 and 2 working, but I noticed when calling createIndex, I had a huge backlog of long running commands with db.currentOp(true). Thanks for any guidance! |
Hi, I've opened a SO thread, but I guess I can ask it here as well.
I want to create an Image that would use
mongo:latest
, but would initializemongod
with--replSet
, so that I can later (in the custom Dockerfile) callrs.initiate()
in the mongo shell.Is there any way I can do that?
The text was updated successfully, but these errors were encountered: