I'm using docker compose to pull up a MongoDB container and a simple Node CRUD app, really nothing fancy. The containers come up and seem to work so far, but when I try to enable authentication and log in using Compass, it always says "Authentication failed", no matter what user or connection settings I use. Inspecting the logs inside the Mongo container, I can see that the creation of the users apparently fails, but I have no clue why. Note that the same error message I posted in the logs section below also shows for the technical user in the same manner.
EDIT: just for clarification, I'm deploying this on my own dev server inside my local network, and the whole stuff is not intended to be pushed to some public server at any time. For personal use only, you could say ;-)
Here's my docker compose file:
services:
mongodb:
image: mongo:latest
restart: unless-stopped
ports:
- "1335:27017"
volumes:
- database:/database
- ./config/UserInit.js:/docker-entrypoint-initdb.d/UserInit.js:ro
environment:
- "MONGO_INITDB_ROOT_USERNAME=${MONGO_USER}"
- "MONGO_INITDB_ROOT_PASSWORD=${MONGO_PW}"
- "MONGO_INITDB_DATABASE=banking"
stdin_open: true
tty: true
bankingbackend:
depends_on:
- mongodb
build: .
restart: unless-stopped
stdin_open: true
tty: true
ports:
- "1336:1336"
volumes:
database:
Dockerfile:
FROM node:latest
WORKDIR "/bankingBackend"
COPY . .
RUN npm install
CMD ["npm", "start"]
UserInit.js which should create another (technical) user:
db.createUser(
{
user: process.env.MONGO_TEC_USER,
pwd: process.env.MONGO_TEC_USER_PASS,
roles: [
{
role: "readWrite",
db: "banking"
}
]
}
);
use("banking");
db.createCollection("accounts");
db.createCollection("transactions");
Jenkinsfile triggering the build and providing the credentials as env vars:
pipeline {
agent any
stages {
stage('checkout') {
steps {
checkout scm
}
}
stage('docker-compose-up') {
steps {
withCredentials([
usernamePassword(credentialsId: 'Mongo tec user', passwordVariable: 'MONGO_PW', usernameVariable: 'MONGO_USER'),
usernamePassword(credentialsId: 'Mongo tec user', passwordVariable: 'MONGO_TEC_USER_PASS', usernameVariable: 'MONGO_TEC_USER')]) {
sh 'MONGO_USER=MONGO_USER MONGO_PW=MONGO_PW MONGO_TEC_USER_PASS=MONGO_TEC_USER_PASS MONGO_TEC_USER=MONGO_TEC_USER docker compose up -d --build --force-recreate'
}
}
}
}
}
Logs:
"c":"ACCESS", "id":5286307, "ctx":"conn2","msg":"Failed to authenticate","attr":{"client":"192.166.124.101:53804","isSpeculative":false,"isClusterMember":false,"mechanism":"SCRAM-SHA-1","user":"adminUser","db":"admin","error":"UserNotFound: Could not find user \"adminUser\" for db \"admin\"","result":11,"metrics":{"conversation_duration":{"micros":451,"summary":{"0":{"step":1,"step_total":2,"duration_micros":421
When you run docker-compose with environment variables like this:
MONGO_USER=MONGO_USER MONGO_PW=MONGO_PW MONGO_TEC_USER_PASS=MONGO_TEC_USER_PASS MONGO_TEC_USER=MONGO_TEC_USER docker compose up -d --build --force-recreate
The environment variables are not being passed to the docker-compose process, but rather to the shell that's running the command.
To pass environment variables to the docker-compose process, you can use the -e flag followed by the variable name and value, like this:
docker compose -e MONGO_USER=MONGO_USER -e MONGO_PW=MONGO_PW -e MONGO_TEC_USER_PASS=MONGO_TEC_USER_PASS -e MONGO_TEC_USER=MONGO_TEC_USER up -d --build --force-recreate
However, this can become cumbersome if you have many environment variables.
A better approach is to define the environment variables in your docker-compose.yml file, like this:
services:
mongodb:
...
environment:
- MONGO_INITDB_ROOT_USERNAME=${MONGO_USER}
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_PW}
- MONGO_INITDB_DATABASE=banking
- MONGO_TEC_USER=${MONGO_TEC_USER}
- MONGO_TEC_USER_PASS=${MONGO_TEC_USER_PASS}
...
Then, in your Jenkinsfile, you can pass the environment variables like this:
withCredentials([
usernamePassword(credentialsId: 'Mongo tec user', passwordVariable: 'MONGO_PW', usernameVariable: 'MONGO_USER'),
usernamePassword(credentialsId: 'Mongo tec user', passwordVariable: 'MONGO_TEC_USER_PASS', usernameVariable: 'MONGO_TEC_USER')]) {
sh 'docker compose -f docker-compose.yml up -d --build --force-recreate'
}
This way, the environment variables will be passed to the docker-compose process and will be available to your containers.