¿Cómo crear una base de datos para el contenedor MongoDB al iniciar?

82

Estoy trabajando con Docker y tengo una pila con PHP, MySQL, Apache y Redis. Necesito agregar MongoDB ahora, así que estaba verificando el Dockerfile para la última versión y también el archivo docker-entrypoint.sh del MongoDB Dockerhub, pero no pude encontrar una manera de configurar una base de datos predeterminada, usuario / contraseña de administrador y posiblemente autenticación método para el contenedor desde un docker-compose.ymlarchivo.

En MySQL puede configurar algunas variables ENV como por ejemplo:

db:
    image: mysql:5.7
    env_file: .env
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}

Y esto configurará la base de datos y el usuario / contraseña como rootcontraseña.

¿Hay alguna forma de lograr lo mismo con MongoDB? ¿Alguien tiene alguna experiencia o solución?

ReynierPM
fuente
¿Puedes crear un contenedor basado en mysql y configurarlo como quieras y luego usarlo?
Valentin
@Valentin, por supuesto que puedo, pero ¿cuál es tu punto?
ReynierPM
Mi punto es que puede configurar una base de datos predeterminada, un usuario / contraseña de administrador y posiblemente un método de autenticación en dockerfile usando variables y luego pasarlas en el archivo de composición
Valentin
Nota: Si usa alguna de las soluciones que usan el script mongo-init, asegúrese de configurar reiniciar: a menos que se detenga (o algo además de no) para los contenedores que dependen de mongo. Esto se debe a que estos contenedores no se conectarán a mongo la primera vez mientras se inicializa (incluso con el indicador depend_on). Vea este hilo para más detalles stackoverflow.com/questions/31746182/…
java-addict301

Respuestas:

91

La imagen oficial semongo ha fusionado con un PR para incluir la funcionalidad para crear usuarios y bases de datos al inicio.

La inicialización de la base de datos se ejecutará cuando no haya nada en el /data/dbdirectorio.

Configuración de usuario administrador

Las variables de entorno para controlar la configuración del usuario "root" son

  • MONGO_INITDB_ROOT_USERNAME
  • MONGO_INITDB_ROOT_PASSWORD

Ejemplo

docker run -d \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=password \
  mongod

No necesita / no puede usar --authen la línea de comando ya que el script docker entrypoint.sh agrega esto cuando existen las variables de entorno.

Inicialización de la base de datos

La imagen también proporciona la /docker-entrypoint-initdb.d/ruta para implementar scripts de configuración .jso personalizados .shque se ejecutarán una vez en la inicialización de la base de datos. .jsLos scripts se ejecutarán testde forma predeterminada o MONGO_INITDB_DATABASEsi están definidos en el entorno.

COPY mysetup.sh /docker-entrypoint-initdb.d/

o

COPY mysetup.js /docker-entrypoint-initdb.d/

Un archivo javascript simple de inicialización mongo shell que demuestra cómo configurar la containercolección con datos, registro y cómo salir con un error (para la verificación de resultados)

let error = true

let res = [
  db.container.drop(),
  db.container.createIndex({ myfield: 1 }, { unique: true }),
  db.container.createIndex({ thatfield: 1 }),
  db.container.createIndex({ thatfield: 1 }),
  db.container.insert({ myfield: 'hello', thatfield: 'testing' }),
  db.container.insert({ myfield: 'hello2', thatfield: 'testing' }),
  db.container.insert({ myfield: 'hello3', thatfield: 'testing' }),
  db.container.insert({ myfield: 'hello3', thatfield: 'testing' }),
  db.other.
]

printjson(res)

if (error) {
  print('Error, exiting')
  quit(1)
}
Mate
fuente
Esto es excelente, supongo que le set -eestá diciendo entrypoint.shque lea las variables de la ENVdefinición para poder usar el mismo enfoque que el ejemplo de MySQL, ¿verdad? Como complemento a su respuesta me encontré con este PR donde al parecer alguien está trabajando en algo similar a la propuesta que acaba de venir desde otro punto de vista
ReynierPM
Las variables de entorno que obtiene de forma predeterminada. set -ehace que todo el script se cierre cuando falla un comando, por lo que el script no puede fallar silenciosamente y arrancar mongo.
Matt
Similar a todos los scripts de compilación de Dockerfile que ve que se usan en &&todas partes.
Matt
¡Ese mongo PR es una implementación mucho más completa! y el docker-entrypoint-initdb.ddirectorio lo hace extensible. Espero que se fusionen
Matt
Se fusionó (ver aquí )
ReynierPM
90

Aquí otra solución más limpia usando docker-composeun jsscript.

Este ejemplo asume que ambos archivos (docker-compose.yml y mongo-init.js) se encuentran en la misma carpeta.

docker-compose.yml

version: '3.7'

services:
    mongodb:
        image: mongo:latest
        container_name: mongodb
        restart: always
        environment:
            MONGO_INITDB_ROOT_USERNAME: <admin-user>
            MONGO_INITDB_ROOT_PASSWORD: <admin-password>
            MONGO_INITDB_DATABASE: <database to create>
        ports:
            - 27017:27017
        volumes:
            - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro

mongo-init.js

db.createUser(
        {
            user: "<user for database which shall be created>",
            pwd: "<password of user>",
            roles: [
                {
                    role: "readWrite",
                    db: "<database to create>"
                }
            ]
        }
);

Luego, simplemente inicie el servicio ejecutando el siguiente comando docker-compose

docker-compose up --build -d mongodb 

Nota : El código de la carpeta docker-entrypoint-init.d solo se ejecuta si la base de datos nunca se ha inicializado antes.

Paul Wasilewski
fuente
Debe reemplazar todos los valores <> en el fragmento con su configuración.
Paul Wasilewski
4
¿Qué es mongo-init.js: ro?
Heril Muratovic
9
@HerilMuratovic, la volumesentrada ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:rovincula el archivo local ./mongo-init.jsa la ruta del contenedor /docker-entrypoint-initdb.d/mongo-init.jscomo de solo lectura ro. Puede encontrar más detalles sobre cómo usar los volúmenes aquí: docs.docker.com/storage/volumes
Paul Wasilewski
2
@GustavoSilva Estoy absolutamente seguro de que está funcionando. Parece que el archivo de composición de la ventana acoplable y el script js no están en la misma carpeta. ¿O estás trabajando en Windows? Luego, ajuste la volumesopción y agregue la ruta absoluta al mongo-init.jsarchivo, por ejemplo c:\docker\mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro.
Paul Wasilewski
1
¿Qué es DB? El código me parece incompleto, ¿es esa la conexión de la mangosta?
andrevenancio
51

Aquí hay una solución funcional que crea un admin-userusuario con una contraseña, una base de datos adicional ( test-database) y test-useren esa base de datos.

Dockerfile:

FROM mongo:4.0.3

ENV MONGO_INITDB_ROOT_USERNAME admin-user
ENV MONGO_INITDB_ROOT_PASSWORD admin-password
ENV MONGO_INITDB_DATABASE admin

ADD mongo-init.js /docker-entrypoint-initdb.d/

mongo-init.js:

db.auth('admin-user', 'admin-password')

db = db.getSiblingDB('test-database')

db.createUser({
  user: 'test-user',
  pwd: 'test-password',
  roles: [
    {
      role: 'root',
      db: 'test-database',
    },
  ],
});

La parte complicada fue entender que los archivos * .js se ejecutaron sin autenticar. La solución autentica el script como admin-useren la adminbase de datos. MONGO_INITDB_DATABASE admines esencial, de lo contrario, el script se ejecutaría contra la base de datos test. Verifique el código fuente de docker-entrypoint.sh .

Mateusz Stefek
fuente
1
¿Hay un error tipográfico en los roles? db debería ser test-database?
Winster
45

La imagen de Mongo puede verse afectada por una MONGO_INITDB_DATABASE variable , pero no creará la base de datos. Esta variable determina la base de datos actual al ejecutar /docker-entrypoint-initdb.d/* scripts . Como no puede usar variables de entorno en scripts ejecutados por Mongo, elegí un script de shell:

docker-swarm.yml:

version: '3.1'

secrets:
  mongo-root-passwd:
    file: mongo-root-passwd
  mongo-user-passwd:
    file: mongo-user-passwd

services:
  mongo:
    image: mongo:3.2
    environment:
      MONGO_INITDB_ROOT_USERNAME: $MONGO_ROOT_USER
      MONGO_INITDB_ROOT_PASSWORD_FILE: /run/secrets/mongo-root-passwd
      MONGO_INITDB_USERNAME: $MONGO_USER
      MONGO_INITDB_PASSWORD_FILE: /run/secrets/mongo-user-passwd
      MONGO_INITDB_DATABASE: $MONGO_DB
    volumes:
      - ./init-mongo.sh:/docker-entrypoint-initdb.d/init-mongo.sh
    secrets:
      - mongo-root-passwd
      - mongo-user-passwd

init-mongo.sh:

mongo -- "$MONGO_INITDB_DATABASE" <<EOF
    var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
    var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
    var admin = db.getSiblingDB('admin');
    admin.auth(rootUser, rootPassword);

    var user = '$MONGO_INITDB_USERNAME';
    var passwd = '$(cat "$MONGO_INITDB_PASSWORD_FILE")';
    db.createUser({user: user, pwd: passwd, roles: ["readWrite"]});
EOF

Alternativamente, puede almacenar init-mongo.shen configs ( docker config create) y montarlo con:

configs:
    init-mongo.sh:
        external: true
...
services:
    mongo:
        ...
        configs:
            - source: init-mongo.sh
              target: /docker-entrypoint-initdb.d/init-mongo.sh

Y los secretos no se pueden almacenar en un archivo.

Un par de ideas al respecto.

x-yuri
fuente
9
Pasé 3 horas buscando cómo crear mi propia base de datos inicialmente. Es una locura que la documentación no mencione que necesita autenticarse dentro de los archivos .js o .sh. Los ejemplos en Internet no están completos en absoluto. Literalmente necesitas profundizar en su script .sh para concluir cómo escribir estas cosas. Cómo "crear una base de datos vacía" cuando se inicia el contenedor. Debería crearse un RP para que esto se simplifique. Un poco loco si me preguntas.
fresco
1
Pasé horas buscando una solución a este problema. Esto me acaba de salvar. Gracias.
NaijaProgrammer
$(cat "$MONGO_INITDB_ROOT_PASSWORD_FILE")Debería reemplazarse por $MONGO_INITDB_ROOT_PASSWORDestos días porque la imagen de Mongo ya maneja el secreto por nosotros. hub.docker.com/_/mongo
FlippingBinary
También fue así en 3.2 . Probablemente no me di cuenta.
x-yuri
13

En caso de que alguien esté buscando cómo configurar MongoDB con autenticación usando docker-compose, aquí hay una configuración de muestra usando variables de entorno:

version: "3.3"

services:

  db:
      image: mongo
      environment:
        - MONGO_INITDB_ROOT_USERNAME=admin
        - MONGO_INITDB_ROOT_PASSWORD=<YOUR_PASSWORD>
      ports:
        - "27017:27017"

Cuando se ejecuta, docker-compose upsu instancia de mongo se ejecuta automáticamente con la autenticación habilitada. Tendrá una base de datos de administrador con la contraseña proporcionada.

usuario2350644
fuente
3
mongo --username admin --password password --host localhost --port 27017No puedo conectarme porque los registros muestran a los usuarios y la base de datos se ha creado correctamente. ERROR:$ mongo --username admin --password password --host localhost --port 27017 MongoDB shell version v3.4.10 connecting to: mongodb://localhost:27017/ MongoDB server version: 3.6.5 WARNING: shell and server versions do not match 2018-06-07T13:05:09.022+0000 E QUERY [thread1] Error: Authentication failed. : DB.prototype._authOrThrow@src/mongo/shell/db.js:1461:20 @(auth):6:1 @(auth):1:2 exception: login failed
Tara Prasad Gurung
1
necesitas mongo admin --username ADMIN --password PASSWORTconectarte a tu instancia de mongo.
Philipp Schemel
1
No puedo hacer que esto funcione. "No se pudo encontrar el usuario admin @ admin". ¿No parece crear automáticamente el usuario?
batjko
mongodb://root:example@localhost/my-db?authSource=admin
FDisk
@TaraPrasadGurung Tuve este problema, noté que ya tenía un volumen creado para la base de datos, tienes que eliminar este volumen para que el contenedor cree un nuevo usuario.
Daniel S.
5

Si está buscando eliminar nombres de usuario y contraseñas de su docker-compose.yml, puede usar Docker Secrets , así es como lo he abordado.

version: '3.6'

services:
  db:
    image: mongo:3
    container_name: mycontainer
  secrets:
    - MONGO_INITDB_ROOT_USERNAME
    - MONGO_INITDB_ROOT_PASSWORD
  environment:
    - MONGO_INITDB_ROOT_USERNAME_FILE=/var/run/secrets/MONGO_INITDB_ROOT_USERNAME
    - MONGO_INITDB_ROOT_PASSWORD_FILE=/var/run/secrets/MONGO_INITDB_ROOT_PASSWORD
secrets:
  MONGO_INITDB_ROOT_USERNAME:
    file:  secrets/${NODE_ENV}_mongo_root_username.txt
  MONGO_INITDB_ROOT_PASSWORD:
    file:  secrets/${NODE_ENV}_mongo_root_password.txt

He usado la opción file: para mis secretos, sin embargo, también puedes usar external: y usar los secretos en un enjambre.

Los secretos están disponibles para cualquier script en el contenedor en / var / run / secrets

La documentación de Docker tiene esto que decir sobre el almacenamiento de datos confidenciales ...

https://docs.docker.com/engine/swarm/secrets/

Puede usar secretos para administrar los datos confidenciales que necesita un contenedor en tiempo de ejecución, pero no desea almacenarlos en la imagen o en el control de fuente, como:

Nombres de usuario y contraseñas Certificados y claves TLS Claves SSH Otros datos importantes como el nombre de una base de datos o un servidor interno Cadenas genéricas o contenido binario (hasta 500 kb de tamaño)

inglés Pete
fuente
3

Dado este .envarchivo:

DB_NAME=foo
DB_USER=bar
DB_PASSWORD=baz

Y este mongo-init.sharchivo:

mongo --eval "db.auth('$MONGO_INITDB_ROOT_USERNAME', '$MONGO_INITDB_ROOT_PASSWORD'); db = db.getSiblingDB('$DB_NAME'); db.createUser({ user: '$DB_USER', pwd: '$DB_PASSWORD', roles: [{ role: 'readWrite', db: '$DB_NAME' }] });"

Esto docker-compose.ymlcreará la base de datos de administrador y el usuario de administrador, se autenticará como el usuario de administrador, luego creará la base de datos real y agregará el usuario real:

version: '3'

services:
#  app:
#    build: .
#    env_file: .env
#    environment:
#      DB_HOST: 'mongodb://mongodb'

  mongodb:
    image: mongo:4
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin-user
      MONGO_INITDB_ROOT_PASSWORD: admin-password
      DB_NAME: $DB_NAME
      DB_USER: $DB_USER
      DB_PASSWORD: $DB_PASSWORD
    ports:
      - 27017:27017
    volumes:
      - db-data:/data/db
      - ./mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh

volumes:
  db-data:
Alf Eaton
fuente