测试容器:忽略来自Dockerfile的父级`EXPOSE`指令

4

我想通过固定暴露端口的测试容器来运行Couchbase v.5.1.1的docker容器进行测试,类似于:

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://dev59.com/xbjna4cB1Zd3GeqP2wXh
     */

    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
  }
}

正如您所看到的,应该公开5个固定端口。 但是,在运行测试时,实际上我可以看到其他端口使用随机端口公开:

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

正如您所看到的,另一个端口已被暴露,并映射到随机端口而不是固定端口。

据我所知,测试容器忽略了我提供的端口,而是从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

我是否能够强制 Test containers 忽略 EXPOSE 命令?

相关帮助:

如何在 Docker 中使用 Couchbase 进行集成测试:使端口 8092、8093、8094 和 8095 可配置以便使用 Docker 的随机端口

1个回答

1

我是否可以强制Test containers忽略EXPOSE指令?

我不知道是否有简单的配置选项可以做到这一点,但我找到了一个解决方法,即使用docker-java create container command customization的高级功能。我提供一个Java示例,请自行将其翻译为Scala,并在从函数返回容器对象之前应用它作为最后一条命令:

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

这里的主要点是使用.withPublishAllPorts(false)。据我理解,这与docker run命令的--publish-all(或-P)参数相同。Testcontainers库默认将此值设置为true。此修改将其覆盖为false
使用此配置不会发布任何端口,包括您期望的5个固定端口。
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

这是因为您提供的答案中,作者创建了一个特殊的自定义Docker镜像couchbase,它“理解”环境变量,如COUCHBASE_RANDOM_PORT_8091。您的代码使用标准的couchbase镜像couchbase:community-5.0.1,基本上忽略这些环境变量。因此,为了在非标准内部端口上运行counchbase,您需要使用“魔法”configure-node.sh脚本构建自定义镜像,该脚本使用环境变量中提供的值来调整couchbase配置。
希望这样有所帮助 :)

是的,它绝对有帮助!非常感谢您提供如此详细的答案。 - Ivan Kurchenko
快速问题:带有“魔法”的自定义图像,你能建议我应该实现什么样的魔法吗?我能在子Dockerfile中重写expose指令吗?谢谢。 - Ivan Kurchenko
1
你需要一些东西来根据环境变量覆盖容器内Couchbase的默认内部端口。例如 sed -i "s|8092|${COUCHBASE_RANDOM_PORT_8092}|g" /opt/couchbase/etc/couchdb/default.d/capi.ini。这应该在启动Couchbase服务器之前完成。 - yuppie-flu
好的,我明白了。老实说,我已经尝试过这个方法,但是它并没有起到作用,测试容器仍然从父Dockerfile中暴露端口。如果可能的话,我会尝试覆盖父Dockerfile中的EXPOSE指令。再次感谢您的帮助! - Ivan Kurchenko
1
我认为EXPOSE并不是很重要。它更像是文档:https://docs.docker.com/engine/reference/builder/#expose 我建议您通过ssh登录到自定义容器中,并确保couchbase确实在自定义端口上运行,而不是默认端口。祝好运。 - yuppie-flu
谢谢 - 很好的观点。感谢您的帮助! - Ivan Kurchenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接