Connecting to mongo docker container from host - node.js

I'm running Docker on OS X with:
docker run --name mongo -p 27017:27017 -v ./data/db:/data/db -d mongo mongod
and using the ip I get from:
docker inspect --format '{{ .NetworkSettings.IPAddress }}' <cid>
in:
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var url = 'mongodb://<ip>:27017';
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
db.close();
});
and I'm getting a timed out error.
I'm using the official mongo repository from Docker Hub. Is there any additional setup that I need to do in order to connect from the host?

Is the node.js code being run from a container or from the host?
If it's on the host, just use the localhost address i.e:
var url = 'mongodb://localhost:27017';
This will work because you published the port with -p 27017:27017.
If the code is running inside a container, it would be best to rewrite it to use links and referring to the mongo container by name e.g:
var url = 'mongodb://mongo:27017';
Then when you launch the container with the Node.js code, you can just do something like:
docker run -d --link mongo:mongo my_container
Docker will then add an entry to /etc/hosts inside the container so that the name mongo resolves to the IP of the mongo container.

If you use a user defined network you should be able to pick it up without linking or specifying 27017
const MONGO_NAME_STR = "mongodb://" + "your_docker_container_name";
var db = {};
mongo_client.connect(MONGO_NAME_STR, function(err, _db){
//some err handling
db = _db;
});

Another option for anyone who use docker-compose
version: '3.1'
services:
mongo:
image: mongo
container_name: "mongo"
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
volumes:
- './dockervolume/mongodb:/data/db'
ports:
- 27017:27017
And u can connect using the url string
MongoClient.connect("mongodb://root:example#localhost:27017")
.then(()=>{
console.log("db connect success");
})
.catch((err)=>{
throw err
});

Using docker-compose, same can be achieved as below
version: '3.1'
services:
mongo:
image: mongo
restart: always
ports:
- 27017:27017
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
mongo-express:
image: mongo-express
restart: always
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: example
ME_CONFIG_MONGODB_URL: mongodb://root:example#mongo:27017/
The connection string is as below,
On Host -
const uri = "mongodb://root:example#localhost:27017/
On Container -
const url = 'mongodb://root:example#mongo:27017'
Port mapping can be configured to use a custom host port [8000] like - 8000:27017

Related

How to link mongo with node using docker compose

I'm trying link my node server with my db in Mongo, but doesn't work...
This is my Docker-Compose.yml:
version: '3.9'
services:
human:
build:
context: ./human-app
container_name: human
ports:
- "3001:3001"
mongodb:
image: mongo
container_name: mongodb
env_file:
- ./human-app/srcs/.env
environment:
- MONGO_INITDB_ROOT_USERNAME=Pepe
- MONGO_INITDB_ROOT_PASSWORD=PepePass
- MONGO_INITDB_DATABASE=Pool
ports:
- "27017:27017"
volumes:
- ./volumes_mongo:/data/db
And when i run the command:
docker-compose up -d
Everything work correctly but separate, i check the status with the command "docker ps -a" and the result is this:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9335c5cd4940 mongo "docker-entrypoint.s…" 4 seconds ago Up 3 seconds 0.0.0.0:27017->27017/tcp mongodb
2a28635d2caa human-selection-app_human "node server" 4 seconds ago Up 3 seconds 0.0.0.0:3001->3001/tcp human
If i enter in my container of mongo, and follow the next steps, thats happen:
1- docker exec -it mongodb bash
2- mongo
3- show dbs "result no dbs"
So, i can't link nothing with my node server, probably i need create a network for the 2 services? can anyone help me? thanks.
Extra, this is how i connect from my server to MongoDB:
async _connectDB() {
//! We create the connection to the database
const dbUser = process.env.DBUSER;;
const dbPassword = process.env.DBPASSWORD;
const dbName = process.env.DBNAME;
const dbUriLocal = `mongodb://${dbUser}:${dbPassword}#127.0.0.1:27017/${dbName}`;
mongoose.connect(dbUriLocal, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log(clc.cyan('Debug: Database connected successfully')))
.catch(e => console.log(e));
}
As your application is also running inside of a Docker container being in the same network with the MongoDB Service, it means you should use MongoDB's service name as the connection address instead of the localhost IP address.
Change your dbUriLocal variable to use the MongoDB Service name (in your case, it is "mongodb" named after the service name in docker-compose.yml) as the connection address instead of "127.0.0.1":
const dbUriLocal = `mongodb://${dbUser}:${dbPassword}#mongodb:27017/${dbName}`;
See "Networking" in the Docker Compose File Referrence for more information.

Nodejs cannot connect to Postgresdb container

I am currently working on an angular app using Rest API (Express, Nodejs) and Postgresql. Everything worked well when hosted on my local machine. After testing, I moved the images to Ubuntu server so the app can be hosted on an external port. I am able to access the angular frontend using the https://serveripaddress:80 but when trying to login, the api is not connecting to Postgresql. I am getting an error message: ERR_CONNECTION_REFUSED. Here is my docker-compose file:
version: '3.0'
services:
db:
image: postgres:9.6-alpine
environment:
POSTGRES_DB: myDatabase
POSTGRES_PASSWORD: myPwd
POSTGRES_PORT: 5432
POSTGRES_HOST: db
ports:
- 5434:5432
restart: always
volumes:
- ./postgres-data:/var/lib/postgresql/data
backend: # name of the second service
image: myid/nodeapi
ports:
- 3000:3000
environment:
POSTGRES_DB: myDatabase
POSTGRES_PASSWORD: myPwd
POSTGRES_PORT: 5432
POSTGRES_HOST: db
depends_on:
- db
command: bash -c "sleep 20 && node server.js"
myapp-portal:
image: myId/angular-app
ports:
- "80:80"
depends_on:
- backend
volumes:
postgres-data:
The code to connect to database:
const { Client } = require('pg')
const client = new Client({
database: process.env.POSTGRES_DB,
user: 'postgres',
password: process.env.POSTGRES_PASSWORD,
host: process.env.POSTGRES_HOST,
port: process.env.POSTGRES_PORT
})
client.connect()
.then(
() => {
console.log("db connected");
})
and the docker-compose log for backend:
backend_1 | db connected
When I exec into the database docker container and connect to psql, I see that my database is created(used pg_dump manually) with all the tables and data. My guess is that node.js is connecting to the default Postgres database created at the time of the installation. I had the same issue on my local machine but I resolved it by creating a new server group in pgAdmin4 and creating a new db on port 5434. I prefer not to do this on server as it defeats the purpose of the concept of docker. Another thought is perhaps node.js is attempting to connect to the database even before it is up. That is the reason I added the line 'sleep 20' which worked on my local machine. Any thoughts on how I can fix this? TIA!
If you want to wait on the availability of a host and TCP port, you can use this script https://github.com/vishnubob/wait-for-it
In your docker file you can copy this file into container and change mode
RUN chmod +x wait-for-it.sh
Then in your docker compose run this script on service which you want to wait
entrypoint: bash -c "./wait-for-it.sh --timeout=0 service_name:service_port && node server.js"

Using Docker Compose to connect separate Postgres and Node containers together

I'm trying to use Docker Compose to connect a Node.js container to a Postgres container. I can run the Node server fine, and can also connect to the Postgres container fine from my local as I've mapped the ports, but I'm unable to get the Node container to connect to the database.
Here's the compose YAML file:
version: "3"
services:
api_dev:
build: ./api
command: sh -c "sleep 5; npm run dev" # I added the sleep in to wait for the DB to load but it doesn't work either way with or without this sleep part
container_name: pc-api-dev
depends_on:
- dba
links:
- dba
ports:
- 8001:3001
volumes:
- ./api:/home/app/api
- /home/app/api/node_modules
working_dir: /home/app/api
restart: on-failure
dba:
container_name: dba
image: postgres
expose:
- 5432
ports:
- '5431:5432'
env_file:
- ./api/db.env
In my Node container, I'm waiting for the Node server to spin up and attempting to connect to the database in the other container like so:
const { Client } = require('pg')
const server = app.listen(app.get('port'), async () => {
console.log('App running...');
const client = new Client({
user: 'db-user',
host: 'dba', // host is set to the service name of the DB in the compose file
database: 'db-name',
password: 'db-pass',
port: 5431,
})
try {
await client.connect()
console.log(client) // x - can't see this
client.query('SELECT NOW()', (err, res) => {
console.log(err, res) // x - can't see this
client.end()
})
console.log('test') // x - can't see this
} catch (e) {
console.log(e) // x - also can't see this
}
});
After reading up on it today in depth, I've seen the DB host in the connection code above can't be localhost as that refers to the container which is currently running, so it must be set to the service name of the container we're connecting to (dba in this case). I've also mapped the ports, and can see the DB is ready accepting connections well before my Node server starts.
However, not only can I not connect to the database from Node, I'm also unable to see any success or error console logs from the try catch. It's as if the connection is not resolving, and doesn't ever time out, but I'm not sure.
I've also seen that the "listen_addresses" needs to be updated so other containers can connect to the Postgres container, but struggling to find out how to do this and test when I can't debug the actual issue due to lack of logs.
Any direction would be appreciated, thanks.
You are setting the container name and can reference that container by it. For example,
db:
container_name: container_db
And host:port
DB_URL: container_db:5432

How do I connect my mongo database to my node app with this mongoDB connection string using docker-compose?

This is a part of my node app
app.configure('development', function() {
app.set('db-uri', 'mongodb://localhost/nodepad-development');
app.use(express.errorHandler({ dumpExceptions: true }));
app.set('view options', {
pretty: true
});
});
app.configure('test', function() {
app.set('db-uri', 'mongodb://localhost/nodepad-test');
app.set('view options', {
pretty: true
});
});
app.configure('production', function() {
app.set('db-uri', 'mongodb://localhost/nodepad-production');
});
Edited to
app.set('db-uri', 'mongodb://mongoDB:27017/nodepad-development');
Still the same error.
I have already created container for my node app which runs on local host but I am unable to connect it to another mongo container due to which I cannot do POST requests to the app.
This is my docker compose file
version: '3'
services:
apptest:
container_name: apptest
restart: always
image: ekamzf/nodeapp:1.1
ports:
- '8080:8080
depends_on:
- mongoDB
mongoDB:
container_name: mongoDB
image: mongo
volumes:
- ./data:/usr/src/app
ports:
- '27017:27017'
And the error I get when I try to register account details in my node app is
Error: Timeout POST /users
at null._onTimeout (/usr/src/app/node_modules/connect-timeout/index.js:12:22)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
What am I missing?
Basically, how should I connect this type of code with mongodb anyway ?
What's the role of 'db-uri'?
Docker Compose aliases service names to host names.
Because you named your container running the mongo image as mongoDB, mongodb (case insensitive) will be the name of the host and the name by which you should refer to it from your Node.JS container and app.
Replace localhost in the URI with mongodb
The MongoDB database defaults to port 27017. Unless you've changed the port, you should specify this value.
Add the port to URI so that you have mongodb:27017
Optional but good practice, refactor the app to use environment variables rather than hard-coded values.
This has at least 2 benefits:
a. Your code becomes more flexible;
b. Your Compose file, by then specifying these values, will be clearer.
See the DockerHub documentation for the image here
See MongoDB"s documentation on connection strings here
A Google search returns many examples using Compose, MongoDB and Node.JS
Update: repro
I'm confident your issue may be related to the timing of the Compose containers. I believe your app tries to connect to the DB before the DB container is ready. This is a common issue with Compose and is not solved using Compose's depends_on. Instead you must find a MongoDB (or perhaps other database) solution to this.
In my repro, index.js (see below) introduces a false delay before it tries to connect to the database. 5 seconds is sufficient time for the DB container to be ready and thus this works:
docker-compose build --no-cache
docker-compose up
Then:
docker-compose logs app
Attaching to 60359441_app_1
app_1 | URL: mongodb://mongodb:27017/example
app_1 | Connected
yields Connected which is good.
Alternatively, to prove the timing issue, you may run the containers separately (and you could remove the sleep function to ensure the database is ready before the app:
HOST=localhost # No DNS naming
PORT=37017 # An arbitrary port to prove the point
# In one session
docker run \
--interactive --tty --rm \
--publish=${PORT}:27017 \
mongo
# In another session
docker run \
--interactive --tty --rm \
--net=host \
--env=HOST=${HOST} --env=PORT=${PORT} --env=DATA=example --env=WAIT=0 \
app
URL: mongodb://localhost:37017/example
Connected
docker-compose.yaml:
version: "3"
services:
app:
image: app
build:
context: ./app
dockerfile: Dockerfile
environment:
- HOST=mongodb
- PORT=27017
- DATA=example
- WAIT=5000
volumes:
- ${PWD}/app:/app
mongodb:
image: mongo
restart: always
# environment:
# MONGO_INITDB_ROOT_USERNAME: root
# MONGO_INITDB_ROOT_PASSWORD: example
mongo-express:
image: mongo-express
restart: always
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_SERVER: mongodb
# ME_CONFIG_MONGODB_ADMINUSERNAME: root
# ME_CONFIG_MONGODB_ADMINPASSWORD: example
NB Because I followed your naming of mongodb, the mongo-express container must be provided this host name through ME_CONFIG_MONGODB_SERVER
NB The other environment variables shown with mongo and mongo-express images are the defaults and thus optional.
Dockerfile:
FROM node:13.8.0-slim
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . .
ENTRYPOINT ["node","index.js"]
index.js:
// Obtain config from the environment
const HOST = process.env.HOST;
const PORT = process.env.PORT;
const DATA = process.env.DATA;
const WAIT = parseInt(process.env.WAIT, 10);
// Create MongoDB client
var MongoClient = require("mongodb").MongoClient;
let url = `mongodb://${HOST}:${PORT}/${DATA}`;
console.log(`URL: ${url}`);
// Artificially delay the code
setTimeout(function() {
MongoClient.connect(url, function(err, db) {
if(!err) {
console.log("Connected");
}
});
}, WAIT);
NB index.js uses the environment (HOST,PORT,DB) for its config which is good practice.
Including mongo-express provides the ability to browse the mongo server to readily observe what's going on:

Link nodejs app to Rethinkdb from another container

I made two 2 containers, one for the RethinkDB and one for a nodejs app.
I want to connect my nodejs app to this RethinkDB but everytime I try get an error
Error:{"message":"Failed to connect to localhost:58015\nFull error:\n{\"code\":\"ECONNREFUSED\"
But I can connect the same nodejs app running without Docker to the RethinkDB, with the open port (58015).
My Docker compose config look like this
# Rethink DB
rethink:
build: docker/rethinkdb
container_name: rethink
ports:
- 58080:8080
- 58015:28015
- 59015:29015
# NodeJS
nodejs:
build: docker/nodejs
container_name: nodejs
ports:
- 53000:3000
- 55000:5000
depends_on:
- rethink
To connect my app to the db I set the host and port inside a JS config file
database: {
servers: [
{
host: process.env.DB_PORT_28015_TCP_ADDR || 'localhost',
port: process.env.DB_PORT_28015_TCP_PORT || 28015
}
],
name: 'atlas'
},
I tried with RethinkDB port (28015) and with my open port (58015) without success.
I tried to link this two containers with links, network_mode, without success too.
Every solutions I tried don't work.
I think my Rethink container is not ready when the nodejs app try to connect. I really don't understand the problem, if this not this.
The nodejs app is running with pm2
How can I made this app connect to my db ?
For you config, you should use
# Rethink DB
rethink:
build: docker/rethinkdb
container_name: rethink
ports:
- 58080:8080
- 58015:28015
- 59015:29015
# NodeJS
nodejs:
build: docker/nodejs
container_name: nodejs
ports:
- 53000:3000
- 55000:5000
links:
- rethink
depends_on:
- rethink
and in JS code
database: {
servers: [
{
host: process.env.DB_PORT_28015_TCP_ADDR || 'rethink',
port: process.env.DB_PORT_28015_TCP_PORT || 28015
}
],
name: 'atlas'
},
As far as I know, one Docker container will not see the other unless specifically linked and using the same net:
docker run \
--name ${NEWAPP} \
--restart=always \
--env MYAPPPAR=${PROJ} \
-v /var/log/docker/node/logs:/usr/src/app/log \
--link myapp_rethink_1:myapp_rethink_1 \
--net myapp_default \
-p ${PORT}:9000 \
-d ${NEWAPP}
So you need both --net and --link:
--link format is sourcecontainername:containeraliasname
--net so that containers can find each other with internal DNS / containername. You can check network with 'docker network ls'
When using newer versions of docker-compose, your services will be configured to run on the same network.
The top level service name in your 'docker-compose.yml' will become the host that needs to be specified, when connecting to RethinkDB from your app:
# docker-compose.yml
version: '3.2'
Services:
web:
build: .
links: db
...
db:
image: rethinkDB
...
Using the example above, you can connect to RethinkDB by using the host named 'db', within the app configuration file:
module.exports = {
rethinkdb: {
host: 'db',
port: 28015
}
};

Resources