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

时间:2017-03-20 19:51:54

标签: mongodb docker docker-compose

我正在使用Docker,我有一个PHP,MySQL,Apache和Redis的堆栈。我现在需要添加MongoDB所以我正在检查Dockerfile以获取最新版本以及来自the docker-entrypoint.shMongoDB Dockerhub文件,但我找不到设置默认数据库的方法,管理员用户/密码以及可能来自docker-compose.yml文件的容器的auth方法。

在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实现相同的目标?任何人都有一些经验或解决方法吗?

12 个答案:

答案 0 :(得分:54)

official mongo imagemerged a PR to include the functionality在启动时创建用户和数据库。

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

一个简单的初始化javascript文件,用于演示日志记录以及如何退出并显示错误(用于结果检查)。

let error = true

let res = [
  db.container.drop(),
  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' }),
]

printjson(res)

if (error) {
  print('Error, exiting')
  quit(1)
}

答案 1 :(得分:13)

这是使用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 

答案 2 :(得分:12)

如果有人正在寻找如何使用docker-compose通过身份验证配置MongoDB,以下是使用环境变量的示例配置:

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实例会在启用auth的情况下自动运行。您将拥有一个具有给定密码的管理数据库。

答案 3 :(得分:11)

这是一个有效的解决方案,它使用密码,附加数据库(admin-user)和该数据库中的test-db创建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: 'admin',
    },
  ],
});

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

答案 4 :(得分: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将创建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:

答案 5 :(得分:3)

Mongo图像可能受MONGO_INITDB_DATABASE variable的影响,但不会创建数据库。运行/docker-entrypoint-initdb.d/* scripts时,此变量确定当前数据库。由于您can't在Mongo执行的脚本中使用环境变量,因此我使用了shell脚本:

docker-cloud.yml

version: '3.1'

secrets:
  mongo-passwd:
    file: mongo-passwd

services:
  mongo:
    image: mongo:3.2
    environment:
      MONGO_DB: ${MONGO_DB}
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_USER}
      MONGO_INITDB_ROOT_PASSWORD_FILE: /run/secrets/mongo-passwd
    volumes:
      - ./init-mongo.sh:/docker-entrypoint-initdb.d/init-mongo.sh
    secrets:
      - mongo-passwd

init-mongo.sh

mongo -- "$MONGO_DB" <<EOF
var user = '$MONGO_INITDB_ROOT_USERNAME';
var passwd = '$MONGO_INITDB_ROOT_PASSWORD';
var admin = db.getSiblingDB('admin');
admin.auth(user, passwd);
db.createUser({user: user, pwd: passwd, roles: ["readWrite"]});
EOF

答案 6 :(得分:2)

这对我有用:

docker-compose.yaml

version: "3.8"

services:
  mongodb:
    image: mongo:3.6
    restart: always
    environment:
      - MONGO_INITDB_ROOT_USERNAME=root
      - MONGO_INITDB_ROOT_PASSWORD=hello
    volumes:
      - ./mongo-init/:/docker-entrypoint-initdb.d/:ro
    ports:
      - 27017:27017
      - 9229:9229

  mongo-express:
    image: mongo-express
    restart: always
    ports:
      - 8111:8081
    environment:
      - ME_CONFIG_MONGODB_SERVER=mongodb
      - ME_CONFIG_MONGODB_ADMINUSERNAME=root
      - ME_CONFIG_MONGODB_ADMINPASSWORD=hello

./mongo-init/init.js

conn = new Mongo();
db = conn.getDB("MyDatabaseName");


db.myCollectionName.createIndex({ "address.zip": 1 }, { unique: false });

db.myCollectionName.insert({ "address": { "city": "Paris", "zip": "123" }, "name": "Mike", "phone": "1234" });
db.myCollectionName.insert({ "address": { "city": "Marsel", "zip": "321" }, "name": "Helga", "phone": "4321" });

通过 http://localhost:8111/ 查看仪表板:

enter image description here

答案 7 :(得分:1)

如果您希望从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)

答案 8 :(得分:1)

我的回答是基于@x-yuri 提供的;但我的情况有点不同。我想要一个包含脚本的图像,而不是绑定而不需要绑定安装它。

mongo-init.sh -- 不知道是否需要,但我也跑了 chmod +x mongo-init.sh

#!/bin/bash
# https://stackoverflow.com/a/53522699
# https://stackoverflow.com/a/37811764
mongo -- "$MONGO_INITDB_DATABASE" <<EOF
  var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
  var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
  var user = '$MONGO_INITDB_USERNAME';
  var passwd = '$MONGO_INITDB_PASSWORD';

  var admin = db.getSiblingDB('admin');

  admin.auth(rootUser, rootPassword);
  db.createUser({
    user: user,
    pwd: passwd,
    roles: [
      {
        role: "root",
        db: "admin"
      }
    ]
  });
EOF

Dockerfile

FROM mongo:3.6

COPY mongo-init.sh /docker-entrypoint-initdb.d/mongo-init.sh

CMD [ "/docker-entrypoint-initdb.d/mongo-init.sh" ]

docker-compose.yml

version: '3'

services:
    mongodb:
        build: .
        container_name: mongodb-test
        environment:
            - MONGO_INITDB_ROOT_USERNAME=root
            - MONGO_INITDB_ROOT_PASSWORD=example
            - MONGO_INITDB_USERNAME=myproject
            - MONGO_INITDB_PASSWORD=myproject
            - MONGO_INITDB_DATABASE=myproject

    myproject:
        image: myuser/myimage
        restart: on-failure
        container_name: myproject
        environment:
            - DB_URI=mongodb
            - DB_HOST=mongodb-test
            - DB_NAME=myproject
            - DB_USERNAME=myproject
            - DB_PASSWORD=myproject
            - DB_OPTIONS=
            - DB_PORT=27017            
        ports:
            - "80:80"

在那之后,我继续将此 Dockefile 发布为图像以用于其他项目。

注意:没有添加 CMD 它 mongo 抛出:未绑定变量错误

答案 9 :(得分:1)

如果您正在使用 docker-compose 并在创建卷后尝试运行这些建议中的任何一个,您可能需要删除该卷,因为如果该卷已经存在,init 脚本将不会运行。

要查看是否是这种情况,请尝试运行:-

docker volume ls

如果您的 mongo 数据在那里,您应该在卷名中看到它,例如:-

<db>_<volume>

如果卷类似于 db_volume,您将需要运行:-

docker volume rm db_volume

您可能需要将容器放入垃圾箱才能使其正常工作。

答案 10 :(得分:0)

在没有 root 访问权限的情况下在 MongoDB docker 容器中创建多个数据库和用户的步骤

  1. 停止 docker-compose with
    docker-compose down
    
    命令,如果您有多个文件,则为 'docker-compose -f docker-compose.yml -f docker-compose.dev.yml <...>'
  2. 删除分配给 mongo 容器的卷。运行'docker volume ls'。如果有类似于 <projectfolder>_mongodb--vol 的内容,请通过应用将其删除
    docker volume rm <projectfolder>_mongodb--vol
    
  3. 使用 .js.sh mongo 数据库 init scripts 设置文件夹。例如,mongo-init/db_1.js
    conn = new Mongo();
    db = conn.getDB("db_1")
    db.createUser(
    {
        user: "db_1_service_user",
        pwd: "<password>",
        roles: [
            {
                role: "readWrite",
                db: "db_1"
            }
        ]
    }
    );
    
    mongo-init/db_2.js 文件重复该过程。 conn.getDB() 创建数据库,db.createUser() 创建用户并将其分配给数据库。
  4. docker-compose.yml 片段,注意从包含数据库初始化脚本的 ./mongo-init/ 本地文件夹到远程 /docker-entrypoint-initdb.d/ 的挂载绑定:
    version: "3.8"
    services:
    
      my-service_1:
        depends_on:
          - mongodb
    
      my-service_2:
        depends_on:
          - mongodb
    
      mongodb:
        image: mongo:4.4-bionic
        ports:
        - "27017:27017"
        volumes:
        - mongodb--vol:/data/db
        - ./mongo-init/:/docker-entrypoint-initdb.d/:ro
        healthcheck:
        test: "echo 'db.runCommand(\"ping\").ok'"
        interval: 5s
        timeout: 5s
        retries: 3
    
    # in-service volumes are very slow in MacOS and Windows, 
    # so using fast shared volumes for large storage
    volumes:
        mongodb--vol:
    
  5. 将连接字符串应用于您的应用程序:
    mongodb://db_1_service_user:<password>@mongodb:27017/db_1
    
    mongodb://db_2_service_user:<password>@mongodb:27017/db_2
    

答案 11 :(得分:0)

只是对这里几个答案的快速补充 - 这一切都很棒,它确实为我节省了很多时间来解决问题! 如果您要创建的用户需要附加到特定数据库,我会添加一些代码

最重要的是,您需要登录到您的管理员库才能创建新用户。因此,当所有 docker-compose.yml 出现在提要上时,您的 mongo-init.js 文件将如下所示:

db = db.getSiblingDB('admin');
// move to the admin db - always created in Mongo
db.auth("rootUser", "rootPassword");
// log as root admin if you decided to authenticate in your docker-compose file...
db = db.getSiblingDB('DB_test');
// create and move to your new database
db.createUser({
'user': "dbUser",
'pwd': "dbPwd",
'roles': [{
    'role': 'dbOwner',
    'db': 'DB_test'}]});
// user created
db.createCollection('collection_test');
// add new collection

如果这可以帮助某人,我很高兴 - 欢呼,