Search code examples
mongodbbashdockerdocker-compose

Docker entrypoint script for MongoDB does not get executed


This is a copy of my question on the MongoDB forum, accessible here. It has been about 12 hours since I've posted, so I am now trying to see if I am able to get an answer with SO. I also added some extra detail.

I've been trying to get my Docker setup of MongoDB to work the whole day. Unfortunately, I was not able to. I have a docker-compose.yml file in which I have my application and MongoDB:

services:
  app:
    build: ./app
    restart: unless-stopped
    env_file: "app/.env"
    ports:
      - 21865:21865
    depends_on:
      mongo:
        condition: service_healthy
    networks:
      - mongo-network
  
  mongo:
    image: mongo:latest
    restart: unless-stopped
    ports:
      - 27017:27017
    env_file: "mongo/.env"
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
      interval: 10s
      timeout: 10s
      retries: 5
    volumes:
      - ./mongo/data:/data/db
      - ./mongo/scripts:/docker-entrypoint-initdb.d/
    networks:
      - mongo-network

networks:
  mongo-network:
    driver: bridge

My entrypoint script is mongo/scripts/init.js:

use db1;
db.col1.insertOne({"exists": true});
db.createUser({
    user: "<user>",
    pwd: "<pw>",
    roles: [ { role: "readWrite", db: "db1" } ]
});

use db2;
db.col2.insertOne({"exists": true});
db.createUser({
    user: "<user>",
    pwd: "<pw>",
    roles: [ { role: "readWrite", db: "db2" } ]
});

I am using some probably redundant code to ENSURE the existence of the databases db1 and db2. However, when I launch Docker Compose and authenticate with root (docker-compose exec -it mongo mongosh -u "root" -p) and run show databases, the databases db1 and db22 are not shown:

test> show databases;
admin   100.00 KiB
config   12.00 KiB
local    72.00 KiB

Additionally, authentication, be it with or without specifying authSource, always fails. This is the output after my application attempts to authenticate.

docker-compose logs mongo | grep <user>
docker-server-mongo-1  | {"t":{"$date":"2024-10-20T17:31:28.573+00:00"},"s":"I",  "c":"ACCESS",   "id":20251,   "ctx":"conn300","msg":"Supported SASL mechanisms requested for unknown user","attr":{"user":{"user":"<user>","db":"<db1>"}}}
docker-server-mongo-1  | {"t":{"$date":"2024-10-20T17:31:28.573+00:00"},"s":"I",  "c":"ACCESS",   "id":5286307, "ctx":"conn300","msg":"Failed to authenticate","attr":{"client":"192.168.160.3:44922","isSpeculative":true,"isClusterMember":false,"mechanism":"SCRAM-SHA-256","user":"<user>","db":"<db1>","error":"UserNotFound: Could not find user \"<user1>\" for db \"<db1>\"","result":11,"metrics":{"conversation_duration":{"micros":177,"summary":{"0":{"step":1,"step_total":2,"duration_micros":150}}}},"extraInfo":{}}}
docker-server-mongo-1  | {"t":{"$date":"2024-10-20T17:31:28.575+00:00"},"s":"I",  "c":"ACCESS",   "id":5286307, "ctx":"conn300","msg":"Failed to authenticate","attr":{"client":"192.168.160.3:44922","isSpeculative":false,"isClusterMember":false,"mechanism":"SCRAM-SHA-1","user":"<user>","db":"<db1>","error":"UserNotFound: Could not find user \"<user>\" for db \"<db1>\"","result":11,"metrics":{"conversation_duration":{"micros":194,"summary":{"0":{"step":1,"step_total":2,"duration_micros":181}}}},"extraInfo":{}}}

I was able to confirm that the MongoDB server is locally accessible by running curl:


> curl localhost:27017
It looks like you are trying to access MongoDB over HTTP on the native driver port.

Bash-ing into my application, curl also shows that the database is accessible:

> docker-compose exec -it app bash
bash-5.2# curl mongo:27017
It looks like you are trying to access MongoDB over HTTP on the native driver port.

Interestingly, I was able to confirm that MongoDB acknowledges the presence of the script. So I tried including a printjson({"This": "Works"}) statement in my startup script, but to no avail.

> docker-compose logs mongo | grep entrypoint
docker-server-mongo-1  | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/init.js
> docker-compose logs mongo | grep This
>

I hope I have provided enough detail. I redacted the actual usernames, passwords and database names. Please assist me in resolving this problem. The only solution I currently see is to authenticate my app with the root user, which I do not want to do.


Solution

  • You had something like this in composer logs:

    mongo-1  | SyntaxError: Missing semicolon. (1:3)
    mongo-1  |
    mongo-1  | > 1 | use db1;
    mongo-1  |     |    ^
    

    Script syntax is slightly different to the interactive shell flavour:

    db = connect( 'mongodb://localhost/db1');
    db.col1.insertOne({"exists": true});
    db.createUser({
        user: "<user>",
        pwd: "<pw>",
        roles: [ { role: "readWrite", db: "db1" } ]
    });
    
    db = connect( 'mongodb://localhost/db2');
    db.col2.insertOne({"exists": true});
    db.createUser({
        user: "<user>",
        pwd: "<pw>",
        roles: [ { role: "readWrite", db: "db2" } ]
    });
    

    A side note:

    Ensure ./mongo/data is empty when you start composer.

    Initdb scripts run only once, when db is not initialized yet:

    Initializing a fresh instance

    When a container is started for the first time it will execute files with extensions .sh and .js that are found in /docker-entrypoint-initdb.d. Files will be executed in alphabetical order. .js files will be executed by mongosh (mongo on versions below 6) using the database specified by the MONGO_INITDB_DATABASE variable, if it is present, or test otherwise. You may also switch databases within the .js script.

    Source: https://hub.docker.com/_/mongo