Reputation: 3998
This is my first post in node js and docker so bear with me. I am running a mongo and mongo express container with the docker-compose but mongo express is not running. When I run mongo and mongo express without docker-compose it works perfectly. So, I think I am having some issues in docker-compose or maybe node js code
docker-compose.yaml
version: '3'
services:
mongodb:
image: mongo
ports:
- 27017:27017
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
mongo-express:
image: mongo-express
ports:
- 8080:8081
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME=admin
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
- ME_CONFIG_MONGODB_SERVER=mongodb
server.js
let express = require('express');
let path = require('path');
let fs = require('fs');
let MongoClient = require('mongodb').MongoClient;
let bodyParser = require('body-parser');
let app = express();
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, "index.html"));
});
app.get('/profile-picture', function (req, res) {
let img = fs.readFileSync(path.join(__dirname, "images/profile-1.jpg"));
res.writeHead(200, {'Content-Type': 'image/jpg' });
res.end(img, 'binary');
});
// use when starting application locally
let mongoUrlLocal = "mongodb://admin:password@localhost:27017";
// use when starting application as docker container
let mongoUrlDocker = "mongodb://admin:password@mongodb";
// pass these options to mongo client connect request to avoid DeprecationWarning for current Server Discovery and Monitoring engine
let mongoClientOptions = { useNewUrlParser: true, useUnifiedTopology: true };
// "user-account" in demo with docker. "my-db" in demo with docker-compose
let databaseName = "my-db";
app.post('/update-profile', function (req, res) {
let userObj = req.body;
MongoClient.connect(mongoUrlLocal, mongoClientOptions, function (err, client) {
if (err) throw err;
let db = client.db(databaseName);
userObj['userid'] = 1;
let myquery = { userid: 1 };
let newvalues = { $set: userObj };
db.collection("users").updateOne(myquery, newvalues, {upsert: true}, function(err, res) {
if (err) throw err;
client.close();
});
});
// Send response
res.send(userObj);
});
app.get('/get-profile', function (req, res) {
let response = {};
// Connect to the db
MongoClient.connect(mongoUrlLocal, mongoClientOptions, function (err, client) {
if (err) throw err;
let db = client.db(databaseName);
let myquery = { userid: 1 };
db.collection("users").findOne(myquery, function (err, result) {
if (err) throw err;
response = result;
client.close();
// Send response
res.send(response ? response : {});
});
});
});
app.listen(3000, function () {
console.log("app listening on port 3000!");
});
If I run docker ps I can only see mongo is running
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d20c4784d316 mongo "docker-entrypoint.s…" 43 seconds ago Up 38 seconds 0.0.0.0:27017->27017/tcp, :::27017->27017/tcp nodeapplications_mongodb_1
And when I run my docker-compose with the below command I see this log where I suspect an issue. Any help is appreciated
docker-compose -f docker-compose.yaml up
Logs
mongo-express_1 | Welcome to mongo-express
mongo-express_1 | ------------------------
mongo-express_1 |
mongo-express_1 |
mongo-express_1 | (node:7) [MONGODB DRIVER] Warning: 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.
mongo-express_1 | Could not connect to database using connectionString: mongodb://admin:password@mongodb:27017/"
mongo-express_1 | (node:7) UnhandledPromiseRejectionWarning: MongoNetworkError: failed to connect to server [mongodb:27017] on first connect [Error: connect ECONNREFUSED 172.19.0.3:27017
mongo-express_1 | at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1144:16) {
mongo-express_1 | name: 'MongoNetworkError'
mongo-express_1 | }]
mongo-express_1 | at Pool.<anonymous> (/node_modules/mongodb/lib/core/topologies/server.js:438:11)
mongo-express_1 | at Pool.emit (events.js:314:20)
mongo-express_1 | at /node_modules/mongodb/lib/core/connection/pool.js:562:14
mongo-express_1 | at /node_modules/mongodb/lib/core/connection/pool.js:995:11
mongo-express_1 | at /node_modules/mongodb/lib/core/connection/connect.js:32:7
mongo-express_1 | at callback (/node_modules/mongodb/lib/core/connection/connect.js:280:5)
mongo-express_1 | at Socket.<anonymous> (/node_modules/mongodb/lib/core/connection/connect.js:310:7)
mongo-express_1 | at Object.onceWrapper (events.js:421:26)
mongo-express_1 | at Socket.emit (events.js:314:20)
mongo-express_1 | at emitErrorNT (internal/streams/destroy.js:92:8)
mongo-express_1 | at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
mongo-express_1 | at processTicksAndRejections (internal/process/task_queues.js:84:21)
mongo-express_1 | (node:7) 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)
As suggested by @Blunderchips Update 1
server.js
let express = require('express');
let path = require('path');
let fs = require('fs');
let MongoClient = require('mongodb').MongoClient;
let bodyParser = require('body-parser');
let app = express();
const dbServer = process.env.ME_CONFIG_MONGODB_SERVER;
const dbPassword = process.env.ME_CONFIG_MONGODB_ADMINPASSWORD;
const dbUserName = process.env.ME_CONFIG_MONGODB_ADMINUSERNAME;
const dbPort = process.env.ME_CONFIG_MONGODB_PORT;
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, "index.html"));
});
app.get('/profile-picture', function (req, res) {
let img = fs.readFileSync(path.join(__dirname, "images/profile-1.jpg"));
res.writeHead(200, {'Content-Type': 'image/jpg' });
res.end(img, 'binary');
});
// use when starting application locally
//let mongoUrlLocal = "mongodb://admin:password@localhost:27017";
// use when starting application as docker container
let mongoUrlDocker = `mongodb://${dbUserName}:${dbPassword}@${dbServer}:${dbPort}`;//"mongodb://admin:password@mongodb:27017";//"mongodb://admin:password@mongodb";
// pass these options to mongo client connect request to avoid DeprecationWarning for current Server Discovery and Monitoring engine
let mongoClientOptions = { useNewUrlParser: true, useUnifiedTopology: true };
// "user-account" in demo with docker. "my-db" in demo with docker-compose
let databaseName = "my-db";
app.post('/update-profile', function (req, res) {
let userObj = req.body;
MongoClient.connect(mongoUrlDocker, mongoClientOptions, function (err, client) {
if (err) throw err;
let db = client.db(databaseName);
userObj['userid'] = 1;
let myquery = { userid: 1 };
let newvalues = { $set: userObj };
db.collection("users").updateOne(myquery, newvalues, {upsert: true}, function(err, res) {
if (err) throw err;
client.close();
});
});
// Send response
res.send(userObj);
});
app.get('/get-profile', function (req, res) {
let response = {};
// Connect to the db
MongoClient.connect(mongoUrlDocker, mongoClientOptions, function (err, client) {
if (err) throw err;
let db = client.db(databaseName);
let myquery = { userid: 1 };
db.collection("users").findOne(myquery, function (err, result) {
if (err) throw err;
response = result;
client.close();
// Send response
res.send(response ? response : {});
});
});
});
app.listen(3000, function () {
console.log("app listening on port 3000!");
});
docker-compose.yaml
version: '3'
services:
mongodb:
image: mongo
ports:
- 27017:27017
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
mongo-express:
image: mongo-express
ports:
- 8080:8081
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME=admin
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
- ME_CONFIG_MONGODB_SERVER=mongodb
links:
- mongodb:mongodb
I still can't see mongo express running
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
23428dc0c3a1 mongo "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:27017->27017/tcp, :::27017->27017/tcp nodeapplications_mongodb_1
Logs
mongo-express_1 | Welcome to mongo-express
mongo-express_1 | ------------------------
mongo-express_1 |
mongo-express_1 |
mongo-express_1 | (node:7) [MONGODB DRIVER] Warning: 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.
mongo-express_1 | Could not connect to database using connectionString: mongodb://admin:password@mongodb:27017/"
mongo-express_1 | (node:7) UnhandledPromiseRejectionWarning: MongoNetworkError: failed to connect to server [mongodb:27017] on first connect [Error: connect ECONNREFUSED 172.23.0.2:27017
mongo-express_1 | at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1144:16) {
mongo-express_1 | name: 'MongoNetworkError'
mongo-express_1 | }]
mongo-express_1 | at Pool.<anonymous> (/node_modules/mongodb/lib/core/topologies/server.js:438:11)
mongo-express_1 | at Pool.emit (events.js:314:20)
mongo-express_1 | at /node_modules/mongodb/lib/core/connection/pool.js:562:14
mongo-express_1 | at /node_modules/mongodb/lib/core/connection/pool.js:995:11
mongo-express_1 | at /node_modules/mongodb/lib/core/connection/connect.js:32:7
mongo-express_1 | at callback (/node_modules/mongodb/lib/core/connection/connect.js:280:5)
mongo-express_1 | at Socket.<anonymous> (/node_modules/mongodb/lib/core/connection/connect.js:310:7)
mongo-express_1 | at Object.onceWrapper (events.js:421:26)
mongo-express_1 | at Socket.emit (events.js:314:20)
mongo-express_1 | at emitErrorNT (internal/streams/destroy.js:92:8)
mongo-express_1 | at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
mongo-express_1 | at processTicksAndRejections (internal/process/task_queues.js:84:21)
mongo-express_1 | (node:7) 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)
mongo-express_1 | (node:7) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Update 2
let express = require('express');
let path = require('path');
let fs = require('fs');
let MongoClient = require('mongodb').MongoClient;
let bodyParser = require('body-parser');
let app = express();
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, "index.html"));
});
app.get('/profile-picture', function (req, res) {
let img = fs.readFileSync(path.join(__dirname, "images/profile-1.jpg"));
res.writeHead(200, {'Content-Type': 'image/jpg' });
res.end(img, 'binary');
});
// use when starting application locally
//let mongoUrlLocal = "mongodb://admin:password@localhost:27017";
// use when starting application as docker container
let mongoUrlDocker = "mongodb://admin:password@mongodb:27017";
// pass these options to mongo client connect request to avoid DeprecationWarning for current Server Discovery and Monitoring engine
let mongoClientOptions = { useNewUrlParser: true, useUnifiedTopology: true };
// "user-account" in demo with docker. "my-db" in demo with docker-compose
let databaseName = "my-db";
app.post('/update-profile', function (req, res) {
let userObj = req.body;
MongoClient.connect(mongoUrlDocker, mongoClientOptions, function (err, client) {
if (err) throw err;
let db = client.db(databaseName);
userObj['userid'] = 1;
let myquery = { userid: 1 };
let newvalues = { $set: userObj };
db.collection("users").updateOne(myquery, newvalues, {upsert: true}, function(err, res) {
if (err) throw err;
client.close();
});
});
// Send response
res.send(userObj);
});
app.get('/get-profile', function (req, res) {
let response = {};
// Connect to the db
MongoClient.connect(mongoUrlDocker, mongoClientOptions, function (err, client) {
if (err) throw err;
let db = client.db(databaseName);
let myquery = { userid: 1 };
db.collection("users").findOne(myquery, function (err, result) {
if (err) throw err;
response = result;
client.close();
// Send response
res.send(response ? response : {});
});
});
});
app.listen(3000, function () {
console.log("app listening on port 3000!");
});
Update 3
docker-compose
version: '3'
services:
mongodb:
image: mongo
ports:
- 27017:27017
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
mongo-express:
image: mongo-express
ports:
- 8080:8081
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME=admin
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
- ME_CONFIG_MONGODB_SERVER=mongodb
links:
- mongodb:mongodb
restart: on-failure
Full Logs
mongo-express_1 | Welcome to mongo-express
mongo-express_1 | ------------------------
mongo-express_1 |
mongo-express_1 |
mongodb_1 | {"t":{"$date":"2021-07-04T10:41:58.806+00:00"},"s":"I", "c":"STORAGE", "id":22318, "ctx":"SignalHandler","msg":"Shutting down session sweeper thread"}
mongodb_1 | {"t":{"$date":"2021-07-04T10:41:58.806+00:00"},"s":"I", "c":"STORAGE", "id":22319, "ctx":"SignalHandler","msg":"Finished shutting down session sweeper thread"}
mongodb_1 | {"t":{"$date":"2021-07-04T10:41:58.807+00:00"},"s":"I", "c":"STORAGE", "id":22322, "ctx":"SignalHandler","msg":"Shutting down checkpoint thread"}
mongodb_1 | {"t":{"$date":"2021-07-04T10:41:58.807+00:00"},"s":"I", "c":"STORAGE", "id":22323, "ctx":"SignalHandler","msg":"Finished shutting down checkpoint thread"}
mongodb_1 | {"t":{"$date":"2021-07-04T10:41:58.807+00:00"},"s":"I", "c":"STORAGE", "id":4795902, "ctx":"SignalHandler","msg":"Closing WiredTiger","attr":{"closeConfig":"leak_memory=true,"}}
mongodb_1 | {"t":{"$date":"2021-07-04T10:41:58.810+00:00"},"s":"I", "c":"STORAGE", "id":22430, "ctx":"SignalHandler","msg":"WiredTiger message","attr":{"message":"[1625395318:810568][28:0x7f50eec9b700], close_ckpt: [WT_VERB_CHECKPOINT_PROGRESS] saving checkpoint snapshot min: 48, snapshot max: 48 snapshot count: 0, oldest timestamp: (0, 0) , meta checkpoint timestamp: (0, 0)"}}
mongo-express_1 | (node:7) [MONGODB DRIVER] Warning: 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.
mongo-express_1 | Could not connect to database using connectionString: mongodb://admin:password@mongodb:27017/"
mongo-express_1 | (node:7) UnhandledPromiseRejectionWarning: MongoNetworkError: failed to connect to server [mongodb:27017] on first connect [Error: connect ECONNREFUSED 172.27.0.2:27017
mongo-express_1 | at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1144:16) {
mongo-express_1 | name: 'MongoNetworkError'
mongo-express_1 | }]
mongo-express_1 | at Pool.<anonymous> (/node_modules/mongodb/lib/core/topologies/server.js:438:11)
mongo-express_1 | at Pool.emit (events.js:314:20)
mongo-express_1 | at /node_modules/mongodb/lib/core/connection/pool.js:562:14
mongo-express_1 | at /node_modules/mongodb/lib/core/connection/pool.js:995:11
mongo-express_1 | at /node_modules/mongodb/lib/core/connection/connect.js:32:7
mongo-express_1 | at callback (/node_modules/mongodb/lib/core/connection/connect.js:280:5)
mongo-express_1 | at Socket.<anonymous> (/node_modules/mongodb/lib/core/connection/connect.js:310:7)
mongo-express_1 | at Object.onceWrapper (events.js:421:26)
mongo-express_1 | at Socket.emit (events.js:314:20)
mongo-express_1 | at emitErrorNT (internal/streams/destroy.js:92:8)
mongo-express_1 | at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
mongo-express_1 | at processTicksAndRejections (internal/process/task_queues.js:84:21)
mongo-express_1 | (node:7) 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)
mongo-express_1 | (node:7) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
mongodb_1 | {"t":{"$date":"2021-07-04T10:42:00.871+00:00"},"s":"I", "c":"STORAGE", "id":4795901, "ctx":"SignalHandler","msg":"WiredTiger closed","attr":{"durationMillis":2064}}
mongodb_1 | {"t":{"$date":"2021-07-04T10:42:00.871+00:00"},"s":"I", "c":"STORAGE", "id":22279, "ctx":"SignalHandler","msg":"shutdown: removing fs lock..."}
mongodb_1 | {"t":{"$date":"2021-07-04T10:42:00.872+00:00"},"s":"I", "c":"-", "id":4784931, "ctx":"SignalHandler","msg":"Dropping the scope cache for shutdown"}
mongodb_1 | {"t":{"$date":"2021-07-04T10:42:00.873+00:00"},"s":"I", "c":"FTDC", "id":4784926, "ctx":"SignalHandler","msg":"Shutting down full-time data capture"}
mongodb_1 | {"t":{"$date":"2021-07-04T10:42:00.873+00:00"},"s":"I", "c":"FTDC", "id":20626, "ctx":"SignalHandler","msg":"Shutting down full-time diagnostic data capture"}
mongodb_1 | {"t":{"$date":"2021-07-04T10:42:00.878+00:00"},"s":"I", "c":"CONTROL", "id":20565, "ctx":"SignalHandler","msg":"Now exiting"}
mongodb_1 | {"t":{"$date":"2021-07-04T10:42:00.879+00:00"},"s":"I", "c":"CONTROL", "id":23138, "ctx":"SignalHandler","msg":"Shutting down","attr":{"exitCode":0}}
nodeapplications_mongo-express_1 exited with code 0
mongodb_1 |
mongodb_1 | MongoDB init process complete; ready for start up.
Upvotes: 9
Views: 12216
Reputation: 7527
Adding restart: unless-stopped
works, but that seems not the root cause, after read this - https://docs.docker.com/compose/startup-order/, I think the issue is that mongo-express is depends on the mongo service, so ideally it should start after mongo is running, but seems there is no elegant solution for this issue, the depends_on
option will help to reduce the problem but it can't solve it totally.
Check the limitation (or design) of depends_on
option, https://docs.docker.com/compose/compose-file/compose-file-v3/#depends_on
Quote
depends_on does not wait for db and redis to be “ready” before starting web - only until they have been started. If you need to wait for a service to be ready, see Controlling startup order for more on this problem and strategies for solving it.
My final yaml file,
version: '3'
services:
mongodb:
image: mongo
ports:
- 27017:27017
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
mongo-express:
image: mongo-express
ports:
- 8080:8081
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME=admin
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
- ME_CONFIG_MONGODB_SERVER=mongodb
depends_on:
- "mongodb"
restart: unless-stopped
Updates on 2023-06-23:
The solution for detecting the ready state of a service is to use the condition attribute with one of the following options
check: https://docs.docker.com/compose/startup-order/#control-startup
Upvotes: 2
Reputation: 93
Well, the issue here is clearly that mongo-express did start while mongo was not ready yet, so it (mongo-express) failed to connect, and kept in that failed state.
The way to go, is to add a dependency on mongo-express. It should start once mongo finished launching, and to achieve this use :
depends_on:
- mongodb
Upvotes: 1
Reputation: 3998
As suggested by @David Maze by adding restart: unless-stopped it worked
version: '3'
services:
mongodb:
image: mongo
ports:
- 27017:27017
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
mongo-express:
image: mongo-express
ports:
- 8081:8081
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME=admin
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
- ME_CONFIG_MONGODB_SERVER=mongodb
restart: unless-stopped
Upvotes: 19
Reputation: 564
The issues seem to be that you have configured the network. Within the express server, it is trying to connect to a Mongo instance running on its own localhost (being 127.0.0.1 of the container NOT your local machine). As there is no MongoDB instance running on your express service an ECONNREFUSED
(Error Connection Refused) is thrown. What we need to do is place the DB container on a network accessible from the express service and connect to it. You can find more information at the documentation here on networking with docker-compose.
What I find the easiest to do in this case, particularly for local development is to 'link' to two services together as shown below:
version: '3'
services:
mongodb:
image: mongo
ports:
- 27017:27017
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
mongo-express:
image: mongo-express
ports:
- 8080:8081
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME=admin
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
- ME_CONFIG_MONGODB_SERVER=mongodb
links:
- mongodb:mongodb
Then change mongoUrlLocal
to mongodb://admin:password@mongodb:27017
. Please check out the documentation here for more information. In effect, this creates a little pseudo DNS record within the mongo-express
services that points at the mongodb
service so whenever you try to connect to an address of "mongodb" you are connecting to the container that is running your database. Please note that this will only work for linked services so you can't connect to "mongodb" from your local machine.
In addition what I recommended you do I have environment variables for your database connection. At the moment I see you have ME_CONFIG_MONGODB_SERVER
which is not used, mongoUrlLocal
and mongoUrlDocker
. I think it may be better to pull the connection string information from process.env
then pass the environment variables, as you already, from your docker-compose file.
Something like this for example:
const dbServer = process.env.ME_CONFIG_MONGODB_SERVER;
const dbPassword = process.env.ME_CONFIG_MONGODB_ADMINPASSWORD;
const dbUserName = process.env.ME_CONFIG_MONGODB_ADMINUSERNAME;
const dbPort = process.env.ME_CONFIG_MONGODB_PORT;
let mongoUrl = `mongodb://${dbUserName}:${dbPassword}@${dbServer}:${dbPort}`;
Upvotes: 0