You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同一Docker网络下无法从另一个Testcontainer连接Neo4j Testcontainer

解决Testcontainers同一网络下容器连接失败问题

我来帮你分析下这个问题——你遇到的ServiceUnavailableException,核心原因是容器间通信时用错了端口类型。

问题根源

当两个容器处于同一个Docker网络时,它们是通过内部网络直接通信的,这时候应该用容器自身暴露的内部端口(也就是你定义的NEO4j_EXPOSED_PORT=7687),而不是Testcontainers映射到宿主机的随机端口。你现在用neo4jContainer.getMappedPort(NEO4j_EXPOSED_PORT)拿到的是宿主机上的端口(比如错误日志里的32819),这个端口在容器内部网络是无效的,所以myservice容器根本找不到这个端口对应的服务。

直接修正方案

把myservice容器的Neo4j URI配置改成使用内部端口:

private static GenericContainer myserviceContainer = new GenericContainer("myservice-container")
    .withExposedPorts(MYSERVICE_EXPOSED_PORT)
    .withNetwork(network)
    // 这里直接用内部端口7687,加上网络别名neo4j即可
    .withEnv("spring.data.neo4j.uri", "bolt://neo4j:" + NEO4j_EXPOSED_PORT);

额外优化建议

除了端口问题,还有两个小细节可以让你的容器配置更可靠:

  1. 移除手动start()调用:Testcontainers的Rule会自动管理容器的启动、停止和依赖顺序,你现在的static { ... start() }代码块会打乱这个生命周期管理,建议直接删掉这些静态启动代码,完全交给RuleChain处理。

  2. 更可靠的Neo4j就绪等待:只等待端口监听可能不够,Neo4j启动后还需要一点时间初始化服务,可以改成等待日志输出特定内容,确保服务真正可用:

    .waitingFor(Wait.forLogMessage(".*Remote interface available at.*", 1))
    

修正后的完整代码

import org.junit.Rule;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;

@ContextConfiguration(initializers = RuleCombination.Initializer.class)
public abstract class RuleCombination {
    private static final Integer NEO4j_EXPOSED_PORT = 7687;
    private static final Integer MYSERVICE_EXPOSED_PORT = xxxx; // 替换为你的实际服务端口

    private static Network network = Network.newNetwork();

    private static GenericContainer neo4jContainer = new GenericContainer("preconfigured-neo4j-container")
            .withExposedPorts(NEO4j_EXPOSED_PORT)
            .withNetwork(network)
            .withNetworkAliases("neo4j")
            .withEnv("NEO4J_dbms_security_auth__enabled", "false")
            .waitingFor(Wait.forLogMessage(".*Remote interface available at.*", 1));

    private static GenericContainer myserviceContainer = new GenericContainer("myservice-container")
            .withExposedPorts(MYSERVICE_EXPOSED_PORT)
            .withNetwork(network)
            .withEnv("spring.data.neo4j.uri", "bolt://neo4j:" + NEO4j_EXPOSED_PORT);

    @Rule
    public TestRule containerCombination = RuleChain.outerRule(neo4jContainer).around(myserviceContainer);

    public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            EnvironmentTestUtils.addEnvironment(
                    configurableApplicationContext.getEnvironment(),
                    "feign.myservice.url: http://" + myserviceContainer.getContainerIpAddress() + ":" + myserviceContainer.getMappedPort(MYSERVICE_EXPOSED_PORT)
            );
        }
    }
}

这样修改后,myservice容器就能通过网络别名neo4j和内部端口7687正常连接到Neo4j容器了。

内容的提问来源于stack exchange,提问作者Ira Re

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:22:13