MacOS下Rancher Desktop无法配合JUnit Testcontainers使用的问题
我在MacOS上运行Rancher Desktop,Docker CLI可以正常执行docker run启动容器,但JUnit Testcontainers测试代码执行时报错。
简化后的JUnit测试代码
@Testcontainers class FactoryDiscoveryDataIT { @Container private static final PostgreSQLContainer POSTGRES_CONTAINER = new PostgreSQLContainer("postgres:11.11-alpine") .withDatabaseName("psql-link-test"); }
报错信息
2023-03-08 08:14:28,816 ERROR [main] org.testcontainers.dockerclient.DockerClientProviderStrategy: Could not find a valid Docker environment. Please check configuration. Attempted configurations were: 2023-03-08 08:14:28,816 ERROR [main] org.testcontainers.dockerclient.DockerClientProviderStrategy: UnixSocketClientProviderStrategy: failed with exception InvalidConfigurationException (Could not find unix domain socket). Root cause NoSuchFileException (/var/run/docker.sock) 2023-03-08 08:14:28,816 ERROR [main] org.testcontainers.dockerclient.DockerClientProviderStrategy: As no valid configuration was found, execution cannot continue Test ignored. java.lang.IllegalStateException: Could not find a valid Docker environment. Please see logs and check configuration at org.testcontainers.dockerclient.DockerClientProviderStrategy.lambda$getFirstValidStrategy$6(DockerClientProviderStrategy.java:257) at java.base/java.util.Optional.orElseThrow(Optional.java:403) at org.testcontainers.dockerclient.DockerClientProviderStrategy.getFirstValidStrategy(DockerClientProviderStrategy.java:247) at org.testcontainers.DockerClientFactory.getOrInitializeStrategy(DockerClientFactory.java:135) at org.testcontainers.DockerClientFactory.client(DockerClientFactory.java:171) at org.testcontainers.DockerClientFactory$1.getDockerClient(DockerClientFactory.java:89) at com.github.dockerjava.api.DockerClientDelegate.authConfig(DockerClientDelegate.java:108) at org.testcontainers.containers.GenericContainer.start(GenericContainer.java:321) at org.testcontainers.junit.jupiter.TestcontainersExtension$StoreAdapter.start(TestcontainersExtension.java:242) at org.testcontainers.junit.jupiter.TestcontainersExtension$StoreAdapter.access$200(TestcontainersExtension.java:229) at org.testcontainers.junit.jupiter.TestcontainersExtension.lambda$null$1(TestcontainersExtension.java:56) at org.junit.jupiter.engine.execution.ExtensionValuesStore.lambda$getOrComputeIfAbsent$4(ExtensionValuesStore.java:86) at org.junit.jupiter.engine.execution.ExtensionValuesStore$MemoizingSupplier.computeValue(ExtensionValuesStore.java:223) at org.junit.jupiter.engine.execution.ExtensionValuesStore$MemoizingSupplier.get(ExtensionValuesStore.java:211) at org.junit.jupiter.engine.execution.ExtensionValuesStore$StoredValue.evaluate(ExtensionValuesStore.java:191) at org.junit.jupiter.engine.execution.ExtensionValuesStore$StoredValue.access$100(ExtensionValuesStore.java:171) at org.junit.jupiter.engine.execution.ExtensionValuesStore.getOrComputeIfAbsent(ExtensionValuesStore.java:89) at org.junit.jupiter.engine.execution.NamespaceAwareStore.getOrComputeIfAbsent(NamespaceAwareStore.java:53) at org.testcontainers.junit.jupiter.TestcontainersExtension.lambda$beforeAll$2(TestcontainersExtension.java:56) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.testcontainers.junit.jupiter.TestcontainersExtension.beforeAll(TestcontainersExtension.java:55) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeBeforeAllCallbacks$10(ClassBasedTestDescriptor.java:381) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeBeforeAllCallbacks(ClassBasedTestDescriptor.java:381) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:205) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:80) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:148) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
我确认代码本身没问题,在minikube环境下可以正常运行——通过设置minikube docker-env导出的环境变量,就能让minikube作为构建环境。
请问Rancher Desktop有没有类似的解决方案?有没有其他方法让JUnit Testcontainers使用我的Rancher Desktop安装?
解决方案
方法1:导入Rancher Desktop的Docker环境变量
和minikube逻辑一致,Rancher Desktop提供了导出Docker环境配置的命令。在终端执行以下命令,将配置临时导入当前会话:
eval "$(rdctl shell docker context export rancher-desktop)"
之后在同一个终端中运行测试代码,Testcontainers就能识别到Rancher Desktop的Docker环境。
如果需要永久生效,可将上述命令添加到你的shell配置文件(如~/.zshrc或~/.bash_profile)中,每次打开终端会自动加载配置。
方法2:手动指定Docker Socket路径
Rancher Desktop在MacOS上的Docker Socket路径为~/.rd/docker.sock,而Testcontainers默认查找/var/run/docker.sock,可通过以下两种方式指定正确路径:
方式A:设置环境变量
运行测试前执行:
export DOCKER_HOST=unix://$HOME/.rd/docker.sock
再启动测试即可。
方式B:在代码中配置Testcontainers
在测试类中添加静态代码块,指定Socket路径:
static { String homeDir = System.getProperty("user.home"); System.setProperty("docker.host", "unix://" + homeDir + "/.rd/docker.sock"); }
方法3:创建Socket软链接
如果不想每次设置环境变量或修改代码,可创建默认路径到Rancher Desktop Socket的软链接:
sudo ln -s ~/.rd/docker.sock /var/run/docker.sock
执行后Testcontainers会自动识别到Docker环境。
内容的提问来源于stack exchange,提问作者Kaputnik120

