使用 testcontainers 使用自定义端口运行 ES docker 映像

Posted

技术标签:

【中文标题】使用 testcontainers 使用自定义端口运行 ES docker 映像【英文标题】:Run ES docker image with custom port using testcontainers 【发布时间】:2020-09-06 20:38:42 【问题描述】:

我想运行一个通过 Docker 运行 ES 映像的容器测试。 经过一番研究,我找到了https://www.testcontainers.org/,他们也有一个内置的ES module。

因为我的开发环境在端口 9200 和 9300 中使用 ES,所以我更喜欢使用其他端口进行测试,比如 1200 和 1300。 因此,要从 CLI 运行 docker 映像,我使用以下命令:

docker run -p 1200:9200 -p 1300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.6.2

我尝试用测试容器来做,例如:

static ElasticsearchContainer esContainer =
        new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:7.6.2")
                .withExposedPorts(1200, 9200)
                .withExposedPorts(1300, 9300)
                .withEnv("discovery.type", "single-node");
                // .waitingFor(Wait.forHttp("/")); // Wait until elastic start – cause an error

@BeforeClass
public static void initEsDockerImage() 
    esContainer.start();
    esContainer.isRunning();

esContainer.isRunning() 中的断点:

端口为 32384,运行 esContainer.getHttpHostAddress() return localhost/127.0.0.1:32847 以及来自 docker 仪表板: 无论如何,未能与两者建立 ES 连接(1200 和 32384)。

使用**waitingFor** 命令运行 start() 行会抛出 Container startup failed 错误

另一个问题,我如何知道测试容器中的架构(http 或 https)?

【问题讨论】:

【参考方案1】:

如果你想指定一个端口而不是使用随机端口,你可以这样做:

static final mysqlContainer<?> mysql =
    new MySQLContainer<>("mysql:5.6")
        .withExposedPorts(34343)
        .withCreateContainerCmdModifier(cmd -> cmd.withHostConfig(
            new HostConfig().withPortBindings(new PortBinding(Ports.Binding.bindPort(34343), new ExposedPort(3306)))
        ));

【讨论】:

【参考方案2】:

我做错了。 withExposedPorts 允许我们从容器的角度公开端口(在这种情况下我不需要这样做,因为 ElasticContainer 已经公开了一个 http 端口(9200)和一个 tcp 端口(9300))。

要找出映射这些端口的主机(测试运行所在)上的随机端口,请调用 getMappedPort(9200) 或在 ElasticContainer 的情况下获取主机:您调用 getHttpHostAddress() 的端口。

更多信息在这里:https://www.testcontainers.org/features/networking/

底线,将 init 更改为:

static ElasticsearchContainer esContainer =
    new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:7.6.2")
            .withEnv("discovery.type", "single-node");

通过以下方式获取端口:

int containerPort = esContainer.getMappedPort(9200);

附: 关于架构 - 我仍然不知道,但看起来 testContainer 在 https 上运行..

【讨论】:

【参考方案3】:

你只需要绑定一个特定的端口,这是因为通用容器实现默认绑定一个免费的随机端口

    List<String> portBindings = container.getPortBindings();
    portBindings.add(String.format("%d:%d/%s", ES_PORT_HOST, ES_PORT_CONTAINER, InternetProtocol.TCP));
    container.setPortBindings(portBindings);

     // or just in one line if no previous binding required
     // container.setPortBindings(List.of(String.format("%d:%d/%s", ES_PORT_HOST, ES_PORT_CONTAINER, InternetProtocol.TCP)));

【讨论】:

以上是关于使用 testcontainers 使用自定义端口运行 ES docker 映像的主要内容,如果未能解决你的问题,请参考以下文章

如何运行自定义 docker 镜像 testContainer

我可以在 JDBC URL 模式下使用带有自定义 Dockerfile 的 Testcontainers 吗?

使用 Testcontainers 时如何设置 Postgresql 的端口?

Testcontainers:使用 GitLab CI “等待容器端口打开超时”

SpringBootTest、Testcontainers、容器启动——映射端口只能在容器启动后获取

Spring Boot TestContainers 映射的端口只能在容器启动后获取