Jak utworzyć bazę danych dla kontenera MongoDB przy uruchomieniu?

87

Pracuję z Dockerem i mam stos z PHP, MySQL, Apache i Redis. Muszę teraz dodać MongoDB, więc sprawdzałem plik Dockerfile pod kątem najnowszej wersji, a także plik docker-entrypoint.sh z MongoDB Dockerhub, ale nie mogłem znaleźć sposobu na skonfigurowanie domyślnej bazy danych, użytkownika / hasła administratora i prawdopodobnie autoryzacji metoda dla kontenera z docker-compose.ymlpliku.

W MySQL możesz ustawić niektóre zmienne ENV, na przykład:

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}

I to ustawi bazę danych i użytkownika / hasło jako roothasło.

Czy jest jakiś sposób na osiągnięcie tego samego w MongoDB? Czy ktoś ma jakieś doświadczenie lub obejście?

ReynierPM
źródło
czy możesz stworzyć kontener w oparciu o mysql i skonfigurować go tak, jak chcesz, a następnie go używać?
Valentin
@Valentin oczywiście, ale o co ci chodzi?
ReynierPM
Chodzi mi o to, że możesz ustawić domyślną bazę danych, użytkownika / hasło administratora i prawdopodobnie metodę uwierzytelniania w pliku dockerfile za pomocą zmiennych, a następnie przekazać je w pliku redagowania
Valentin
Uwaga: Jeśli używasz któregokolwiek z rozwiązań, które używają skryptu mongo-init, upewnij się, że ustawiłeś restart: chyba, że ​​zatrzymano (lub coś poza nie) dla kontenerów zależnych od mongo. Dzieje się tak, ponieważ te kontenery nie będą mogły połączyć się z mongo za pierwszym razem podczas jego inicjalizacji (nawet z flagą depend_on). Zobacz ten wątek, aby poznać szczegóły stackoverflow.com/questions/31746182/…
java-addict301

Odpowiedzi:

98

Oficjalny mongoobraz jest połączone PR obejmuje funkcjonalność do tworzenia użytkowników i baz danych przy starcie.

Inicjalizacja bazy danych rozpocznie się, gdy w /data/dbkatalogu nie ma żadnych danych .

Konfiguracja użytkownika administratora

Zmienne środowiskowe kontrolujące ustawienia użytkownika „root” to

  • MONGO_INITDB_ROOT_USERNAME
  • MONGO_INITDB_ROOT_PASSWORD

Przykład

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

Nie musisz / nie możesz używać --authw wierszu poleceń, ponieważ skrypt docker entrypoint.sh dodaje to, gdy istnieją zmienne środowiskowe.

Inicjalizacja bazy danych

Obraz zawiera również /docker-entrypoint-initdb.d/ścieżkę do wdrażania niestandardowych .jslub .shkonfiguracyjnych skryptów, które zostaną uruchomione po zainicjowaniu bazy danych. .jsskrypty będą uruchamiane testdomyślnie lub MONGO_INITDB_DATABASEjeśli zostały zdefiniowane w środowisku.

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

lub

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

Prosty plik inicjalizacyjny powłoki mongo javascript , który demonstruje konfigurację containerkolekcji z danymi, rejestrowanie i jak wyjść z błędem (w celu sprawdzenia wyników).

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
źródło
To jest doskonałe, przypuszczam, że set -enakazuje entrypoint.shodczytać zmienne z ENVdefinicji, więc mogę użyć tego samego podejścia, co w przykładzie z MySQL, mam rację? Jako dodatek do twojej odpowiedzi znalazłem ten PR, w którym najwyraźniej ktoś pracuje nad czymś podobnym do twojej propozycji, wychodząc z innego punktu widzenia
ReynierPM
Zmienne środowiskowe, które otrzymujesz domyślnie. set -epowoduje, że cały skrypt kończy pracę, gdy polecenie zawiedzie, więc skrypt nie może po cichu zawieść i uruchomić mongo.
Matt
Podobnie jak wszystkie skrypty kompilacji Dockerfile, które są używane &&wszędzie.
Matt
Ten mongo PR to znacznie dokładniejsza realizacja! a docker-entrypoint-initdb.dkatalog czyni go rozszerzalnym. Mam nadzieję, że get się połączyło
Matt
Jest scalony (patrz tutaj )
ReynierPM
99

Tutaj kolejne czystsze rozwiązanie przy użyciu docker-composei jsskryptu.

W tym przykładzie założono, że oba pliki (docker-compose.yml i mongo-init.js) znajdują się w tym samym folderze.

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

Następnie po prostu uruchom usługę, uruchamiając następujące polecenie docker-compose

docker-compose up --build -d mongodb 

Uwaga : Kod w folderze docker-entrypoint-init.d jest wykonywany tylko wtedy, gdy baza danych nigdy wcześniej nie została zainicjowana.

Paul Wasilewski
źródło
Musisz zamienić wszystkie wartości <> we fragmencie na swoje ustawienia.
Paul Wasilewski
6
co to jest mongo-init.js: ro?
Heril Muratovic
11
@HerilMuratovic, volumeswpis ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:rołączy plik lokalny ./mongo-init.jsze ścieżką kontenera /docker-entrypoint-initdb.d/mongo-init.jsjako tylko do odczytu ro. Więcej informacji na temat korzystania z woluminów można znaleźć tutaj: docs.docker.com/storage/volumes
Paul Wasilewski
2
@GustavoSilva Jestem absolutnie pewien, że działa. Wygląda na to, że twój plik redagowania dockera i skrypt js nie znajdują się w tym samym folderze. A może pracujesz nad oknami? Następnie dostosuj volumesopcję i dodaj na przykład bezwzględną ścieżkę do mongo-init.jspliku c:\docker\mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro.
Paul Wasilewski
1
Co to jest db? Kod wydaje mi się niekompletny, czy to połączenie mangusty?
andrevenancio
55

Oto działające rozwiązanie, które tworzy admin-userużytkownika z hasłem, dodatkową bazą danych ( test-database) oraz test-userw tej bazie danych.

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

Najtrudniejsze było zrozumienie, że pliki * .js były uruchamiane bez uwierzytelnienia. Rozwiązanie uwierzytelnia skrypt jako plik admin-userw adminbazie danych. MONGO_INITDB_DATABASE adminjest niezbędna, w przeciwnym razie skrypt zostałby wykonany na testbazie danych. Sprawdź kod źródłowy docker-entrypoint.sh .

Mateusz Stefek
źródło
1
Czy w rolach jest literówka? db powinna być testową bazą danych?
Winster
Dwa komentarze do drugiej linii, która zawiera getSiblingDB. Po pierwsze, w moim teście wszystko działało bez tej linii. Po drugie, nadpisanie zmiennej db w ten sposób wydaje się złą formą, ponieważ jest ona uważana za obiekt globalny i nadpisanie jej zmienia kontekst wszystkiego.
Lazor
50

UPD Dzisiaj unikać Docker Swarm, tajemnice i configs. Chciałbym uruchomić go docker-composei .envplików. O ile nie potrzebuję autoskalowania. Gdybym to zrobił, prawdopodobnie wybrałbym k8s. A hasła do bazy danych, konto root czy nie… Czy naprawdę mają znaczenie, gdy używasz pojedynczej bazy danych w kontenerze niepołączonym ze światem zewnętrznym? .. Chciałbym wiedzieć, co o tym myślisz, ale Stack Overflow prawdopodobnie nie nadaje się dobrze do tego rodzaju komunikacji.

MONGO_INITDB_DATABASE Zmienna może mieć wpływ na obraz Mongo , ale nie utworzy bazy danych. Ta zmienna określa bieżącą bazę danych podczas uruchamiania /docker-entrypoint-initdb.d/* skryptów . Ponieważ nie możesz używać zmiennych środowiskowych w skryptach wykonywanych przez Mongo, wybrałem skrypt powłoki:

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

Alternatywnie możesz przechowywać init-mongo.shw configs ( docker config create) i zamontować za pomocą:

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

A sekretów nie można przechowywać w pliku.

Para z GIST w tej sprawie.

x-yuri
źródło
11
Właśnie spędziłem 3 godziny na poszukiwaniu, jak początkowo utworzyć własną bazę danych. Szalone, że dokumentacja nie wspomina o konieczności uwierzytelniania w plikach .js lub .sh. Przykłady w Internecie nie są w ogóle kompletne. Dosłownie musisz zagłębić się w ich skrypt .sh, aby wywnioskować, jak napisać te rzeczy. Jak „utworzyć pustą bazę danych” po uruchomieniu kontenera. Aby to uprościć, należy stworzyć PR. Trochę szalone, jeśli o mnie chodzi.
fajne
1
Godzinami szukałem rozwiązania tego problemu. To mnie właśnie uratowało. Dziękuję Ci.
NaijaProgrammer
$(cat "$MONGO_INITDB_ROOT_PASSWORD_FILE")Powinien zostać zastąpiony $MONGO_INITDB_ROOT_PASSWORDtymi dniami, ponieważ obraz Mongo już obsługuje sekret za nas. hub.docker.com/_/mongo
FlippingBinary
Tak też było w 3.2 . Prawdopodobnie nie zauważyłem.
x-yuri
@ x-yuri Jaka jest korzyść z używania konfiguracji dla init-mongo.sh, zamiast po prostu kopiowania pliku do docker-entrypoint-initdb.d i pozwalania mu na automatyczne uruchamianie?
Lazor
13

Jeśli ktoś szuka sposobu konfiguracji MongoDB z uwierzytelnianiem docker-compose, oto przykładowa konfiguracja z wykorzystaniem zmiennych środowiskowych:

version: "3.3"

services:

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

Podczas uruchamiania docker-compose upinstancja mongo jest uruchamiana automatycznie z włączoną autoryzacją. Będziesz mieć bazę danych administratora z podanym hasłem.

user2350644
źródło
3
mongo --username admin --password password --host localhost --port 27017nie mogę się połączyć, ponieważ dzienniki pokazują użytkowników, a baza danych została pomyślnie utworzona. BŁĄD:$ 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
musisz mongo admin --username ADMIN --password PASSWORTpołączyć się ze swoją instancją mongo.
Philipp Schemel
1
Nie mogę tego zmusić do działania. „Nie można znaleźć użytkownika admin @ admin”. Wydaje się, że nie tworzy automatycznie użytkownika?
batjko
mongodb://root:example@localhost/my-db?authSource=admin
FDisk
@TaraPrasadGurung Miałem ten problem, zauważyłem, że mam już utworzony wolumen dla bazy danych, musisz usunąć ten wolumin, aby kontener mógł utworzyć nowego użytkownika.
Daniel S.
5

Jeśli chcesz usunąć nazwy użytkowników i hasła ze swojego pliku docker-compose.yml, możesz użyć Docker Secrets , oto jak do tego przystąpiłem.

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

Ja korzystam z opcji file: dla moich sekretów, jednak możesz też użyć zewnętrznego: i używać sekretów w roju.

Sekrety są dostępne dla każdego skryptu w kontenerze w / var / run / secrets

Dokumentacja Dockera ma to do powiedzenia na temat przechowywania poufnych danych ...

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

Możesz używać wpisów tajnych do zarządzania dowolnymi poufnymi danymi, których kontener potrzebuje w czasie wykonywania, ale nie chcesz przechowywać ich w obrazie ani w kontroli źródła, na przykład:

Nazwy użytkowników i hasła Certyfikaty i klucze TLS Klucze SSH Inne ważne dane, takie jak nazwa bazy danych lub serwera wewnętrznego Ogólne ciągi znaków lub zawartość binarna (do 500 kb)

angielskiPete
źródło
4

Biorąc pod uwagę ten .envplik:

DB_NAME=foo
DB_USER=bar
DB_PASSWORD=baz

A ten mongo-init.shplik:

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

Spowoduje docker-compose.ymlto utworzenie bazy danych administratora i użytkownika administratora, uwierzytelnienie jako administrator, a następnie utworzenie prawdziwej bazy danych i dodanie prawdziwego użytkownika:

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
źródło