Skip to content

No documentation on accessing ENV variables from docker-entrypoint_initdb.d #257

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dlipovac012 opened this issue Mar 23, 2018 · 19 comments
Closed

Comments

@dlipovac012
Copy link

dlipovac012 commented Mar 23, 2018

As the name said, i couldn't find a way of accessing env variables from docker.
What i need is to access some var that is defined in docker-compose file over here:

let res = [
'use admin',
db.createUser({
user: 'apUser', // it should be this: ENV_APP_SERVER_USERNAME
pwd: '12345',
roles: [
{
role: 'readWrite',
db: 'dummydb'
}
]
})
];

printjson(res);

This is the content of javascript file that gets copied into docker-entrypoint-inidb.d

@bchrobot
Copy link

There is an open issue on Mongo's Jira about this: https://jira.mongodb.org/browse/SERVER-4895

@BorntraegerMarc
Copy link

Thanks for the link @bchrobot

But what is the purpose of defining users in docker-entrypoint_initdb.d if you can't even access the password through env variables?
How else would one securely set passwords?

@tianon
Copy link
Member

tianon commented Mar 23, 2018 via email

@BorntraegerMarc
Copy link

ah so with a shell script it is possible. Thanks for the info @tianon Nice! So to convert the JS into a .sh script I would have written:

use admin
db.createUser({
  user:  $ENV_APP_SERVER_USERNAME,
  pwd: $ENV_APP_SERVER_PW,
  roles: [{
    role: 'readWrite',
    db: 'dummydb'
  }]
})

Is that correct? Without the whole printjson thing...

@bchrobot
Copy link

bchrobot commented Mar 23, 2018

Shell scripts are also executed (/docker-entrypoint-initdb.d/*.sh) so you could access ENV variables there.

From this SO post it seems like something along the following lines would work:

/docker-entrypoint-initdb.d/create_secure_user.sh:

# Executed during Mongo container startup, concatenates scripts to pass ENV var

mongo --eval "var secureUsername = '$ENV_APP_SERVER_USERNAME'" create_user-js

/docker-entrypoint-initdb.d/create_user-js:

// Skipped during Mongo container startup due to lack of .js extension.
// Instead, is executed by above shell script.

let res = [
  'use admin',
  db.createUser({
    user: secureUsername,
    pwd: '12345',
    roles: [
      {
        role: 'readWrite',
        db: 'dummydb'
      }
    ]
  })
];

printjson(res);

@bchrobot
Copy link

@tianon if the above seems like a reasonable approach I will add it as an example for ENV usage in the 'Initializing a fresh instance' section in my docker-docs PR

@yosifkit
Copy link
Member

I am quite sure you can just put it in one file and just use bash to insert the variables directly into the js. I don't see this as a necessary addition to the docs.

#!/bin/bash
set -e

mongo <<EOF
use admin
db.createUser({
  user:  '$ENV_APP_SERVER_USERNAME',
  pwd: '$ENV_APP_SERVER_PW',
  roles: [{
    role: 'readWrite',
    db: 'dummydb'
  }]
})
EOF

@dlipovac012
Copy link
Author

Thanks @yosifkit This script works perfectly fine.

@BorntraegerMarc
Copy link

Thanks @yosifkit
But may I ask why you don't want to put this in the docs? The fact that we had to open an issue to get this information is proof for me that the info is not easily accessable.

@x-yuri
Copy link

x-yuri commented Nov 28, 2018

No need for shebang, it's sourced.

@weibeld
Copy link

weibeld commented Apr 2, 2019

No need for shebang, it's sourced.

Thanks @x-yuri to point to this location in the code, that's great information.

For short commands, you could also use a pipe instead of a heredoc to send the commands to mongo's stdin:

echo "db.createUser({...})" | mongo admin

weibeld added a commit to weibeld/kubernetes-test-application that referenced this issue Apr 3, 2019
This works by means of the docker-entrypoint-initdb.d feature of the
mongo Docker image:

- https://hub.docker.com/_/mongo
- https://github.com/docker-library/docs/blob/master/mongo/README.md#initializing-a-fresh-instance

This feature runs scripts in the /docker-entrypoint-initdb.d directory
when the container is created. These scripts can do things like
initialising the database with default data.

The scripts can be either MongoDB JavaScript files or shell scripts.

JavaScript files (ending in .js) have to be written as explained here:
https://docs.mongodb.com/manual/tutorial/write-scripts-for-the-mongo-shell/.
They are executed as 'mongo <js-file>', as defined in the code here:
https://github.com/docker-library/mongo/blob/master/4.1/docker-entrypoint.sh#L321.

Shell scripts (ending in .sh) are sourced, as defined in the code here:
https://github.com/docker-library/mongo/blob/master/4.1/docker-entrypoint.sh#L320

The problem with using JavaScript files is that they do not allow to
read environment variables (see discussion here docker-library/mongo#257).
However, with shell scripts this is easily possible. For this reason,
the current solution uses a shell script (init-data.sh) to insert the
default data into the database.

The init-data.sh script is included in the database container image by
creating a new custom image on top of the MongoDB image that simply adds
the init-data.sh file to the /docker-entrypoint-initdb.d directory.

The database and collection to use is defined in the config-db.yaml
ConfigMap, which is used to initialise env variables for the database
pod (as well as for the webserver pod).
@javierguzman
Copy link

javierguzman commented Oct 30, 2020

edit: sorry I found the stupid error; I had a typo I did not notice and was importing badly my environment variable, sorry for the trouble! I am going to run it now through the entire CI/CD flow and see if it works.
Sorry @yosifkit I am trying your code snippet, however, it does not work. Has this changed?

I have an initDatabase.sh file with the following content:

#!/bin/bash
set -e

mongo <<EOF
use admin
db.createUser({
  user: '$MONGO_ADMIN_USER',
  pwd:  '$MONGO_ADMIN_PASSWORD',
  roles: [{
    role: 'readWrite',
    db: 'dummydb'
  }]
})
EOF

I have in my shell the environment variables defined, but if I run the script it does not go ok, the error is:

Error: couldn't add user: User passwords must not be empty

What am I missing?

Thank you very much in advance and regards.

@x-yuri
Copy link

x-yuri commented Oct 30, 2020

FWIW, here's my answer on Stack Overflow. Although I'd avoid using Docker Swarm (buggy) and secrets (environment variables are easier to use). Also from a cursory glance at docker-entrypoint.sh, it looks like without MONGO_INITDB_ROOT_USERNAME, MONGO_INITDB_ROOT_PASSWORD authentication is disabled, so no point in creating a user. On the other hand if you do specify the variables, you've got to authenticate first (before creating a user), as I did in my example. Whether it makes sense to create a non-root user if the database is accessed just by one application... I'm not sure.

@javierguzman
Copy link

Thanks @x-yuri Indeed at the end I just placed those variables (INITDB_ROOT_blabla) because as you pointed out, without them, auth is not enabled and I was having issues connecting because of that.

@orgads
Copy link
Contributor

orgads commented Apr 21, 2021

A function named _getEnv was added here. Usage:

_getEnv("MONGO_INITDB_ROOT_USERNAME")

@garex
Copy link

garex commented Jul 30, 2021

A function named _getEnv was added here. Usage:

_getEnv("MONGO_INITDB_ROOT_USERNAME")

But only since 4.7.0 !

@ogostus
Copy link

ogostus commented Mar 23, 2023

To access env variables from docker-entrypoint-initdb.d

Add env variables to mongo's container either via env_file or environment attributes

  mongo:
    volumes:
      # Add the db-init.js file to the Mongo DB container
      - .PATH_TO_FILE/db-init.js:/docker-entrypoint-initdb.d/db-init.js:ro
    ports:
      - ${MONGO_PORT}:27017
    environment:
      - MONGO_INITDB_DATABASE=
      - MONGO_INITDB_ROOT_USERNAME
      - MONGO_INITDB_ROOT_PASSWORD-
      - MONGO_USER
      - MONGO_PASSWORD

db-init.js content would be:

db.createUser({
  user: process.env.MONGO_USER,
  pwd: process.env.MONGO_PASSWORD,
  roles: [{ role: "readWrite", db: "dummydb" }],
});

@x-yuri
Copy link

x-yuri commented Mar 23, 2023

Some time ago, I updated my answer. _getEnv() is undocumented and available for a limited range of versions (around >=4.4, <5 probably). Starting with 6.x you can use process.env. Before that with the help of jq you can achieve pretty much the same result. At least I don't see any issues with it.

@bacloud22

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests