'Run ES docker image with custom port using testcontainers

I want to run a container tests that running ES image via Docker. After some research I found https://www.testcontainers.org/ and they also have a built-it ES module.

Because my development environment using ES in ports 9200 and 9300 I prefer to use another ports for my tests, let’s say 1200 and 1300. Therefore, to run the docker image from CLI I use this command:

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

I tried to do it with testcontainers, for example:

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();
}

breakpoint in esContainer.isRunning():

port is 32384, run esContainer.getHttpHostAddress() return localhost/127.0.0.1:32847 and also from docker dashboard: Anyway, failed to make ES connection with both (1200 and 32384).

run the start() line with the **waitingFor** command throws Container startup failed error

Another question, how can I know the schema (http or https) in testcontainers?



Solution 1:[1]

If you want to specify a port instead of using a random one, you can do it with this:

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

Solution 2:[2]

I'm doing it wrong. withExposedPorts allows us to expose ports from the container’s perspective (which I don’t need to do in this case since ElasticContainer already exposes an http port (9200) and a tcp port (9300)).

To find out the random port on the host (on which the test runs) that these ports were mapped, call getMappedPort(9200) or in the case of ElasticContainer to get the host:port you call getHttpHostAddress().

More info here: https://www.testcontainers.org/features/networking/

Bottom line, change the init to:

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

Get the port by:

int containerPort = esContainer.getMappedPort(9200);

P.S. About the schema - I still don't know but looks like testContainer runs on https..

Solution 3:[3]

I was able to get it working as below. I have to set 9200 for withExposedPorts()

container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE)
            .withEnv("discovery.type", "single-node")
            .withExposedPorts(9200)     
            .withCreateContainerCmdModifier(cmd -> cmd.withHostConfig(
                        new HostConfig().withPortBindings(new PortBinding(Ports.Binding.bindPort(34343), new ExposedPort(9200)))));

Here is the log:

 org.elasticsearch.client.RestClient - request [GET http://localhost:34343/] returned 1 warnings

Solution 4:[4]

You just need to bind a specific ports, this is since the generic container implementation binds a free random one by default

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Felipe Desiderati
Solution 2 halfer
Solution 3 yulinxp
Solution 4 wizardInCloud