同一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);
额外优化建议
除了端口问题,还有两个小细节可以让你的容器配置更可靠:
移除手动start()调用:Testcontainers的Rule会自动管理容器的启动、停止和依赖顺序,你现在的
static { ... start() }代码块会打乱这个生命周期管理,建议直接删掉这些静态启动代码,完全交给RuleChain处理。更可靠的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
相关产品推荐
相关产品推荐

