2017-04-09 75 views
5

我在一起在Docker群中运行6个容器。 Kafka + Zookeeper,MongoDB,A,B,C和界面。接口是公共的主要接入点 - 只有此容器发布端口 - 5683.接口容器在启动过程中连接到A,B和C.我正在使用docker-compose文件+ docker stack deploy,每个服务都有一个用作接口主机的名称。一切都开始成功,工作正常。经过一段时间(20分钟,1小时,..)我无法提出接口请求。接口收到我的请求,但应用程序与服务A,B,C或全部服务失去连接。如果我重新启动界面,它可以重新连接到服务A,B,C。泊坞窗服务在一段时间后停止通信

我首先想到让我暴露在每个服务(接口,A,B,C)2个新港口,并与分析器和调试器将它们连接它的应用的问题。应用程序运行正常,没有泄漏,没有阻塞的线程,正常工作和等待连接。调试器告诉我,当我向接口和接口请求尝试请求服务A时,抛出了由同级异常重置的连接。

在调试过程中,我发现有趣的东西。当服务启动并且调试器在一段时间后断开连接时,我将调试器连接到接口。 +我无法重新连接,直到向容器 - >应用程序发出请求。问题 - 握手失败。

,我发现了另一个有趣的事情是,我无法要求既不接口。所以我用wireshark来看看发生了什么,并且:SYN - ACK很好。然后应用程序发布一些数据和接口以FIN,ACK进行响应。我认为这也发生在接口试图请求服务A并且它终止连接时。接口的代码库,A,B和C对于netty服务器是一样的。

最后,我不认为这是一个应用程序问题。为什么?我试图将容器部署为不作为服务。我分别运行每个容器,发布每个端口的服务端点和设置为localhost。 (不覆盖网络)。它正在工作。容器运行没有问题。 +在开始时我并没有说过,当java应用程序(接口,A,B,C)作为独立应用程序运行时没有问题,而不是在docker中运行。

你能帮我解决这个问题吗?为什么码头在覆盖网络的情况下关闭套接字?

我正在使用最新的码头。我也用得比较老。

+0

“接口”,“A”,“B”和“C”是你自己的Java应用程序吗?我很困惑什么是“接口”。另外,你是否在没有Docker Swarm的Docker Compose中尝试过这种方法?我的猜测是,该应用程序与Docker Swarm路由器奇怪地工作,所以也许尝试没有Docker Swarm可能是一个好主意。 –

+0

是的,A,B,C和接口是我的Java应用程序,具有相同的基本代码。共享的基本代码除其他外包含netty。接口只是服务的名称,可以很容易地解释这个问题 - 只有这个接口是公共接口,并且作为其他服务的网关,不会发布端口。 +它负责认证和授权,但这是业务逻辑。 –

+0

正如我写的,我试图分别运行每个容器,每个容器都公布了它公开的端口,并且我使用localhost作为ip,因此interface不是连接到dns主机名,而是连接到localhost。这工作没有任何问题。 –

回答

4

最后,我能够解决这个问题。

发生了什么,还有一次。接口打开与A,B,C的永久TCP连接。当您尝试将这些服务A,B,C作为独立的Java应用程序运行时,一切都正常。当我们将它们码头化并在群集中运行时,它只能工作几分钟。奇怪的是,当你向客户端发出一个请求时,Interface和另一个服务之间的连接中断了。

经过很多很多不成功的测试和调试每个容器我想单独运行每个泊坞窗的容器中,映射端口和端点我指定本地主机。 (每个容器暴露的端口和接口连接到本地主机)有趣的事情发生,它正在工作。当你像这样运行容器时,使用不同的容器网络驱动程序。桥一个。如果您在群集中运行它,则会使用覆盖网络驱动程序。

所以它必须是一些与泊坞窗的网络,而不是与应用程序本身。接下来的步骤是几分钟后从每个容器运行tcpdump,此时应停止工作。它很有意思。

  • 客户端 - >接口(OK,请求接受)
  • 接口 - >(前向请求,因为它属于A)
    • 接口 - > A [POST]
    • A - >接口[RESET]

A被正在重置几分钟而不通信之后打开TCP通信。为什么?

Docker使用IP虚拟服务器,IPVS维护自己的连接表。 IPVS表中CLOSE_WAIT连接的默认超时值为60秒。因此,当服务器在60秒后发送某些内容时,IPVS连接不再可用,并且该数据包对于新的TCP会话看起来无效并且获得RST。在客户端,连接永远保持在FIN_WAIT2状态,因为应用程序仍然打开套接字;内核的fin_wait定时器仅为孤立的TCP套接字启用。

这是我读到的,它是如何理解的。我不确定我对问题的解释是否正确,但基于这些假设,我在界面和A,B,C服务之间实现了乒乓,以防在没有通信的情况下60秒。而且,它正在工作。

+0

非常有用的研究!谢谢。但我在这里有一个更深的问题。我的一个容器是MongoDB,它随机重置连接,我显然无法在这里实现乒乓球.. –

+0

我也在使用MongoDB,并且我对它没有任何问题。我会尝试不同的客户端库。 –

+0

这是Mongo团队的官方客户端库,我设法了解一些重现条件。 如果我的容器通过覆盖网络通信,它工作正常。如果有人试图通过发布的端口进行通信(通过入口网络),则存在风险。 这与客户端库无关,因为我尝试建立两个官方容器:一个是数据库,另一个是运行'mongodump'(相同的映像,只是不同的启动命令),它的工作方式相同。 当我使用发布的端口时它会随机重置连接,并且每当我使用内部网络地址时它都可以正常工作。 –