Testcontainers container.getHost() 在本地与 GitLab 管道的行为不同

问题描述 投票:0回答:1

tl:博士;

Testcontainers

container.getHost()
在 Maven 生命周期步骤和 GitLab CI-Pipeline 中的行为不同。

  • 在本地计算机上
    container.getHost()
    替换为
    localhost
  • 在 Gitlab 管道中
    container.getHost()
    替换为实际的
    HostIP

背景:

二手:

  • Maven
  • 经过测试的主机系统
    • 苹果 M2 Pro (2023)
      • IntelliJ 终极版
    • Linux(库班图:23.10)
      • IntelliJ 社区版
    • GitLab CI/CD 管道

版本:

  • Java 21(OpenJDK 和 Amazon Coretto)
  • Junit-木星:5.9.3
  • 测试容器:1.19.3
  • SpringBoot:3.2.4
    • RestClient 和 Rest 模板

为什么使用 RestClient 和 Rest 模板?

尽管 RestClient 与 RestTemplate 相比被认为是最先进的(spring.io:2024 年 4 月)... ...两者给出不同的错误反馈(如下)。

设置

假设 Junit-Testcontainers 设置中有 3 个 java 微服务:

Container1   <-   Container2   <-  Validator

Container2
需要
Container1
,并且验证器在Junit-Test容器环境中提升两者,观察其通信。 验证器不是一个实时系统,只是一个集成测试系统。

因此:

  1. Container1
    已开始
  2. Container1's
    端口写入
    Container2's
    env。
  3. Container2
    已开始。
  4. 启动期间
    Container2
    尝试联系
    Container1's
    执行器端点。
    // Create a common network for all containers
    @ClassRule
    public static Network network = Network.newNetwork();

    @ClassRule
    public static GenericContainer<?> C1 =
            new GenericContainer<>(C1DockerImage)
                    .withExposedPorts(C1Port)
                    .withNetwork(network)
                    .withNetworkAliases("C1")

    @ClassRule
    public static GenericContainer<?> C2 =
            new GenericContainer<>(C2DockerImage)
                    .withExposedPorts(C2Port)
                    .withNetwork(network)
                    .withNetworkAliases("C2")

    static {
        // Start C1
        C1.start();
        C1BaseURL = "http://" + C1.getHost() + ":" + C1.getMappedPort(C1Port);

        // Start C2
        C2.withEnv("C1_URL", C1BaseURL);
        C2.start();

        logger.info("C1-Url given to C2 via ENV-Variable:   " + C1BaseURL);
    }

因此:

  • 所有容器都连接到同一个网络
  • C1BaseURL 看起来像
    http://localhost:51059
  • 这里
    51059
    是主机系统的端口,映射到
    C1's exposed port

到目前为止 -> 很好:)

行为

区分三 (3) 个环境:

C2 的 Junit 测试

这里启动了一个Testcontainers环境,里面有C1。 请注意,C2 正在运行

IntelliJ Maven Test livecycle
因此,C2 不在显式 Docker 容器中。

C1 的暴露端口由 testcontainers 和它提供给 C2 的代理端口包装。 C2 连接,一切正常。

It works like a charm
- 正如预期的那样。

验证者的junit测试

接下来,

Validator
运行它的
IntelliJ Maven Test livecycle
。 因此,C2 现在位于显式 Docker 容器内。

提供给 C2 的 URL 仍然是指向

http://localhost:TestcontainersProxyPortToC1
的指针。

假设:

  • C2 找不到 C1,因为 C2 正在自己的容器中搜索 C1。

假设成立:

  • RestTemplate:`连接被拒绝``
  • RestClient:
    null

GitLab CI 管道

在 GitLab CI 管道中使用相同的存储库、相同的 Java 代码、可重现......

  • 验证器的junit测试
    • http://HostIP:TestcontainersProxyPortToC1
    • C2 连接到 C1 就足够了

相同的代码在 GitLab CI-Pipeline 中成功,因为

localhost
被替换为实际机器
HostIP

混乱

我的假设是..

  • 验证器的junit测试(mac本地)
  • 验证器的junit测试(GitLab管道)

..必须以同样的方式行事。 两个 C2 容器应通过 ..

之一成功连接或失败
  • http://localhost:TestcontainersProxyPortToC1
  • http://HostIP:TestcontainersProxyPortToC1

还有其他建议如何解决这个问题吗?

还有另一个 Testcontainers 命令,它总是解析主机 IP 地址吗?

任何帮助表示赞赏:)

java docker junit gitlab testcontainers
1个回答
0
投票

问题依然存在...

还有另一个 Testcontainers 命令,它总是解析主机 IP 地址吗?

据我所知,没有这样的“测试容器命令” ...

C1.getHost()
上的分歧行为仍然存在(2024 年 4 月)。

  • 本地:C1.getHost() =>“localhost”
  • Gitlab:C1.getHost() =>“HostIP”

没有任何线索,

C1.getHost()
如何确定何时必须提供哪个答案。

...解决方法

本地主机的 IP 在本地始终是 Testcontainers HostIP。

但是在 GitLab Ci-Pipeline 中,IP 与 HostIP 不同。 因此,与运行程序相比,C1 的 IP 对于 GitLab 来说始终是不同的主机 IP。

因此,必须对先前给出的代码进行以下更改:

        C1BaseURL =
                "http://" + getHostIp(C1) + ":" + C1.getMappedPort(C1Port);

自定义函数看起来像这样:

    private static String getHostIp(GenericContainer<?> C1) {

        if (C1.getHost().equals("localhost")) {
            try {
                return InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                throw new RuntimeException(e);
            }
        }
        return C1.getHost();
    }

还是没有成功?

您可能需要更深入地挖掘:使用Java获取当前机器的IP地址

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.