如何在启动时为 MongoDB 容器创建 DB?

我与 Docker 工作,我有一个与 PHP,MySQL,Apache 和 Redis 堆栈。我现在需要添加 MongoDB,所以我正在检查 文件夹的最新版本,也从 MongoDB DockerhubDocker-entrypoint.sh文件,但我无法找到一种方法来设置默认数据库,管理员用户/密码和可能的 auth 方法的容器从 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}

这将把 DB 和用户/密码设置为 root密码。

有没有什么方法可以用 MongoDB 来达到同样的效果? 有没有人有一些经验或者解决方案?

210401 次浏览

/data/db目录中没有填充任何内容时,docker hub mongo映像将运行 /docker-entrypoint-initdb.d/中的任何脚本。

数据库初始化

mongo容器映像提供了 /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' })
]


printjson(res)


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

管理用户设置

控制“ 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

Dockerfile

FROM docker.io/mongo
ENV MONGO_INITDB_ROOT_USERNAME admin
ENV MONGO_INITDB_ROOT_PASSWORD password

您不需要在命令行上使用 --auth,因为 docker entrypoint.sh脚本在检测到环境变量存在时会添加这一点。

如果有人正在寻找如何使用 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 实例将在启用身份验证的情况下自动运行。您将拥有一个具有给定密码的管理数据库。

如果你正在寻找删除用户名和密码从你的码头-组成。你可以使用 码头秘密,这里是我如何处理它。

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

我有使用我的秘密 文件:选项,但是,你也可以使用 外界:和使用的秘密在一个蜂群。

这些秘密对于容器中的任何脚本都是可用的,位于/var/run/secret

Docker 文档说明了如何存储敏感数据..。

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

您可以使用机密来管理容器在运行时需要但不想存储在映像或源代码控制中的任何敏感数据,例如:

用户名和密码 TLS 证书和密钥 SSH 密钥 其他重要数据,如数据库或内部服务器的名称 泛型字符串或二进制内容(大小不超过500kb)

下面是一个可行的解决方案,它使用密码、附加数据库(test-database)和该数据库中的 test-user创建 admin-user用户。

文件夹:

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数据库中的 admin-userMONGO_INITDB_DATABASE admin是必不可少的,否则脚本将针对 testdb 执行。检查 Docker-entrypoint.sh的源代码。

UPD Today I 避免 Docker Swarm,secret,and configs.我会用 docker-compose.env文件运行它。只要我不需要自动缩放。如果是我,我可能会选 K8。还有数据库密码,root 帐户与否... ... 当您在一个容器中运行单个数据库而不与外部世界连接时,它们真的重要吗?..我想知道您对此的看法,但 Stack Overflow 可能不太适合这种交流。

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

返回文章页面

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

返回文章页面

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

秘密不能存储在文件中。

要点一对

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

本例假设两个文件(docker-compose. yml 和 mongo-init. js)位于同一个文件夹中。

码头作曲

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 文件夹中的代码只有在数据库以前从未初始化过的情况下才会执行。

根据这个 .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:

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

不知道是否需要,但我也运行了 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

返回文章页面

FROM mongo:3.6


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


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

返回文章页面

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 会抛出: 未绑定变量错误

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

要了解情况是否如此,请尝试运行:-

docker volume ls

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

<db>_<volume>

如果卷类似于 db _ music,则需要运行:-

docker volume rm db_volume

您可能需要丢弃您的容器以使其工作。

创建 多个数据库和 MongoDB Docker 容器中没有 root 访问权限的用户的步骤。

  1. 停止码头-与
    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/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文件的过程。 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
    

这对我有用:

码头作曲

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

只是一个快速的附加到这里的一对夫妇的答案-这些都是伟大的,它确实节省了我很多时间弄清楚事情!

如果您想创建的用户需要附加到特定的数据库,我会添加一点代码

主要的事情是,您需要登录到您的管理员基地,以创建新的用户。

因此,对于 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

如果这能帮到别人,我很高兴,干杯,

这是我使用 env 变量和机密的方法。

下面将在 mongo 容器启动时创建“ app _ user”和“ app _ database”(只有当存储在/data/db 中的已用数据库为空时)。

文件夹

FROM mongo:5.0.3


COPY images/mongo/init.js /docker-entrypoint-initdb.d/

Init.js

db.log.insertOne({"message": "Database created."});


db.createUser(
{
user: _getEnv("MONGO_USER"),
pwd: cat(_getEnv("MONGO_PASSWORD_FILE")),
roles: [
"readWrite", "dbAdmin"
]
}
);
  • 脚本将使用 MONGO _ INITDB _ DATABASE (在 docker-compose. yml 中定义的 env 变量)作为数据库名称。
  • 只有当存储在/data/db 中的已用数据库为空时,才会运行/docker-entrypoint-initdb. d/中的脚本。

码头作曲

mongo:
build:
context: .
dockerfile: ./images/mongo/Dockerfile
container_name: app_mongo
environment:
MONGO_INITDB_DATABASE: "app_database"
MONGO_INITDB_ROOT_PASSWORD_FILE: /run/secrets/app_mongo_root_password
MONGO_INITDB_ROOT_USERNAME: "root"
MONGO_PASSWORD_FILE: /run/secrets/app_mongo_password
MONGO_USER: "app_user"
secrets:
- app_mongo_password
- app_mongo_root_password
volumes:
- mongo:/data/db


secrets:
app_mongo_password:
file: ./secrets/app_mongo_password.txt
app_mongo_root_password:
file: ./secrets/app_mongo_root_password.txt


volumes:
mongo: