Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]: Add a method to GenericContainer to expose a random container port with the same number as the host port #9553

Open
linghengqian opened this issue Nov 23, 2024 · 0 comments

Comments

@linghengqian
Copy link

linghengqian commented Nov 23, 2024

Module

Core

Problem

  • Currently, it is not possible to expose a random port in a container to the same random port on the host. To achieve this goal, you can only use the deprecated class org.testcontainers.containers.FixedHostPortGenericContainer. For HiveServer2 with Zookeeper service discovery enabled, there are similar operations as follows.
import org.apache.curator.test.InstanceSpec;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.FixedHostPortGenericContainer;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
public class ExampleTest {
    @Test
    void test() {
        Network network = Network.newNetwork();
        int randomPort = InstanceSpec.getRandomPort();
        try (
                GenericContainer<?> zookeeper = new GenericContainer<>("zookeeper:3.9.3-jre-17")
                        .withNetwork(network)
                        .withNetworkAliases("foo")
                        .withExposedPorts(2181);
                GenericContainer<?> hiveServer2 = new FixedHostPortGenericContainer<>("apache/hive:4.0.1")
                        .withNetwork(network)
                        .withEnv("SERVICE_NAME", "hiveserver2")
                        .withFixedExposedPort(randomPort, randomPort)
                        .dependsOn(zookeeper)
        ) {
            zookeeper.start();
            hiveServer2.withEnv("SERVICE_OPTS", "-Dhive.server2.support.dynamic.service.discovery=true" + " "
                    + "-Dhive.zookeeper.quorum=" + zookeeper.getNetworkAliases().get(0) + ":2181" + " "
                    + "-Dhive.server2.thrift.bind.host=0.0.0.0" + " "
                    + "-Dhive.server2.thrift.port=" + randomPort);
            hiveServer2.start();
        }
    }
}
  • The only purpose of org.apache.curator.test.InstanceSpec#getRandomPort() is to get a random host port. This can sometimes conflict with the port in the container.
  • This is like a Docker Compose unit like this,
services:
  zookeeper:
    image: zookeeper:3.9.3-jre-17
    ports:
      - "12181:2181"
  apache-hive-1:
    image: apache/hive:4.0.1
    depends_on:
      - zookeeper
    environment:
      SERVICE_NAME: hiveserver2
      SERVICE_OPTS: >-
        -Dhive.server2.support.dynamic.service.discovery=true
        -Dhive.zookeeper.quorum=zookeeper:2181
        -Dhive.server2.thrift.bind.host=0.0.0.0
        -Dhive.server2.thrift.port=23593
    ports:
      - "23593:23593"
  • There is almost no way around org.testcontainers.containers.FixedHostPortGenericContainer to use a random numeric port both on the host, inside the container, and in the container's environment variables.

Solution

  • I was expecting there to be a method in GenericContainer to expose the same host port number on a random container port. If this method is called org.testcontainers.containers.GenericContainer#withRandomExposedPorts(), it can expose a random container port. And allow the host to obtain this port number through org.testcontainers.containers.GenericContainer#getFirstMappedPort(), then the use of org.testcontainers.containers.FixedHostPortGenericContainer can obviously be simplified to,
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
public class ExampleTest {
    @Test
    void test() {
        Network network = Network.newNetwork();
        try (
                GenericContainer<?> zookeeper = new GenericContainer<>("zookeeper:3.9.3-jre-17")
                        .withNetwork(network)
                        .withNetworkAliases("foo")
                        .withExposedPorts(2181);
                GenericContainer<?> hiveServer2 = new GenericContainer<>("apache/hive:4.0.1")
                        .withNetwork(network)
                        .withEnv("SERVICE_NAME", "hiveserver2")
                        .withRandomExposedPorts()
                        .dependsOn(zookeeper)
        ) {
            zookeeper.start();
            hiveServer2.withEnv("SERVICE_OPTS", "-Dhive.server2.support.dynamic.service.discovery=true" + " "
                    + "-Dhive.zookeeper.quorum=" + zookeeper.getNetworkAliases().get(0) + ":2181" + " "
                    + "-Dhive.server2.thrift.bind.host=0.0.0.0" + " "
                    + "-Dhive.server2.thrift.port=" + hiveServer2.getFirstMappedPort());
            hiveServer2.start();
        }
    }
}

Benefit

  • This helps simplify the process of starting a HiveServer2 with Zookeeper service discovery enabled.

Alternatives

Would you like to help contributing this feature?

No

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant