2

I made 3 docker containers from 2 images in this repo and 1 using MongoDB public image. I turned ON all three containers using sudo docker-compose -f docker-compose.yaml up

docker-compose.yaml is:

version: '3'
services:
  frontend:
    image: samar080301/mern-frontend:1.0
    ports:
      - 3000:3000
  backend:  
    image: samar080301/mern-backend:1.0
    ports:
      - 5000:5000
  mongodb:
    image: mongo:latest
    ports:
      - 27017:27017

But the MongoDB couldn't connect with the node server and gave this error:

backend_1   | > crud-app@1.0.0 start /home/app
backend_1   | > node server.js
backend_1   | 
backend_1   | (node:18) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
backend_1   | (Use `node --trace-deprecation ...` to show where the warning was created)
backend_1   | App running on port 5000
backend_1   | Error with the database! MongoNetworkError: failed to connect to server [localhost:27017] on first connect [Error: connect ECONNREFUSED 127.0.0.1:27017
backend_1   |     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16) {
backend_1   |   name: 'MongoNetworkError'
backend_1   | }]
backend_1   |     at Pool.<anonymous> (/home/app/node_modules/mongodb/lib/core/topologies/server.js:438:11)
backend_1   |     at Pool.emit (events.js:315:20)
backend_1   |     at /home/app/node_modules/mongodb/lib/core/connection/pool.js:562:14
backend_1   |     at /home/app/node_modules/mongodb/lib/core/connection/pool.js:995:11
backend_1   |     at /home/app/node_modules/mongodb/lib/core/connection/connect.js:32:7
backend_1   |     at callback (/home/app/node_modules/mongodb/lib/core/connection/connect.js:280:5)
backend_1   |     at Socket.<anonymous> (/home/app/node_modules/mongodb/lib/core/connection/connect.js:310:7)
backend_1   |     at Object.onceWrapper (events.js:422:26)
backend_1   |     at Socket.emit (events.js:315:20)
backend_1   |     at emitErrorNT (internal/streams/destroy.js:84:8)
backend_1   |     at processTicksAndRejections (internal/process/task_queues.js:84:21)
backend_1   | (node:18) UnhandledPromiseRejectionWarning: MongoNetworkError: failed to connect to server [localhost:27017] on first connect [Error: connect ECONNREFUSED 127.0.0.1:27017
backend_1   |     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16) {
backend_1   |   name: 'MongoNetworkError'
backend_1   | }]

Code of backend/db.js:

const mongoose = require('mongoose');
// Allow Promises
mongoose.Promise = global.Promise;
// Connection
mongoose.connect('mongodb://localhost:27017/db_test', { useNewUrlParser: true });
// Validation
mongoose.connection
  .once('open', () => console.log('Connected to the database!'))
  .on('error', err => console.log('Error with the database!', err));

Terminal Output of docker inspect mongodb: enter image description here

Terminal output after adding the mongo uri as environment variable:

backend_1   | App running on port 5000
backend_1   | (node:19) UnhandledPromiseRejectionWarning: MongooseError: The `uri` parameter to `openUri()` must be a string, got "undefined". Make sure the first parameter to `mongoose.connect()` or `mongoose.createConnection()` is a string.
backend_1   | (node:19) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)

New error:

backend_1   | Error with the database! MongoNetworkError: failed to connect to server [merncrudapp_mongodb_1:27017] on first connect [Error: connect ECONNREFUSED 172.23.0.3:27017
backend_1   |     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16) {
backend_1   |   name: 'MongoNetworkError'
backend_1   | }]
Samar Pratap Singh
  • 471
  • 1
  • 10
  • 29
  • Please include logs from mongodb container too. The error says it is not started at the time backend connects to it. It could be just a race condition, as mongo requires some time to spin up and start listening on the port. – Alex Blex Feb 21 '22 at 11:52

3 Answers3

5

When you run docker-compose up, the following happens:

  1. A network called MernCrudApp(takes the default name of the directory) is created.
  2. A container is created using the frontend's configuration. It joins the network MernCrudApp under the name frontend.
  3. A container is created using the backend's configuration. It joins the network MernCrudApp under the name backend.
  4. A container is created using mongodb’s configuration. It joins the network MernCrudApp under the name mongodb.

now if you use mongodb://localhost:27017/db_test to connect to the db, the node app will look for MongoDB in the backend container which you will get a connection error since it does not exist.

To remedy this, change the MongoDB connection string to mongodb://mongodb:27017/db_test so that it

Aditional comments
I would recommend the following to help solve some problems you might face in the future using the current configuration.

  1. Add the connection string as an environment variable. This will make it easier for you to change the DB instances without rebuilding the container.
  2. Since the backend application depends on the database add depend_on on the docker-compose files so that the MongoDB container starts before the backend container
Stephen Ng'etich
  • 628
  • 7
  • 12
  • how can i add the connection string as env variable? Please tell me, actually I have just started learning docker – Samar Pratap Singh Feb 20 '22 at 17:43
  • 1
    Let say `MONGO_URI` is the environment variable for MongoDB. Add a line in the docker file `ENV MONGO_URI=mongodb://localhost:27017/db_test`. once you build it you can change it on the docker-compose files. Find more info on this [post](https://stackoverflow.com/questions/39597925/how-do-i-set-environment-variables-during-the-build-in-docker) – Stephen Ng'etich Feb 20 '22 at 19:11
  • How can I pass that uri to my javascript connector code? – Samar Pratap Singh Feb 21 '22 at 09:56
  • 1
    example `const mongo_uri = process.env.MONGO_URI` and then pass the variable when using the mongodb connect function `mongoose.connect(mongo_uri , { useNewUrlParser: true });` – Stephen Ng'etich Feb 21 '22 at 10:17
  • I did it, you can check the updated code in Github and I have also updated the new error – Samar Pratap Singh Feb 21 '22 at 16:00
3

Try to connect not using localhost but a container name. So for example, if you want to connect to MongoDB from another container (in the same docker network) you can use mongodb:27017. It should work.

1

Modify your backend/db.js code.

Your are getting error because when you mention 'localhost' in code your container is trying to connect to backend container on port 2017 which not in use.

// Connection
//mongodb is a container name of mongo image
mongoose.connect('mongodb://mongodb:27017/db_test', { useNewUrlParser: true });

Pro Tip - 1)If you are in same docker network then use hostname or Docker Container Name to communicate/Link with each other.

2)Never use container IP address in code if IP's are not assign manually. Whenever you restart container it may change.

  • i tried both `mongodb://merncrudapp_mongodb_1:27017/db_test` and `mongodb://mongodb:27017/db_test`. But they both gave me error which i have added in the question as new error – Samar Pratap Singh Feb 22 '22 at 05:26
  • Is your mongodb container running ? to check this use below command from your server. Command - telnet localhost 27017 if you are not able to telnet 27017 port then it means Mongodb container is not running. – Vishal Ghadage Mar 01 '22 at 07:14