Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test containers: ignore parent `EXPOSE` instruction from Dockerfile

I'm trying to run Couchbase v.5.1.1 docker container for test purposes via Test container with fixed exposed ports, like:

trait CouchbaseTestEnvironment extends ForAllTestContainer {
  this: Suite =>

  def couchbaseContainer: FixedHostPortGenericContainer = {
    val consumer = new Slf4jLogConsumer(LoggerFactory.getLogger(getClass))

    /*
     * Couchbase should know which ports are exposed for client, because this is how it exposes services.
     * E.g. client ask only for on port - say 8091. And query service port is 8093. So client, won't ask for every port,
     * instead CB will tell client on which port query service exposed, that's why CB should be aware about port mapping.
     * That's why we need to give CB port mappings
     *
     * See for more details:
     * https://stackoverflow.com/questions/59277436/couchbase-in-docker-for-integration-tests-make-the-ports-8092-8093-8094-and-8
     */

    def randomPort: Int = {
      val (from, to) = (32768, 35000) //linux private port range
      from + Random.nextInt(to - from)
    }

    val random8091Port = randomPort
    val random8092Port = randomPort
    val random8093Port = randomPort
    val random8094Port = randomPort
    val random11210Port = randomPort

    val container = FixedHostPortGenericContainer(
      imageName = "couchbase:community-5.0.1",
      exposedHostPort = random8091Port,
      exposedContainerPort = random8091Port,
      env = Map(
        "COUCHBASE_RANDOM_PORT_8091" -> random8091Port.toString,
        "COUCHBASE_RANDOM_PORT_8092" -> random8092Port.toString,
        "COUCHBASE_RANDOM_PORT_8093" -> random8093Port.toString,
        "COUCHBASE_RANDOM_PORT_8094" -> random8094Port.toString,
        "COUCHBASE_RANDOM_PORT_11210" -> random11210Port.toString
      )
    )

    container.container.withFixedExposedPort(random8092Port, random8092Port)
    container.container.withFixedExposedPort(random8093Port, random8093Port)
    container.container.withFixedExposedPort(random8094Port, random8094Port)
    container.container.withFixedExposedPort(random11210Port, random11210Port)

    container.container.withLogConsumer(consumer)

    container
  }
}

So as you can see 5 FIXED ports should be exposed. But, when I'm running tests I actually can see, that instead other ports exposed with random ports:

docker ps

f4fc1ce06544   couchbase:community-5.0.1   "/entrypoint.sh /opt…"   59 seconds ago   Up 1 second    0.0.0.0:55264->8091/tcp, 0.0.0.0:55263->8092/tcp, 0.0.0.0:55262->8093/tcp, 0.0.0.0:55261->8094/tcp, 0.0.0.0:55260->11207/tcp, 0.0.0.0:55259->11210/tcp, 0.0.0.0:55258->11211/tcp, 0.0.0.0:55257->18091/tcp, 0.0.0.0:55256->18092/tcp, 0.0.0.0:55255->18093/tcp, 0.0.0.0:55254->18094/tcp   unruffled_mendel
03b491ac2ea8   testcontainersofficial/ryuk:0.3.0

So as you can see another ports was exposed, and mapped to random ports instead fixed.

As far as I understand, test containers, ignores ports I gave, and instead exposes ports from Couchbase Dockerfile: https://github.com/couchbase/docker/blob/master/community/couchbase-server/5.1.1/Dockerfile#L74

EXPOSE 8091 8092 8093 8094 8095 8096 11207 11210 11211 18091 18092 18093 18094 18095 18096

Can I somehow force Test containers to ignore EXPOSE instruction?

Partially helped question: Couchbase in docker for integration tests: Make the ports 8092, 8093, 8094 and 8095 configurable to be able to use docker’s random ports

like image 359
Ivan Kurchenko Avatar asked Nov 07 '22 02:11

Ivan Kurchenko


1 Answers

Can I somehow force Test containers to ignore EXPOSE instruction?

I don't know if there is a simple configuration option for this, but a workaround solution I found is to use an advanced feature of the docker-java create container command customization. I'm providing an example in Java, translate it to Scala yourself, please. Apply it as the last command before returning a container object from your function:

container.withCreateContainerCmdModifier(
    cmd -> cmd.getHostConfig().withPublishAllPorts(false)
);

The main point here is the usage of .withPublishAllPorts(false). From my understanding, this is the same as --publish-all (or -P) arguments of the docker run command. Testcontainers library sets this value to true by default. This modification overrides it to false.

With this configuration no ports are published at all for your example, not the 5 fixed as expected:

CONTAINER ID   IMAGE                       COMMAND                  CREATED          STATUS          PORTS                                                        NAMES
2ee4fb91b97c   couchbase:community-5.0.1   "/entrypoint.sh couc…"   33 seconds ago   Up 32 seconds   8091-8094/tcp, 11207/tcp, 11210-11211/tcp, 18091-18094/tcp   trusting_keldysh

This is because in the answer you provided, the author created a special custom docker image of couchbase, which "understands" environment variables like COUCHBASE_RANDOM_PORT_8091. Your code uses the standard couchbase image couchbase:community-5.0.1, which basically just ignores these environment variables. So in order to run counchbase on not standard internal ports, you need to build a custom image with the "magic" configure-node.sh script, which tunes couchbase config using values provided in environment variables.

I hope it helps anyhow :)

like image 196
yuppie-flu Avatar answered Nov 15 '22 06:11

yuppie-flu