Wie erstelle ich beim Start einen DB für MongoDB-Container?

81

Ich arbeite mit Docker und habe einen Stack mit PHP, MySQL, Apache und Redis. Ich brauche MongoDB jetzt hinzufügen , damit ich die Überprüfung Dockerfile für die neueste Version und auch die docker-entrypoint.sh Datei aus dem MongoDB Dockerhub aber ich konnte nicht einen Weg , um das Einrichten eines Standard - DB, Admin - Benutzer / Passwort und möglicherweise Auth finden Methode für den Container aus einer docker-compose.ymlDatei.

In MySQL können Sie einige ENV-Variablen wie folgt einrichten:

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}

Dadurch werden die Datenbank und der Benutzer / das Kennwort als rootKennwort eingerichtet.

Gibt es eine Möglichkeit, dies mit MongoDB zu erreichen? Hat jemand Erfahrung oder Problemumgehung?

ReynierPM
quelle
Können Sie einen auf MySQL basierenden Container erstellen und nach Ihren Wünschen einrichten und dann verwenden?
Valentin
@ Valentin natürlich kann ich aber was ist dein Punkt?
ReynierPM
Mein Punkt ist, dass Sie eine Standard-DB, einen Administrator-Benutzer / ein Administrator-Passwort und möglicherweise eine Auth-Methode in der Docker-Datei mithilfe von Variablen einrichten und diese dann in der Compose-Datei übergeben können
Valentin
Hinweis: Wenn Sie eine der Lösungen verwenden, die das Mongo-Init-Skript verwenden, stellen Sie bitte sicher, dass Sie den Neustart festlegen: sofern nicht gestoppt (oder etwas anderes als Nein) für Container, die von Mongo abhängig sind. Dies liegt daran, dass diese Container beim ersten Initialisieren keine Verbindung zu Mongo herstellen können (auch mit dem Flag "Dependates_on"). Weitere Informationen finden
java-addict301

Antworten:

90

Das offizielle mongoImage hat eine PR zusammengeführt, um die Funktionalität zum Erstellen von Benutzern und Datenbanken beim Start einzuschließen.

Die Datenbankinitialisierung wird ausgeführt, wenn das /data/dbVerzeichnis nichts enthält .

Admin User Setup

Die Umgebungsvariablen zur Steuerung des Benutzer-Setups "root" sind:

  • MONGO_INITDB_ROOT_USERNAME
  • MONGO_INITDB_ROOT_PASSWORD

Beispiel

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

Sie müssen / können nicht --authin der Befehlszeile verwenden, da das Docker-Skript entrypoint.sh dies hinzufügt, wenn die Umgebungsvariablen vorhanden sind.

Datenbankinitialisierung

Das Image enthält auch den /docker-entrypoint-initdb.d/Pfad zum Bereitstellen von benutzerdefinierten .jsoder .shSetup-Skripten, die bei der Datenbankinitialisierung einmal ausgeführt werden. .jsSkripte werden teststandardmäßig oder MONGO_INITDB_DATABASEin der Umgebung definiert ausgeführt.

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

oder

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

Eine einfache Javascript- Datei für die Mongo-Shell zur Initialisierung , die das Einrichten der containerSammlung mit Daten, die Protokollierung und das Beenden mit einem Fehler (zur Ergebnisprüfung) demonstriert .

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)
}
Matt
quelle
Das ist exzellent, ich nehme an, es set -eheißt, entrypoint.shVariablen aus der ENVDefinition zu lesen, damit ich den gleichen Ansatz wie im Beispiel von MySQL verwenden kann. Als Ergänzung zu Ihrer Antwort habe ich diese PR gefunden, in der anscheinend jemand in etwas ähnlichem wie Ihrem Vorschlag arbeitet, nur aus einem anderen Blickwinkel
ReynierPM
Die Umgebungsvariablen, die Sie standardmäßig erhalten. set -ebewirkt, dass das gesamte Skript beendet wird, wenn ein Befehl fehlschlägt, sodass das Skript nicht stillschweigend fehlschlagen und mongo starten kann.
Matt
Ähnlich wie bei allen Dockerfile-Build-Skripten, die &&überall verwendet werden.
Matt
Diese Mongo-PR ist eine viel gründlichere Implementierung! und das docker-entrypoint-initdb.dVerzeichnis macht es erweiterbar. Ich hoffe, dass das zusammengeführt wird
Matt
Es ist zusammengeführt (siehe hier )
ReynierPM
89

Hier eine weitere sauberere Lösung mit docker-composeund einem jsSkript.

In diesem Beispiel wird davon ausgegangen, dass sich beide Dateien (docker-compose.yml und mongo-init.js) im selben Ordner befinden.

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>"
                }
            ]
        }
);

Starten Sie dann einfach den Dienst, indem Sie den folgenden Docker-Compose-Befehl ausführen

docker-compose up --build -d mongodb 

Hinweis : Der Code im Ordner docker-entrypoint-init.d wird nur ausgeführt, wenn die Datenbank noch nie zuvor initialisiert wurde.

Paul Wasilewski
quelle
Sie müssen alle <> Werte im Snippet durch Ihre Einstellungen ersetzen.
Paul Wasilewski
4
Was ist mongo-init.js: ro?
Heril Muratovic
9
@HerilMuratovic, der volumesEintrag ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:roverknüpft die lokale Datei schreibgeschützt ./mongo-init.jsmit dem Containerpfad . Weitere Informationen zur Verwendung von Volumes finden Sie hier: docs.docker.com/storage/volumes/docker-entrypoint-initdb.d/mongo-init.jsro
Paul Wasilewski
2
@GustavoSilva Ich bin absolut sicher, dass es funktioniert. Es scheint, dass sich Ihre Docker-Erstellungsdatei und das js-Skript nicht im selben Ordner befinden. Oder arbeitest du an Windows? Passen Sie dann bitte die volumesOption an und fügen Sie beispielsweise den absoluten Pfad zur mongo-init.jsDatei hinzu c:\docker\mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro.
Paul Wasilewski
1
Was ist db? Der Code scheint mir unvollständig, ist das die Mungo-Verbindung?
andrevenancio
51

Hier ist eine funktionierende Lösung, die admin-userBenutzer mit einem Kennwort, einer zusätzlichen Datenbank ( test-database) und test-userin dieser Datenbank erstellt.

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',
    },
  ],
});

Der schwierige Teil war zu verstehen, dass * .js-Dateien nicht authentifiziert ausgeführt wurden. Die Lösung authentifiziert das Skript als admin-userin der adminDatenbank. MONGO_INITDB_DATABASE administ wichtig, sonst würde das Skript gegen die testDatenbank ausgeführt. Überprüfen Sie den Quellcode von docker-entrypoint.sh .

Mateusz Stefek
quelle
1
Gibt es einen Tippfehler in den Rollen? db sollte test-datenbank sein?
Winster
45

Das Mongo-Bild kann von MONGO_INITDB_DATABASE Variablen beeinflusst werden, die Datenbank wird jedoch nicht erstellt. Diese Variable bestimmt die aktuelle Datenbank beim Ausführen von /docker-entrypoint-initdb.d/* Skripten . Da Sie in von Mongo ausgeführten Skripten keine Umgebungsvariablen verwenden können, habe ich mich für ein Shell-Skript entschieden:

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

Alternativ können Sie init-mongo.shin configs ( docker config create) speichern und es einbinden mit:

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

Und Geheimnisse können nicht in einer Datei gespeichert werden.

Ein paar von Logen über die Angelegenheit.

x-yuri
quelle
9
Ich habe gerade 3 Stunden damit verbracht, zu suchen, wie ich meine eigene Datenbank erstellen kann. Verrückt, dass in der Dokumentation nicht erwähnt wird, dass Sie sich in .js- oder .sh-Dateien authentifizieren müssen. Beispiele über das Internet sind überhaupt nicht vollständig. Sie müssen buchstäblich in ihr .sh-Skript eintauchen, um zu schließen, wie man dieses Zeug schreibt. So erstellen Sie eine leere Datenbank, wenn der Container gestartet wird. PR sollte erstellt werden, um dies zu vereinfachen. Ein bisschen verrückt, wenn du mich fragst.
cool
1
Ich habe stundenlang nach einer Lösung für dieses Problem gesucht. Das hat mich nur gerettet. Vielen Dank.
NaijaProgrammer
$(cat "$MONGO_INITDB_ROOT_PASSWORD_FILE")sollte durch $MONGO_INITDB_ROOT_PASSWORDdiese Tage ersetzt werden, da das Mongo-Bild bereits das Geheimnis für uns behandelt. hub.docker.com/_/mongo
FlippingBinary
So war es auch in 3.2 . Ich habe es wahrscheinlich nicht bemerkt.
x-yuri
13

Für den Fall, dass jemand nach einer Konfiguration von MongoDB mit Authentifizierung mithilfe von sucht docker-compose, finden Sie hier eine Beispielkonfiguration mit Umgebungsvariablen:

version: "3.3"

services:

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

Beim Ausführen wird docker-compose upIhre Mongo-Instanz automatisch mit aktivierter Authentifizierung ausgeführt. Sie haben eine Admin-Datenbank mit dem angegebenen Passwort.

user2350644
quelle
3
mongo --username admin --password password --host localhost --port 27017Ich kann keine Verbindung herstellen, da die Protokolle die Benutzer anzeigen und die Datenbank erfolgreich erstellt wurde. FEHLER:$ 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
Sie müssen eine mongo admin --username ADMIN --password PASSWORTVerbindung zu Ihrer Mongo-Instanz herstellen.
Philipp Schemel
1
Kann das nicht zum Laufen bringen. "Benutzer admin @ admin konnte nicht gefunden werden". Es scheint nicht automatisch den Benutzer zu erstellen?
Batjko
mongodb://root:example@localhost/my-db?authSource=admin
FDisk
@TaraPrasadGurung Ich hatte dieses Problem, bemerkte, dass ich bereits ein Volume für die Datenbank erstellt hatte. Sie müssen dieses Volume löschen, damit der Container einen neuen Benutzer erstellt.
Daniel S.
5

Wenn Sie Benutzernamen und Passwörter aus Ihrer docker-compose.yml entfernen möchten, können Sie Docker Secrets verwenden . So habe ich es angegangen.

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

Ich habe die Option file: für meine Geheimnisse verwendet, Sie können jedoch auch external: verwenden und die Geheimnisse in einem Schwarm verwenden.

Die Geheimnisse stehen jedem Skript im Container unter / var / run / Secrets zur Verfügung

In der Docker-Dokumentation wird Folgendes zum Speichern vertraulicher Daten angegeben ...

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

Sie können Geheimnisse verwenden, um vertrauliche Daten zu verwalten, die ein Container zur Laufzeit benötigt, die Sie jedoch nicht im Image oder in der Quellcodeverwaltung speichern möchten, z.

Benutzernamen und Passwörter TLS-Zertifikate und -Schlüssel SSH-Schlüssel Andere wichtige Daten wie der Name einer Datenbank oder eines internen Servers Generische Zeichenfolgen oder binäre Inhalte (bis zu 500 KB groß)

englishPete
quelle
3

Angesichts dieser .envDatei:

DB_NAME=foo
DB_USER=bar
DB_PASSWORD=baz

Und diese mongo-init.shDatei:

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' }] });"

Dadurch docker-compose.ymlwerden die Administratordatenbank und der Administratorbenutzer erstellt, als Administratorbenutzer authentifiziert, dann die reale Datenbank erstellt und der reale Benutzer hinzugefügt:

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
quelle