在Docker容器中从主机连接Unix套接字出现连接拒绝问题

96次阅读
没有评论

问题描述

在Docker中运行一个服务,该服务在Unix域套接字上监听,并在Docker主机上运行一个客户端(Mac上的一个)。客户端在尝试连接时会收到“连接被拒绝”的错误。
在运行服务器时,我将卷映射到本地路径(docker run -it -v /localpath:/var/run myservice),我可以在本地目录中看到创建的套接字文件。
如果我也在Docker中运行客户端(不同的容器实例),或者在本地运行两者,都可以正常工作。但是,如果我在Docker中运行一侧,在本地运行另一侧,它会失败(我尝试了两个方向)。我认为可能是uid/gid不匹配,但看起来没问题,如果我强制它们不同,我会得到权限被拒绝的错误。
我的应用程序使用Java 16的UnixDomainSocketAddress,但我还使用Python脚本进行了测试(使用AF_UNIX套接字),并出现了相同的问题,所以似乎是Docker的问题。有什么想法吗?

解决方案

请注意以下操作可能因Docker版本差异而略有不同。

最佳解决方案

当前情况下,无法在MacOS主机和Linux虚拟机之间共享(挂载)Unix套接字,这是一个无法实现的限制。关于这个问题的相关工作已经停止。
参考链接:https://github.com/docker/for-mac/issues/483

虽然直接共享Unix套接字在这种情况下无法实现,但是可以考虑以下方法来解决问题:

  1. 使用SSH Agent工具(Docker内):您可以使用SSH Agent工具来进行通信,该工具已集成到Docker中,参见上面的参考链接。
  2. 使用网络共享工具:一些程序设计成可以在网络上运行,比如X11或pulseaudio。在Docker Desktop for Mac和Windows上,容器可以通过host.docker.internal访问宿主机。关于Docker在Linux上的情况,请参阅这里
  3. 使用socat进行套接字映射:您可以在主机上使用socat工具将主机上的套接字映射到主机上的端口,然后在容器内部使用socat工具将主机的端口映射到容器内部的套接字。然而,这会引入另一个需要管理的进程。您可能需要:
  4. 在容器内部运行一些聪明的脚本来同时运行您的程序和socat
  5. 在容器内部运行一个init系统/进程管理器。
  6. 理论上,您可以在一个单独的容器中运行socat,然后在应用程序容器和socat容器之间共享套接字。尽管我从未尝试过这样做。

这些方法可能会增加一些复杂性,但可以帮助您实现在Docker容器和主机之间共享Unix套接字的目标。

正文完