Làm cách nào để tạo DB cho vùng chứa MongoDB khi khởi động?


83

Tôi đang làm việc với Docker và tôi có một ngăn xếp với PHP, MySQL, Apache và Redis. Tôi cần thêm MongoDB ngay bây giờ vì vậy tôi đang kiểm tra Dockerfile cho phiên bản mới nhất và cũng như tệp docker-entrypoint.sh từ MongoDB Dockerhub nhưng tôi không thể tìm thấy cách thiết lập DB mặc định, người dùng / mật khẩu quản trị và có thể là xác thực cho vùng chứa từ một docker-compose.ymltệp.

Trong MySQL, bạn có thể thiết lập một số biến ENV, chẳng hạn như:

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}

Và điều này sẽ thiết lập DB và người dùng / mật khẩu làm rootmật khẩu.

Có cách nào để đạt được điều tương tự với MongoDB không? Bất cứ ai có một số kinh nghiệm hoặc cách giải quyết?


bạn có thể tạo một vùng chứa dựa trên mysql và thiết lập nó như bạn muốn rồi sử dụng nó không?
Valentin ngày

@Valentin tất nhiên tôi có thể nhưng ý của bạn là gì?
ReynierPM

Quan điểm của tôi là bạn có thể thiết lập DB mặc định, người dùng / mật khẩu quản trị và có thể là phương thức auth trong dockerfile bằng cách sử dụng các biến và sau đó chuyển chúng vào tệp soạn thảo
Valentin

Lưu ý: Nếu sử dụng bất kỳ giải pháp nào sử dụng tập lệnh mongo-init, vui lòng đảm bảo bạn đặt khởi động lại: trừ khi dừng (hoặc điều gì đó ngoài không) cho các vùng chứa phụ thuộc vào mongo. Điều này là do các vùng chứa này sẽ không thể kết nối với mongo lần đầu tiên khi nó khởi tạo (ngay cả với cờ tùy thuộc). Xem chủ đề này để biết chi tiết stackoverflow.com/questions/31746182/…
java-fadect301

Câu trả lời:


92

Các quan chức mongohình ảnh đã sáp nhập một PR để bao gồm các chức năng để tạo người dùng và cơ sở dữ liệu lúc khởi động.

Khởi tạo cơ sở dữ liệu sẽ chạy khi không có gì được điền trong /data/dbthư mục.

Thiết lập người dùng quản trị

Các biến môi trường để kiểm soát thiết lập người dùng "root" là

  • MONGO_INITDB_ROOT_USERNAME
  • MONGO_INITDB_ROOT_PASSWORD

Thí dụ

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

Bạn không cần / không thể sử dụng --authtrên dòng lệnh vì tập lệnh docker entrypoint.sh thêm điều này khi các biến môi trường tồn tại.

Khởi tạo cơ sở dữ liệu

Hình ảnh cũng cung cấp /docker-entrypoint-initdb.d/đường dẫn để triển khai các tập lệnh tùy chỉnh .jshoặc .shthiết lập sẽ được chạy một lần khi khởi tạo cơ sở dữ liệu. .jscác tập lệnh sẽ được chạy testtheo mặc định hoặc MONGO_INITDB_DATABASEnếu được xác định trong môi trường.

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

hoặc là

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

Tệp javascript shell mongo khởi tạo đơn giản trình bày việc thiết lập containerbộ sưu tập với dữ liệu, ghi nhật ký và cách thoát khi gặp lỗi (để kiểm tra kết quả).

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

Điều này thật tuyệt vời, tôi cho rằng set -eđang yêu cầu entrypoint.shđọc các biến từ ENVđịnh nghĩa để tôi có thể sử dụng cách tiếp cận tương tự như ví dụ từ MySQL, tôi đúng? Như một sự bổ sung cho câu trả lời của bạn tôi đã tìm thấy PR này mà dường như ai đó đang làm việc trong một cái gì đó tương tự như đề xuất của bạn chỉ đến từ một góc độ khác
ReynierPM

Các biến môi trường bạn nhận được theo mặc định. set -ekhiến toàn bộ tập lệnh thoát khi một lệnh bị lỗi, do đó, tập lệnh không thể âm thầm bị lỗi và khởi động mongo.
Matt

Tương tự như tất cả các script xây dựng Dockerfile mà bạn thấy sử dụng &&ở mọi nơi.
Matt

PR mongo đó là một thực hiện kỹ lưỡng hơn nhiều! và docker-entrypoint-initdb.dthư mục làm cho nó có thể mở rộng. Tôi hy vọng điều đó được hợp nhất
Matt

Nó được hợp nhất (xem ở đây )
ReynierPM

90

Đây là một giải pháp sạch hơn bằng cách sử dụng docker-composevà một jstập lệnh.

Ví dụ này giả định rằng cả hai tệp (docker-comp.yml và mongo-init.js) nằm trong cùng một thư mục.

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

Sau đó, chỉ cần bắt đầu dịch vụ bằng cách chạy lệnh docker-soạn sau

docker-compose up --build -d mongodb 

Lưu ý : Mã trong thư mục docker-entrypoint-init.d chỉ được thực thi nếu cơ sở dữ liệu chưa từng được khởi tạo trước đó.


Bạn phải thay thế tất cả các giá trị <> trong đoạn mã bằng cài đặt của mình.
Paul Wasilewski

4
mongo-init.js: ro là gì?
Heril Muratovic,

9
@HerilMuratovic, volumesmục nhập ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:rođang liên kết tệp cục bộ ./mongo-init.jsvới đường dẫn vùng chứa /docker-entrypoint-initdb.d/mongo-init.jsdưới dạng chỉ đọc ro. Bạn có thể tìm thêm chi tiết về cách sử dụng ổ đĩa tại đây: docs.docker.com/storage/volumes
Paul Wasilewski,

2
@GustavoSilva Tôi hoàn toàn chắc chắn rằng nó đang hoạt động. Có vẻ như tệp soạn thảo docker của bạn và tập lệnh js không nằm trong cùng một thư mục. Hay bạn đang làm việc trên windows? Sau đó, vui lòng điều chỉnh volumestùy chọn và thêm đường dẫn tuyệt đối vào mongo-init.jstệp chẳng hạn c:\docker\mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro.
Paul Wasilewski

1
Db là gì? Mã có vẻ không đầy đủ đối với tôi, đó có phải là kết nối mongoose không?
andrevenancio

52

Đây là một giải pháp đang hoạt động tạo admin-userngười dùng có mật khẩu, cơ sở dữ liệu bổ sung ( test-database) và test-usertrong cơ sở dữ liệu đó.

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

Phần khó khăn là phải hiểu rằng các tệp * .js được chạy chưa được xác thực. Giải pháp xác thực tập lệnh như admin-usertrong admincơ sở dữ liệu. MONGO_INITDB_DATABASE adminlà điều cần thiết, nếu không tập lệnh sẽ được thực thi dựa trên testdb. Kiểm tra mã nguồn của docker-entrypoint.sh .


1
Có một lỗi đánh máy trong các vai trò? db nên là cơ sở dữ liệu thử nghiệm?
Giành chiến thắng

Hai nhận xét trên dòng thứ hai có getSiblingDB. Đầu tiên, mọi thứ hoạt động trong thử nghiệm của tôi mà không có dòng này. Thứ hai, việc ghi đè lên biến db như thế này có vẻ giống như một dạng xấu, vì nó được coi là một đối tượng toàn cục và việc ghi đè lên nó sẽ thay đổi ngữ cảnh cho mọi thứ.
Lazor

46

Hình ảnh Mongo có thể bị ảnh hưởng bởi MONGO_INITDB_DATABASE biến , nhưng nó sẽ không tạo cơ sở dữ liệu. Biến này xác định cơ sở dữ liệu hiện tại khi chạy /docker-entrypoint-initdb.d/* các tập lệnh . Vì bạn không thể sử dụng các biến môi trường trong các tập lệnh do Mongo thực thi, tôi đã sử dụng một tập lệnh 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

Ngoài ra, bạn có thể lưu trữ init-mongo.shtrong configs ( docker config create) và gắn kết nó với:

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

Và bí mật không thể được lưu trữ trong một tập tin.

Một cặp vợ chồng của GIST về vấn đề này.


9
Tôi vừa dành 3 giờ để tìm kiếm cách tạo db của riêng mình ban đầu. Thật điên rồ khi tài liệu không đề cập đến việc bạn cần xác thực trong các tệp .js hoặc .sh. Các ví dụ trên internet hoàn toàn không đầy đủ. Bạn thực sự cần phải tìm hiểu tập lệnh .sh của họ để kết luận cách viết nội dung này. Cách "tạo cơ sở dữ liệu trống" khi vùng chứa bắt đầu. PR nên được tạo ra để đơn giản hóa việc này. Một chút điên rồ nếu bạn hỏi tôi.
mát mẻ

1
Tôi đã dành hàng giờ để tìm giải pháp cho vấn đề này. Điều này vừa cứu tôi. Cảm ơn bạn.
NaijaProgrammer

$(cat "$MONGO_INITDB_ROOT_PASSWORD_FILE")nên được thay thế bằng $MONGO_INITDB_ROOT_PASSWORDnhững ngày này vì hình ảnh Mongo đã xử lý bí mật cho chúng tôi. hub.docker.com/_/mongo
FlippingBinary

Nó cũng như vậy trong 3.2 . Tôi có lẽ đã không nhận thấy.
x-yuri

@ x-yuri Lợi ích của việc sử dụng cấu hình cho init-mongo.sh là gì, thay vì chỉ sao chép tệp vào docker-entrypoint-initdb.d và để nó tự động chạy ở đó?
Lazor

13

Trong trường hợp ai đó đang tìm cách định cấu hình MongoDB với xác thực bằng cách sử dụng docker-compose, đây là cấu hình mẫu sử dụng các biến môi trường:

version: "3.3"

services:

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

Khi chạy, phiên docker-compose upbản mongo của bạn sẽ tự động chạy với tính năng xác thực được bật. Bạn sẽ có một cơ sở dữ liệu quản trị với mật khẩu đã cho.


3
mongo --username admin --password password --host localhost --port 27017tôi không thể kết nối vì nhật ký hiển thị người dùng và db được tạo thành công. LỖI:$ 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
bạn cần mongo admin --username ADMIN --password PASSWORTkết nối với phiên bản mongo của mình.
Philipp Schemel

1
Không thể làm việc này. "Không thể tìm thấy người dùng admin @ admin". Nó dường như không tự động tạo người dùng?
batjko

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

@TaraPrasadGurung Tôi gặp sự cố này, nhận thấy rằng tôi đã có một ổ đĩa được tạo cho cơ sở dữ liệu, bạn phải xóa ổ đĩa này cho vùng chứa để tạo người dùng mới.
Daniel S.

5

Nếu bạn đang tìm cách xóa tên người dùng và mật khẩu khỏi docker -omp.yml của mình, bạn có thể sử dụng Docker Secrets , đây là cách tôi tiếp cận nó.

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

Tôi đã sử dụng tùy chọn tệp: cho các bí mật của tôi, tuy nhiên, bạn cũng có thể sử dụng bên ngoài: và sử dụng các bí mật trong một bầy.

Các bí mật có sẵn cho bất kỳ tập lệnh nào trong vùng chứa tại / var / run / secret

Tài liệu Docker có điều này để nói về việc lưu trữ dữ liệu nhạy cảm ...

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

Bạn có thể sử dụng bí mật để quản lý bất kỳ dữ liệu nhạy cảm nào mà vùng chứa cần trong thời gian chạy nhưng bạn không muốn lưu trữ trong hình ảnh hoặc trong kiểm soát nguồn, chẳng hạn như:

Tên người dùng và mật khẩu Chứng chỉ TLS và khóa Các khóa SSH Dữ liệu quan trọng khác như tên của cơ sở dữ liệu hoặc máy chủ nội bộ Chuỗi chung hoặc nội dung nhị phân (kích thước tối đa 500 kb)


3

Đưa ra .envtệp này :

DB_NAME=foo
DB_USER=bar
DB_PASSWORD=baz

mongo-init.shtệp này :

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

Thao tác này docker-compose.ymlsẽ tạo cơ sở dữ liệu quản trị và người dùng quản trị, xác thực là người dùng quản trị, sau đó tạo cơ sở dữ liệu thực và thêm người dùng thực:

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:
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.