2

I have a project with this directory structure:

- other-service/
- my-service/
   src/
   Dockerfile
   .env
docker-compose
.env

I have defined my mongoDB container & service container in a docker-compose.yml file like below:

version: "3"
services:
  my-service:
    depends_on:
      - mongodb
    env_file: ./my-service/.env
    container_name: my-service
    build: ./my-service
    environment:
      - DB_HOST=$DB_HOST
      - DB_USER=$DB_USER
      - DB_PASSWORD=$DB_PASSWORD
      - DB_NAME=$DB_NAME
      - DB_PORT=$DB_PORT
    ports:
      - "3002:3002"

  mongodb:
    image: mongo:latest
    container_name: my-mongodb
    env_file: ./.env
    environment:
      MONGO_INITDB_ROOT_USERNAME: $DB_USER
      MONGO_INITDB_ROOT_PASSWORD: $DB_PASSWORD
    ports:
      - $DB_PORT:$DB_PORT
    volumes:
      - db_vol:/data/db

volumes:
  db_vol:

The my-service/.env file looks like this:

DB_HOST=mongodb
DB_USER=root
DB_PASSWORD=pass123
DB_NAME=my_db
DB_PORT=27017
...

The root level .env looks like this (basically the same content as my-service/.env for the DB part):

#used by compose
DB_HOST=mongodb
DB_USER=root
DB_PASSWORD=pass123
DB_NAME=my_db
DB_PORT=27017

my-service tries to connect to mongoDB with this code:

 const dbUri=`mongodb://${process.env['DB_USER']}:${process.env['DB_PASSWORD']}@${process.env['DB_HOST']}:${process.env['DB_PORT']}/${process.env['DB_NAME']}`

 console.log(`DB connect to: ${dbUri}`);
 await mongoose.connect(dbUri, {
            useNewUrlParser: true,
            useUnifiedTopology: true,
            useCreateIndex: true
        });

After I run docker-compose build & docker-compose up -d. The my-mongodb container is up and running. But my-service is not. I checked the container log, it shows:

DB connect to: mongodb://root:pass123@mongodb:27017/my_db
...
DatabaseConnError: Database connection failure. undefined
  ...
  statusCode: 500,
  msg: 'Database connection failure'
}

Node.js v19.2.0

I feel it is because both containers are on the same Docker bridge network, the database URI I defined might not correct? But I am not sure. Could someone please guide me where could be wrong in my case?

=== UPDATE on 8th of December2022 ===

I dug deeper of my problem, it turned out the problem is actually an AuthenticationError, full error log is below:

Database connection failure. {"ok":0,"code":18,"codeName":"AuthenticationFailed","name":"MongoError"}

It is the same issue @jeeves' answer below has mentioned, then I tried adding ?authSource=admin like @jeeves suggested:

DB connect to: mongodb://root:pass123@mongodb:27017/my_db?authSource=admin

but I still get the authentication error. Why?

user842225
  • 5,445
  • 15
  • 69
  • 119
  • 1
    One possible cause of your problem here is that the mongo container could be running but the DB app is not ready to accept connections when your `my-service` container starts. Try bringing up the DB first `docker-compose up -f mongodb`. Verify that you can connect to it locally and then bring up your other service, `docker-compose up -f my-service` – jeeves Dec 05 '22 at 17:13
  • Thanks, I am pretty sure the mongodb container is up & running firstly. Do you know is it so that the docker default bridge network doesn't support container name as host to ping each other but only self-created bridge network does? – user842225 Dec 06 '22 at 16:31
  • 1
    afaik you should definitely be able to use the service name i.e. mongodb I'd check to make sure that you can connect to the database locally. By using ports vs expose in your docker-compose you should be able to access the db locally. Use something like mongo-express (if you don't have a local client) to verify the connection & credentials. Then verify with your app running locally. There could be other issues at play - e.g. a volume issue etc. But from what I can see - your compose file looks good to me. See below for working example. – jeeves Dec 08 '22 at 10:19

2 Answers2

2

you might need a healthcheck for mongodb.

version: "3"
services:
  my-service:
    depends_on:
      mongodb:
        condition: service_healthy
    env_file: ./my-service/.env
    container_name: my-service
    build: ./my-service
    environment:
      - DB_HOST=$DB_HOST
      - DB_USER=$DB_USER
      - DB_PASSWORD=$DB_PASSWORD
      - DB_NAME=$DB_NAME
      - DB_PORT=$DB_PORT
    ports:
      - "3002:3002"

  mongodb:
    image: mongo:latest
    container_name: my-mongodb
    env_file: ./.env
    environment:
      MONGO_INITDB_ROOT_USERNAME: $DB_USER
      MONGO_INITDB_ROOT_PASSWORD: $DB_PASSWORD
    ports:
      - $DB_PORT:$DB_PORT
    volumes:
      - db_vol:/data/db
    healthcheck:
      test:  echo 'db.runCommand("ping").ok' | mongosh localhost:$DB_PORT/test --quiet
      interval: 10s
      timeout: 10s
      retries: 5
      start_period: 10s      

volumes:
  db_vol:

Similar: mongodb and mongo-express not connecting with docker-compose

zsolt
  • 1,233
  • 8
  • 18
  • Thanks! I added the healthcheck, but that just repetitively shows me the same error I posted in my question, I don't see how it could solve my problem? Could you please provide more guidance? – user842225 Dec 06 '22 at 18:38
0

I'm not sure where the problem here is. I certainly had a few issues authenticating with the DB but I believe that that is an issue with the database itself (and my lack of understanding of it ;)) and not a docker-compose/ networking problem.

Here is a stripped back (but working) version.

Directory structure

enter image description here

docker-compose file

version: "3"
services:
  my-service:
    depends_on:
      - mongodb
    container_name: my-service
    build: ./my-service
    environment:
      - DB_HOST=mongodb
      - DB_USER=root
      - DB_PASSWORD=password123
      - DB_NAME=test
      - DB_PORT=27017
    ports:
      - "3002:3002"

  mongodb:
    image: mongo:latest
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: password123
    ports: 
      - "27017:27017"

Dockerfile

FROM node:19

WORKDIR /usr/src/app
COPY . .
RUN npm install
USER node
CMD ["node", "index.js"]

And my index.js

Note: added following query param ?authSource=admin to connection string.

const mongoose = require('mongoose');
console.log(process.env);

const dbUri=`mongodb://${process.env['DB_USER']}:${process.env['DB_PASSWORD']}@${process.env['DB_HOST']}:${process.env['DB_PORT']}/${process.env['DB_NAME']}?authSource=admin`

console.log(dbUri, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useCreateIndex: true
});

mongoose.connect(dbUri).then(() => console.log('is connected'))
       .catch((error) => console.log(error));

Then execute following:

$ cd demo
$ docker-compose build
$ docker-compose up mongodb
$ docker-compose up my-service

Output from my-service:

$ docker-compose up my-service
demo_mongodb_1 is up-to-date
Recreating my-service ... done
Attaching to my-service
my-service    | {
my-service    |   NODE_VERSION: '19.2.0',
my-service    |   HOSTNAME: 'ea324ba32274',
my-service    |   DB_PORT: '27017',
my-service    |   YARN_VERSION: '1.22.19',
my-service    |   HOME: '/home/node',
my-service    |   DB_NAME: 'test',
my-service    |   PATH: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
my-service    |   DB_PASSWORD: 'password123',
my-service    |   PWD: '/usr/src/app',
my-service    |   DB_HOST: 'mongodb',
my-service    |   DB_USER: 'root'
my-service    | }
my-service    | mongodb://root:password123@mongodb:27017/test?authSource=admin
my-service    | (node:1) [MONGOOSE] DeprecationWarning: Mongoose: the `strictQuery` option will be switched back to `false` by default in Mongoose 7. Use `mongoose.set('strictQuery', false);` if you want to prepare for this change. Or use `mongoose.set('strictQuery', true);` to suppress this warning.
my-service    | (Use `node --trace-deprecation ...` to show where the warning was created)
my-service    | is connected

The additional query string is doing nothing for connectivity between containers. I was getting an authentication error when connecting - but that still meant containers had connectivity.

Hope this helps

jeeves
  • 1,871
  • 9
  • 25
  • Running this with env files also works as expected – jeeves Dec 07 '22 at 20:25
  • Interesting! Because I dug deeper of my problem, it turned out exactly an `AuthenticationFailed` error code caused it. But I tried your suggestion of adding `?authSource=admin`, I still get the authentication error. Besides, I noticed your code doesn't provide the ConnectionOption when ```await mongoose.connect(dbUri)``` but mine has if you see my code in my OP. – user842225 Dec 08 '22 at 21:46
  • could you please see my update in my post? – user842225 Dec 08 '22 at 21:53
  • Could you please add the ConnectionOptions as in my code to see if it still works for you? And which mongodb version are you using? – user842225 Dec 08 '22 at 22:19
  • Tested with connection options. Still works. Using latest mongodb container. Using mongoose@6.8.0 – jeeves Dec 10 '22 at 16:03