Hello my mongo health check is failing
below is my docker-compose file
version: "2.4"
services:
production-api:
build: .
environment:
- MONGO_URI=mongodb://mongodb:27017/productiondb
volumes:
- .:/app
ports:
- "3000:3000"
depends_on:
- mongodb
# condition: service_healthy
mongodb:
image: mongo
ports:
- "27017:27017"
# healthcheck:
# test: echo 'db.runCommand("ping").ok' | mongo mongo:27017/productiondb --quiet 1
# interval: 10s
# timeout: 10s
# retries: 5
And is there any way to pass MONGO_URI to health check as a variable?
you're healthcheck should look like this:
test: echo 'db.runCommand("ping").ok' | mongo localhost:27017/productiondb --quiet
the hostname mongo doesn't exist inside the mongodb container unless you specify hostname: mongo in your compose file or just simply use localhost which is more common, when doing healthchecks
the 1 after --quiet seems to be a typo which leads to [main] file [1] doesn't exist https://docs.mongodb.com/manual/reference/program/mongo/#cmdoption-mongo-quiet
see also:
Simple HTTP/TCP health check for MongoDB
Why does the docker-compose healthcheck of my mongo container always fail?
You can pass MONGO_URI to the healthcheck, by specifying it a second time:
mongodb:
..
environment:
- MONGO_URI=mongodb://mongodb:27017/productiondb
If you want to use one value for both, create an env_file and use it via:
env_file:
- mongo.env # wich contains `MONGO_URI=mongodb://..`
Related
I have a MongoDb container which is using a single node replica set configured like following code. To run a replica set i need to execute another command on mongoDb shell which is rs.initiate() How to add that command into the container configuration command list so that i do not have to execute that command manually on MongoDb shell ?
mongodb:
image: mongo:5.0
container_name: mongodb
command: ["--replSet", "rs0", "--bind_ip_all"] # This works but i have to manually go into mongoshell to execute rs.initilize(), i dont want to do that
# command: ["--replSet", "rs0", "--bind_ip_all","mongo", "rs.initiate()"] # --> Does't work
# command: ["--replSet", "rs0", "--bind_ip_all","rs.initiate()"] # --> Does't work
# command: ["--replSet", "rs0", "--bind_ip_all", "mongo rs.initiate()"] # --> Does't work
networks:
- dev
ports:
- 27017:27017
volumes:
- ${HOME}/mongodb:/data/db
Ok, i am not sure if this is the correct way to solve that problem but, i got that working by using healthcheck feature of Docker. After this change, i do not have to execute rs.initiate() manually
For details please look at docker mongo for single (primary node only) replica set (for development)?
HealthCheck: https://docs.docker.com/engine/reference/builder/#healthcheck
mongodb:
image: mongo:5.0
container_name: mongodb
command: ["--replSet", "rs0", "--bind_ip_all"]
- dev
ports:
- 27017:27017
volumes:
- ${HOME}/mongodb:/data/db
healthcheck:
test: test $$(echo "rs.initiate().ok || rs.status().ok" | mongo -u root -p imagiaRoot --quiet) -eq 1
interval: 10s
start_period: 30s
This is the portion of the dockerfile that has served us well to date. However, now I need to convert this to be a single node replica set (for transactions to work). I don't want any secondary or arbiter - just the primary node. What am I missing to get this working?
mongo:
image: mongo:4.4.3
container_name: mongo
restart: unless-stopped
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: myPass
command: mongod --port 27017
ports:
- '27017:27017'
volumes:
- ./data/mongodb:/data/db
- ./data/mongodb/home:/home/mongodb/
- ./configs/mongodb/mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh:ro
Got it working. I inserted the following into the block in my question above:
hostname: mongodb
volumes:
- ./data/mongodb/data/log/:/var/log/mongodb/
# the healthcheck avoids the need to initiate the replica set
healthcheck:
test: test $$(echo "rs.initiate().ok || rs.status().ok" | mongo -u root -p imagiaRoot --quiet) -eq 1
interval: 10s
start_period: 30s
I was unable to initiate the replica set via the healthcheck. I used the bash script below instead. For Windows users, be sure to call your DB with the name of your computer. For example:
mongodb://DESKTOP-QPRKMN2:27017
run-test.sh
#!/bin/bash
echo "Running docker-compose"
docker-compose up -d
echo "Waiting for DB to initialize"
sleep 10
echo "Initiating DB"
docker exec mongo_container mongo --eval "rs.initiate();"
echo "Running tests"
# test result
if go test ./... -v
then
echo "Test PASSED"
else
echo "Test FAILED"
fi
# cleanup
docker-compose -f docker-compose.test.yml down
docker-compose file
version: '3.8'
services:
mongo:
hostname: $HOST
container_name: mongo_container
image: mongo:5.0.3
volumes:
- ./test-db.d
expose:
- 27017
ports:
- "27017:27017"
restart: always
command: ["--replSet", "test", "--bind_ip_all"]
This forum post was very helpful: https://www.mongodb.com/community/forums/t/docker-compose-replicasets-getaddrinfo-enotfound/14301/4
everyone. I have an odd problem (who hasn't?)
I have this docker-compose file:
version: '3.4'
services:
ludustack-web:
container_name: ludustack-web
image: ${DOCKER_REGISTRY-}ludustack-web
build:
context: .
dockerfile: LuduStack.Web/Dockerfile
networks:
- ludustack-network
ports:
- '80:80'
- '443:443'
depends_on:
- 'ludustack-db'
ludustack-db:
container_name: ludustack-db
command: mongod --auth
image: mongo:latest
hostname: mongodb
networks:
- ludustack-network
ports:
- '27017:27017'
env_file:
- .env
environment:
- MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
- MONGO_INITDB_DATABASE=${MONGO_INITDB_DATABASE}
- MONGO_REPLICA_SET_NAME=${MONGO_REPLICA_SET_NAME}
healthcheck:
test: test $$(echo "rs.initiate().ok || rs.status().ok" | mongo -u $${MONGO_INITDB_ROOT_USERNAME} -p $${MONGO_INITDB_ROOT_PASSWORD} --quiet) -eq 1
interval: 60s
start_period: 60s
command: ["--replSet", "${MONGO_REPLICA_SET_NAME}", "--bind_ip_all"]
networks:
ludustack-network:
driver: bridge
The problem is the web application only waits for the mongodb container to be ready, not the replica set itself. So, when the application starts, it crashes because the replicaset is not ready yet. Right after the crash, it logs the replicaset continuing its job:
Any tips on how to make the web application wait the replicaset to be ready?
The application did wait, for 30 seconds. You can increase the timeout by adjusting serverSelectionTimeoutMS URI option or through language-specific means.
I want to create a Docker container with an instance of Mongo. In particular, I would like to create a replica set with only one node (since I'm interested in transactions and they are only available for replica sets).
Dockerfile
FROM mongo
RUN echo "rs.initiate();" > /docker-entrypoint-initdb.d/replica-init.js
CMD ["--replSet", "rs0"]
docker-compose.yml
version: "3"
services:
db:
build:
dockerfile: Dockerfile
context: .
ports:
- "27017:27017"
If I use the Dockerfile alone everything is fine, while if I use docker-compose it does not work: in fact if I then log to the container I got prompted as rs0:OTHER> instead of rs0:PRIMARY>.
I consulted these links but the solutions proposed are not working:
https://github.com/docker-library/mongo/issues/246#issuecomment-382072843
https://github.com/docker-library/mongo/issues/249#issuecomment-381786889
This is the compose file I have used for a while now for local development. You can remove the keyfile pieces if you don't need to connect via SSL.
version: "3.8"
services:
mongodb:
image : mongo:4
container_name: mongodb
hostname: mongodb
restart: on-failure
environment:
- PUID=1000
- PGID=1000
- MONGO_INITDB_ROOT_USERNAME=mongo
- MONGO_INITDB_ROOT_PASSWORD=mongo
- MONGO_INITDB_DATABASE=my-service
- MONGO_REPLICA_SET_NAME=rs0
volumes:
- mongodb4_data:/data/db
- ./:/opt/keyfile/
ports:
- 27017:27017
healthcheck:
test: test $$(echo "rs.initiate().ok || rs.status().ok" | mongo -u $${MONGO_INITDB_ROOT_USERNAME} -p $${MONGO_INITDB_ROOT_PASSWORD} --quiet) -eq 1
interval: 10s
start_period: 30s
command: "--bind_ip_all --keyFile /opt/keyfile/keyfile --replSet rs0"
volumes:
mongodb4_data:
It uses Docker's health check (with a startup delay) to sneak in the rs.initiate() if it actually needs it after it's already running.
To create a keyfile.
Mac:
openssl rand -base64 741 > keyfile
chmod 600 keyfile
Linux:
openssl rand -base64 756 > keyfile
chmod 600 keyfile
sudo chown 999 keyfile
sudo chgrp 999 keyfile
The top answer stopped working for me in later MongoDB and Docker versions. Particularly because rs.initiate().ok would throw an error if the replica set was already initiated, causing the whole command to fail. In addition, connecting from another container was failing because the replica set's sole member had some random host, which wouldn't allow the connection. Here's my new docker-compose.yml:
services:
web:
# ...
environment:
DATABASE_URL: mongodb://root:root#db/?authSource=admin&tls=false
db:
build:
context: ./mongo/
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: root
ports:
- '27017:27017'
volumes:
- data:/data/db
healthcheck:
test: |
test $$(mongosh --quiet -u root -p root --eval "try { rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: 'db' }] }).ok } catch (_) { rs.status().ok }") -eq 1
interval: 10s
start_period: 30s
volumes:
data:
Inside ./mongo/, I have a custom Dockerfile that looks like:
FROM mongo:6
RUN echo "password" > /keyfile \
&& chmod 600 /keyfile \
&& chown 999 /keyfile \
&& chgrp 999 /keyfile
CMD ["--bind_ip_all", "--keyFile", "/keyfile", "--replSet", "rs0"]
This Dockerfile is suitable for development, but you'd definitely want a securely generated and persistent keyfile to be mounted in production (and therefore strike the entire RUN command).
You still need to issue replSetInitiate even if there's only one node in the RS.
See also here.
I had to do something similar to build tests around ChangeStreams which are only available when running mongo as a replica set. I don't remember where I pulled this from, so I can't explain it in detail but it does work for me. Here is my setup:
Dockerfile
FROM mongo:5.0.3
RUN echo "rs.initiate({'_id':'rs0', members: [{'_id':1, 'host':'127.0.0.1:27017'}]});" > "/docker-entrypoint-initdb.d/init_replicaset.js"
RUN echo "12345678" > "/tmp/key.file"
RUN chmod 600 /tmp/key.file
RUN chown 999:999 /tmp/key.file
CMD ["mongod", "--replSet", "rs0", "--bind_ip_all", "--keyFile", "/tmp/key.file"]
docker-compose.yml
version: '3.7'
services:
mongo:
build: .
restart: always
ports:
- 27017:27017
healthcheck:
test: test $$(echo "rs.initiate().ok || rs.status().ok" | mongo -u admin -p pass --quiet) -eq 1
interval: 10s
start_period: 30s
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: pass
MONGO_INITDB_DATABASE: test
Run docker-compose up and you should be good.
Connection String: mongodb://admin:pass#localhost:27017/test
Note: You shouldn't use this in production obviously, adjust the key "12345678" in the Dockerfile if security is a concern.
If you just need single node replica set of MongoDB via docker-compose.yml you can simply use this:
mongodb:
image: mongo:5
restart: always
command: ["--replSet", "rs0", "--bind_ip_all"]
ports:
- 27018:27017
healthcheck:
test: mongo --eval "rs.initiate()"
start_period: 5s
This one works fine for me:
version: '3.4'
services:
ludustack-db:
container_name: ludustack-db
command: mongod --auth
image: mongo:latest
hostname: mongodb
ports:
- '27017:27017'
env_file:
- .env
environment:
- MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
- MONGO_INITDB_DATABASE=${MONGO_INITDB_DATABASE}
- MONGO_REPLICA_SET_NAME=${MONGO_REPLICA_SET_NAME}
healthcheck:
test: test $$(echo "rs.initiate().ok || rs.status().ok" | mongo -u $${MONGO_INITDB_ROOT_USERNAME} -p $${MONGO_INITDB_ROOT_PASSWORD} --quiet) -eq 1
interval: 60s
start_period: 60s
Hi I have an application where I am using docker-compose. I have large amount of data in the remote mongo DB server which is running on port 28107. How can I connect from my docker-compose to this remote server?
Below is my docker-compose.yml file:
version: '3'
services:
myapp:
# container_name: myapp
restart: always
build: .
ports:
- '52000:52000'
# - '8080:8080'
# - '4300:4300'
# - '4301:4301'
environment:
- MONGO_URL=mongodb://test:test#ip_address:28107/test
# command: ["./wait-for-it.sh", "mongo:28107", "--", "npm", "start"]
links:
- redis
- mongo
mongo:
# container_name: myapp-mongo
image: 'mongo:latest'
ports:
- '28107:28107'
# - '27017:27017'
volumes:
# - ~/Downloads/db_dump_09_01_2020:/data/db
- /data/db
# - /data/configdb
# command: mongod --auth
redis:
# container_name: myapp-redis
restart: always
image: 'redis:4.0.11'
# command: ["redis-server", "--appendonly", "yes"]
depends_on:
- helper
sysctls:
- net.core.somaxconn=511
ports:
- '6379:6379'
helper:
image: alpine
command: sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled"
privileged: true
In the above code, in the environment parameter, I have mentioned the remote mongo DB server url. I have all the data in that url. I don't want to export that data in my localhost and mount it in my docker container but instead, I would like to directly link my docker container to that remote mongo DB server.
How can I do it ? I am new to the docker concepts.
Seems like you are trying to connect to an external MongoDb server on a network different from your docker network. Then you shouldn't need.
mongo:
# container_name: myapp-mongo
image: 'mongo:latest'
ports:
- '28107:28107'
# - '27017:27017'
volumes:
# - ~/Downloads/db_dump_09_01_2020:/data/db
- /data/db
# - /data/configdb
# command: mongod --auth
You should only need to provide the necessary environment settings of the remote MongoDb server to myapp.