如何在启动时为MongoDB容器创建数据库?


81

我正在使用Docker,并且拥有PHP,MySQL,Apache和Redis的堆栈。我现在需要添加MongoDB,因此我正在检查Dockerfile中的最新版本以及MongoDB Dockerhub中的docker-entrypoint.sh文件,但我找不到设置默认数据库,管理员用户/密码以及可能进行身份验证的方法文件中容器的方法。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

@Valentin当然可以,但是您的意思是什么?
ReynierPM

我的观点是,您可以使用变量在dockerfile中设置默认数据库,管理员用户/密码以及可能的auth方法,然后将其传递到撰写文件中
Valentin

注意:如果使用任何使用mongo-init脚本的解决方案,请确保对依赖于mongo的容器设置重新启动:除非已停止(或除no外)。这是因为这些容器在初始化时(即使带有depends_on标志)也将首次无法连接到mongo。看到这个线程细节stackoverflow.com/questions/31746182/...
Java的addict301

Answers:


90

官方mongo图片已经合并公关,包括功能,在启动时创建用户和数据库。

/data/db目录中未填充任何内容时,数据库初始化将运行。

管理员用户设置

用于控制“ root”用户设置的环境变量是

  • 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/

一个简单的初始化mongo shell javascript文件,演示了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示例相同的方法,对吗?作为您回答的补充,我确实发现了此公关,显然有人在从其他角度来看与您的建议相似的工作
ReynierPM

您默认获得的环境变量。set -e当命令失败时,导致整个脚本退出,因此该脚本不能静默失败并启动mongo。
马特

与所有在所有地方使用的Dockerfile构建脚本相似,您会看到它们&&
马特

mongo PR是更彻底的实现!该docker-entrypoint-initdb.d目录使其可扩展。我希望得到合并
Matt

它已合并(请参阅此处
ReynierPM

90

这里是通过docker-composejs脚本使用的另一个更清洁的解决方案。

本示例假定两个文件(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文件夹中的代码。


您必须将代码段中的所有<>值替换为您的设置。
Paul Wasilewski

4
什么是mongo-init.js:ro?
Heril Muratovic,

9
@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
Paul Wasilewski,

2
@GustavoSilva我绝对确定它能正常工作。看来您的docker compose文件和js脚本不在同一文件夹中。还是在Windows上工作?然后,请调整volumes选项,然后将绝对路径添加到mongo-init.js文件中c:\docker\mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
Paul Wasilewski,

1
什么是db?代码对我来说似乎不完整,是猫鼬连接吗?
andrevenancio

51

这是一个有效的解决方案,可以admin-user使用密码,其他数据库(test-database)和test-user该数据库创建用户。

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

棘手的部分是要了解* .js文件是未经身份验证运行的。该解决方案验证脚本作为admin-useradmin数据库中。MONGO_INITDB_DATABASE admin是必不可少的,否则脚本将针对test数据库执行。检查docker-entrypoint.sh的源代码。


1
角色有错字吗?db应该是测试数据库?
温斯特

45

Mongo图像可能受MONGO_INITDB_DATABASE 变量影响,但不会创建数据库。运行/docker-entrypoint-initdb.d/* 脚本时,此变量确定当前数据库。由于您不能在Mongo执行的脚本中使用环境变量,因此我使用了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

另外,您可以将其存储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

而且机密不能存储在文件中。

对夫妇学家对此事。


9
我只花了3个小时左右的时间来搜索最初如何创建自己的数据库。疯狂的文档没有提到您需要在.js或.sh文件中进行身份验证。互联网上的示例根本不完整。从字面上看,您需要深入研究他们的.sh脚本来总结如何编写这些内容。容器启动时如何“创建空数据库”。应该创建PR来简化此过程。如果你问我,那有点疯狂。
很酷的

1
我花了几个小时寻找解决这个问题的方法。这救了我。谢谢。
NaijaProgrammer

$(cat "$MONGO_INITDB_ROOT_PASSWORD_FILE")$MONGO_INITDB_ROOT_PASSWORD这些天应该替换掉,因为Mongo图像已经为我们处理了秘密。hub.docker.com/_/mongo
FlippingBinary

3.2中也是如此。我可能没注意到。
x-yuri

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 upmongo实例时,它将在启用身份验证的情况下自动运行。您将拥有一个具有给定密码的管理数据库。


3
mongo --username admin --password password --host localhost --port 27017我无法连接,因为日志显示用户并且数据库创建成功。错误:$ 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实例。
Philipp Schemel

1
无法使它正常工作。“找不到用户admin @ admin”。似乎没有自动创建用户?
batjko

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

@TaraPrasadGurung我遇到了这个问题,注意到我已经为数据库创建了一个卷,您必须删除该卷才能为容器创建一个新用户。
Daniel S.19年

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


3

给定此.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将创建admin数据库和admin用户,以admin用户身份进行身份验证,然后创建真实数据库并添加真实用户:

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:
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.