Як створити БД для контейнера MongoDB при запуску?


87

Я працюю з Docker і маю стек з PHP, MySQL, Apache та Redis. Мені потрібно додати MongoDB зараз, тому я перевіряв Dockerfile на останню версію, а також файл docker-entrypoint.sh з MongoDB Dockerhub, але я не міг знайти спосіб встановити БД за замовчуванням, користувача / пароль адміністратора і, можливо, автентифікацію метод для контейнера з docker-compose.ymlфайлу.

У MySQL ви можете встановити деякі змінні ENV, наприклад:

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}

І це встановить БД та користувача / пароль як rootпароль.

Чи є спосіб досягти цього з MongoDB? Хтось має певний досвід чи обхідний шлях?


Ви можете створити контейнер на основі mysql і встановити його як завгодно, а потім використовувати?
Валентин

@Valentin, звичайно, можу, але в чому ваша думка?
ReynierPM

Я хочу сказати, що ви можете встановити БД за замовчуванням, користувача / пароль адміністратора та, можливо, метод автентифікації у файлі docker, використовуючи змінні, а потім передавати їх у файл створення
Валентин,

Примітка: Якщо ви використовуєте будь-яке рішення, яке використовує скрипт mongo-init, переконайтеся, що ви встановили перезапуск: хіба що зупинено (або щось крім ні) для контейнерів, залежних від mongo. Це пов’язано з тим, що ці контейнери не зможуть підключитися до mongo вперше під час її ініціалізації (навіть із прапором depend_on). Дивіться цю гілку для деталей stackoverflow.com/questions/31746182 / ...
Java-addict301

Відповіді:


98

Офіційне mongoзображення вже злитий в PR , щоб включити функціональні можливості для створення користувачів і баз даних при запуску.

Ініціалізація бази даних буде виконуватися, коли в /data/dbкаталозі нічого не заповнено .

Налаштування адміністратора

Змінні середовища для управління "кореневим" налаштуванням користувача є

  • MONGO_INITDB_ROOT_USERNAME
  • MONGO_INITDB_ROOT_PASSWORD

Приклад

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

Вам не потрібно / не можна використовувати --authв командному рядку, оскільки скрипт docker entrypoint.sh додає це, коли існують змінні середовища.

Ініціалізація бази даних

Зображення також надає /docker-entrypoint-initdb.d/шлях до розгортання настроюваних сценаріїв .jsабо .shсценаріїв налаштування, які будуть запускатися один раз при ініціалізації бази даних. .jsсценарії запускатимуться testза замовчуванням або MONGO_INITDB_DATABASEякщо вони визначені в середовищі.

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

або

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

Простий файл javascript оболонки mongo, який демонструє налаштування containerколекції з даними, ведення журналу та спосіб виходу з помилкою (для перевірки результату).

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)
}

Це чудово, я гадаю, set -eце говорить entrypoint.shчитання змінних із ENVвизначення, щоб я міг використовувати той самий підхід, що і приклад з MySQL, я маю рацію? Як доповнення до вашої відповіді я знайшов цей PR, де очевидно хтось працює над чимось подібним до вашої пропозиції, яка просто виходить з іншої точки зору
ReynierPM

Змінні середовища, які ви отримуєте за замовчуванням. set -eзмушує весь сценарій виходити, коли команда не працює, тому сценарій не може мовчки вийти з ладу та запустити mongo.
Метт

Подібно до всіх сценаріїв збірки Dockerfile, які ви бачите &&всюди.
Метт

Цей mongo PR - це набагато більш ретельне впровадження! і docker-entrypoint-initdb.dкаталог робить його розширюваним. Сподіваюся, що get об’єднано
Matt

Він об’єднаний (див. Тут )
ReynierPM

99

Тут ще одне більш чисте рішення за допомогою docker-composeі jsсценарію.

Цей приклад передбачає, що обидва файли (docker-compose.yml та mongo-init.js) лежать в одній папці.

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

Потім просто запустіть службу, виконавши наступну команду docker-compose

docker-compose up --build -d mongodb 

Примітка : Код у папці docker-entrypoint-init.d виконується лише в тому випадку, якщо база даних ніколи раніше не ініціалізувалася.


Вам доведеться замінити всі значення <> у фрагменті своїми налаштуваннями.
Пол Василевський,

6
що таке mongo-init.js: ro?
Гериль Муратович,

11
@HerilMuratovic, volumesзапис посилає ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:roлокальний файл ./mongo-init.jsна шлях контейнера /docker-entrypoint-initdb.d/mongo-init.jsяк лише для читання ro. Детальніше про те, як користуватися томами, ви можете знайти тут: docs.docker.com/storage/volumes
Пол Василевський,

2
@GustavoSilva Я абсолютно впевнений, що це працює. Здається, ваш файл складання докера та скрипт js знаходяться не в одній папці. Або ви працюєте над вікнами? Тоді, будь ласка, налаштуйте volumesпараметр і додайте абсолютний шлях до mongo-init.jsфайлу, наприклад c:\docker\mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro.
Пауль Василевський,

1
Що таке db? Код мені здається неповним, це мангустський зв’язок?
andrevenancio

55

Ось робоче рішення, яке створює admin-userкористувача з паролем, додатковою базою даних ( test-database) і test-userв цій базі даних.

Файл Docker:

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

Хитра частина полягала в тому, щоб зрозуміти, що файли * .js запускаються без аутентифікації. Рішення автентифікує сценарій як admin-userу adminбазі даних. MONGO_INITDB_DATABASE adminмає важливе значення, інакше сценарій буде виконаний проти testdb. Перевірте вихідний код docker-entrypoint.sh .


1
Чи є в ролях друкарська помилка? db має бути тестовою базою даних?
Вінстер

Два коментарі до другого рядка, який має getSiblingDB. По-перше, у моєму тесті все працювало без цього рядка. По-друге, здається поганою формою перезаписувати змінну db так, оскільки вона вважається глобальним об'єктом, а перезапис змінює контекст для всього.
Лазор

50

UPD Сьогодні я уникаю Docker Swarm, секретів та налаштувань. Я б запустив його з docker-composeі.env файл. Поки мені не потрібен автомасштабування. Якби я це зробив, я, мабуть, вибрав би k8s. А паролі бази даних, корінь облікового запису чи ні ... Чи справді вони мають значення, коли ви запускаєте одну базу даних у контейнері, не підключеному до зовнішнього світу? .. Я хотів би знати, що ви думаєте про це, але Stack Overflow мабуть, не дуже підходить для такого роду спілкування.

На зображення Mongo може впливати MONGO_INITDB_DATABASE змінна , але вона не створюватиме базу даних. Ця змінна визначає поточну базу даних під час запуску /docker-entrypoint-initdb.d/* сценаріїв . Оскільки ви не можете використовувати змінні середовища в сценаріях, що виконуються Mongo, я пішов із сценарієм оболонки:

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

Крім того, ви можете зберігати init-mongo.shв configs ( docker config create) і монтувати його за допомогою:

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

І секрети не можна зберігати у файлі.

Пара з г з цього питання.


11
Я просто витратив 3 години на пошуки, як створити власний db спочатку. Божевільний, що в документації не згадується, що вам потрібно пройти автентифікацію у файлах .js або .sh. Приклади через Інтернет взагалі не повні. Вам буквально потрібно заглибитися в їхній .sh-сценарій, щоб зробити висновок, як писати ці речі. Як "створити порожню базу даних" при запуску контейнера. Для спрощення цього слід створити PR. Трохи божевільний, якщо ви запитаєте мене.
круто

1
Я годинами шукав рішення цієї проблеми. Це мене просто врятувало. Дякую.
програміст Naija

$(cat "$MONGO_INITDB_ROOT_PASSWORD_FILE")повинні бути замінені на $MONGO_INITDB_ROOT_PASSWORDці дні, оскільки зображення Монго вже розкриває таємницю для нас. hub.docker.com/_/mongo
FlippingBinary

Так було і в 3.2 . Я, мабуть, не помітив.
x-yuri

@ x-yuri У чому перевага використання конфігурацій для init-mongo.sh, а не просто копіювання файлу в docker-entrypoint-initdb.d і надання йому можливості запускатись там автоматично?
Лазор

13

Якщо хтось шукає, як налаштувати MongoDB з аутентифікацією за допомогою docker-compose, ось зразок конфігурації із використанням змінних середовища:

version: "3.3"

services:

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

При запуску docker-compose upваш екземпляр mongo запускається автоматично з увімкненою автентифікацією. У вас буде база даних адміністратора з вказаним паролем.


3
mongo --username admin --password password --host localhost --port 27017я не можу підключитися, оскільки журнали показують користувачів, і db створено успішно. ПОМИЛКА:$ 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
Тара Прасад Гурунг

1
вам потрібно mongo admin --username ADMIN --password PASSWORTпідключитися до вашого екземпляра mongo.
Філіп Шемел,

1
Не можу змусити це працювати. Msgstr "Не вдалося знайти користувача. Здається, це не створює користувача автоматично?
batjko

mongodb://root:example@localhost/my-db?authSource=admin
FDisk

@TaraPrasadGurung У мене була ця проблема, я помітив, що у мене вже створений том для бази даних, вам потрібно видалити цей том для контейнера, щоб створити нового користувача.
Даніель С.

5

Якщо ви хочете видалити імена користувачів та паролі з вашого docker-compose.yml, ви можете використовувати Docker Secrets , ось як я до цього підійшов.

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

У мене є параметр file: для моїх секретів, однак ви також можете використовувати external: і використовувати секрети в рої.

Секрети доступні для будь-якого сценарію в контейнері за адресою / var / run / secrets

У документації Docker сказано про зберігання конфіденційних даних ...

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

Ви можете використовувати секрети для управління будь-якими конфіденційними даними, які потрібні контейнеру під час виконання, але ви не хочете зберігати їх у зображенні або в контролі джерела, наприклад:

Імена користувачів та паролі Сертифікати та ключі TLS Ключі SSH Інші важливі дані, такі як ім'я бази даних або внутрішнього сервера Загальні рядки або двійковий вміст (розміром до 500 кб)


4

Враховуючи цей .envфайл:

DB_NAME=foo
DB_USER=bar
DB_PASSWORD=baz

І цей mongo-init.shфайл:

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

Це docker-compose.ymlстворить базу даних адміністратора та користувача адміністратора, автентифікується як користувач адміністратора, потім створить реальну базу даних і додасть реального користувача:

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:
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.