使用凭据启动 MongoDb 测试容器

Posted

技术标签:

【中文标题】使用凭据启动 MongoDb 测试容器【英文标题】:Start MongoDb Test Container with credentials 【发布时间】:2021-01-28 03:42:39 【问题描述】:

我可以使用下面的 sn-p 启动 mongo 图像,插入和读取数据。类似于 testcontainers.org 上的 redis 示例。

private static final int MONGO_PORT = 27017;

@ClassRule
public static MongoDBContainer mongo = new MongoDBContainer("mongo:3.2.4")
        .withExposedPorts(MONGO_PORT);

默认情况下,mongo 没有凭据,但我正在寻找一种设置凭据的方法,以便我的应用程序的 MongoClient 可以从系统属性中获取用户/密码并正确连接。我尝试使用以下内容添加 root 用户/密码,但没有正确设置凭据。

@ClassRule
public static MongoDBContainer mongo = new MongoDBContainer("mongo:3.2.4")
        .withExposedPorts(MONGO_PORT)
        .withEnv("MONGO_INITDB_ROOT_USERNAME", "admin")
        .withEnv("MONGO_INITDB_ROOT_PASSWORD", "admin");

我的问题是:如何使用用户名和密码启动测试容器,以允许我的应用在使用wiremock 进行集成测试期间连接到它。

【问题讨论】:

【参考方案1】:

检查文档,您可以拥有 GenericContainer 而不是专门的 MongoDbContainer(不确定这是否有很大不同,因为它看起来与您已经尝试过的大部分相同)...

然后我跑了:

private static final int MONGO_PORT = 27017;

    /**
     * https://hub.docker.com/_/mongo shows:
     *
     * $ docker run -d --network some-network --name some-mongo \
     *     -e MONGO_INITDB_ROOT_USERNAME=mongoadmin \
     *     -e MONGO_INITDB_ROOT_PASSWORD=secret \
     *     mongo
     */
    public static GenericContainer mongo = new GenericContainer(DockerImageName.parse("mongo:4.4.1"));

    public static void main(String[] args) 
        List<String> list = new ArrayList<>();
        list.add("MONGO_INITDB_ROOT_USERNAME=mongoadministrator");
        list.add("MONGO_INITDB_ROOT_PASSWORD=secret");
        list.add("MONGO_INITDB_DATABASE=db");
        mongo.setEnv(list);
        mongo.withExposedPorts(MONGO_PORT);
        mongo.start();
    

来自容器的日志显示: docker logs [container_id]:

...
Successfully added user: 
    "user" : "mongoadministrator",  <<<<<
    "roles" : [
        
            "role" : "root",
            "db" : "admin"
        
    ]

...

我可以使用我的新管理用户在容器内成功登录:

> docker exec -it 3ae15f01074c bash
Error: No such container: 3ae15f01074c

> docker ps -a
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                      NAMES
755e214f23d6        mongo:4.4.1                 "docker-entrypoint.s…"   2 seconds ago       Up 2 seconds        0.0.0.0:32803->27017/tcp   elegant_keldysh
cdb4f55930f4        testcontainers/ryuk:0.3.0   "/app"                   3 seconds ago       Up 3 seconds        0.0.0.0:32802->8080/tcp    testcontainers-ryuk-ef84751e-bfd4-41eb-b381-1c1206186eda

> docker exec -it 755e214f23d6 bash
root@755e214f23d6:/# mongo admin -u mongoadministrator
MongoDB shell version v4.4.1
Enter password:                      <<<<<<<<<<<<<<<< BAD PASSWORD ENTERED HERE
connecting to: mongodb://127.0.0.1:27017/admin?compressors=disabled&gssapiServiceName=mongodb
Error: Authentication failed. :
connect@src/mongo/shell/mongo.js:374:17
@(connect):2:6
exception: connect failed
exiting with code 1

root@755e214f23d6:/# mongo admin -u mongoadministrator
MongoDB shell version v4.4.1
Enter password:                   <<<<<<<< GOOD PASSWORD secret ENTERED HERE
connecting to: mongodb://127.0.0.1:27017/admin?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session  "id" : UUID("63279398-d9c6-491d-9bd9-6b619dc4a99d") 
MongoDB server version: 4.4.1
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
    https://docs.mongodb.com/
Questions? Try the MongoDB Developer Community Forums
    https://community.mongodb.com
---
The server generated these startup warnings when booting: 
        2020-10-24T22:06:24.914+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
---
---
        Enable MongoDBs free cloud-based monitoring service, which will then receive and display
        metrics about your deployment (disk utilization, CPU, operation statistics, etc).

        The monitoring data will be available on a MongoDB website with a unique URL accessible to you
        and anyone you share the URL with. MongoDB may use this information to make product
        improvements and to suggest MongoDB products and deployment options to you.

        To enable free monitoring, run the following command: db.enableFreeMonitoring()
        To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
> 

【讨论】:

我只是想试试你的版本。它对我不起作用 - 日志中似乎没有注册特定用户。我能够连接但无法登录,因为可能是默认用户/密码组合已到位(我不知道)。我看到您必须为 mongoDb 容器 "org.testcontainers:mongodb:1.15.0-rc2" 使用不同的库,而不是标准的 testcontainers 库 'org.testcontainers:testcontainers:1.15.0-rc2'(这是我用于此解决方案的库)。 成功了吗?我希望得到这个赏金? 我有这个问题的答案,但似乎 +100 赏金消失了??? 我意识到这已经晚了,但要回答你的问题 - 你似乎混淆了 Wiremock 提供的 API/HTTP 模拟,使用(真实的)mongo db 服务器(未模拟)。因此,这应该是您问题的正确答案并赢得了赏金:) 希望您能以任何一种方式对其进行排序 我无法尝试。如果这行得通,我会重新开放赏金并给你积分。我无意放弃承诺的赏金。我会在今天结束前优先考虑。【参考方案2】:

简而言之,您可以找到使用 MongoDB 容器 here 进行测试的工作示例。

提供更多详细信息:您可以使用GenericContainer 配置对MongoDB 测试容器的身份验证,并使用以下属性设置环境MONGO_INITDB_ROOT_USERNAME, MONGO_INITDB_ROOT_PASSWORD

@ClassRule
public static final GenericContainer<?> MONGODB = new GenericContainer<>(DockerImageName.parse(MONGO_IMAGE))
        .withEnv("MONGO_INITDB_ROOT_USERNAME", USERNAME)
        .withEnv("MONGO_INITDB_ROOT_PASSWORD", PASSWORD)
        .withEnv("MONGO_INITDB_DATABASE", TEST_DATABASE)
        .withExposedPorts(MONGO_PORT);

那么你应该使用MongoClient 和对应的MongoCredential。例如,下面是测试,向/从 MongoDB 容器写入和读取文档。

@Test
public void shouldWriteAndReadMongoDocument() 
    ServerAddress serverAddress = new ServerAddress(MONGODB.getHost(), MONGODB.getMappedPort(MONGO_PORT));
    MongoCredential credential = MongoCredential.createCredential(USERNAME, AUTH_SOURCE_DB, PASSWORD.toCharArray());
    MongoClientOptions options = MongoClientOptions.builder().build();

    MongoClient mongoClient = new MongoClient(serverAddress, credential, options);
    MongoDatabase database = mongoClient.getDatabase(TEST_DATABASE);
    MongoCollection<Document> collection = database.getCollection(TEST_COLLECTION);

    Document expected = new Document("name", "foo").append("foo", 1).append("bar", "string");
    collection.insertOne(expected);

    Document actual = collection.find(new Document("name", "foo")).first();
    assertThat(actual).isEqualTo(expected);

注意事项:

要了解有关环境变量的更多详细信息,请查看文档 here(具体来说,环境变量部分)

要了解更多关于经过身份验证的 MongoDB 连接的详细信息,请查看文档 here

【讨论】:

似乎需要更多干预。 org.testcontainers.containers.MongoDBContainer$ReplicaSetInitializationException: An error occurred: MongoDB shell version v4.0.10 connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb 2021-06-14T13:31:37.571+0000 E QUERY [js] Error: network error while attempting to run command 'isMaster' on host '127.0.0.1:27017' : connect@src/mongo/shell/mongo.js:344:17 @(connect):2:6

以上是关于使用凭据启动 MongoDb 测试容器的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB的启动与停止

Mongodb启动命令mongod参数说明

mongodb 不会启动 mongod -> 错误 dbpath 不存在,但路径确实退出

MongoDB 通过配置文件启动及注册服务

MongoDB 通过配置文件启动及注册服务

Mongodb启动命令mongod参数说明