ZeroMQ无法在两个Docker容器之间进行通信

我正在尝试在macOS中设置一个与ZeroMQ的Docker联网的玩具示例,其中serverd.py将消息发送到clientd.py ,客户端使用PUSH / PULL将其显示出来。 如果我在容器外部运行它们,它们工作正常,但是在单独的容器中运行时,它们无法使它们进行通信。 看起来像我的clientd.py无法连接到容器名称,尽pipe他们是在同一个桥梁networking。 我尝试使用为serverd_dev_1分配的IP地址replace主机名,但是这也不起作用。

这是我的设置:

  1. 我创build了一个新的networking与docker network create -d bridge mynet 。 以下是来自docker network inpsect mynet的输出:

     { "Name": "mynet", "Id": "cec7f8037c0ef173d9a9a66065bb46cb6a631fea1c0636876ccfe5a792f92412", "Created": "2017-08-19T09:52:44.8034344Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "5fa8dc2f8059d675dfd3dc4f2e50265be99361cd8a8f2730eb273772c0148742": { "Name": "serverd_dev_1", "EndpointID": "3a62e82b1b34d5c08f2a9f340ff93aebd65c0f3dfde70e354819befe21422d0b", "MacAddress": "02:42:ac:12:00:02", "IPv4Address": "172.18.0.2/16", "IPv6Address": "" }, "ec1e5f8c525ca8297611e02bcd3a64198fda3a07ce8ed82c0c4298609ba0357f": { "Name": "clientd_dev_1", "EndpointID": "a8ce6f178a225cb2d39ac0009e16c39abdd2dae02a65ba5fd073b7900f059bb8", "MacAddress": "02:42:ac:12:00:03", "IPv4Address": "172.18.0.3/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } 
  2. 我创build了serverd.pyclientd.py ,并将它们与Dockerfiles和docker-compose.yml放在不同的文件夹中:

serverd.py:

 import zmq import time context = zmq.Context() socket = context.socket(zmq.PUSH) address = "tcp://127.0.0.1:5557" socket.bind(address) print("Sending to {}...".format(address)) while True: message = socket.send_string("Got it!") print("Sent message") time.sleep(1) 

clientd.py:

 import zmq context = zmq.Context() socket = context.socket(zmq.PULL) address = "tcp://serverd_dev_1:5557" socket.connect(address) print("Listening to {}...".format(address)) while True: message = socket.recv_string() print("Client got message! {}".format(message)) 

我有两个Dockerfiles和docker-compose.yml:

serverd.py的Dockerfile:

 FROM python:3.6 RUN mkdir src ADD serverd.py /src/ RUN pip install pyzmq WORKDIR /src/ EXPOSE 5557 

适用于clientd.py的Dockerfile:

 FROM python:3.6 RUN mkdir src ADD clientd.py /src/ RUN pip install pyzmq WORKDIR /src/ EXPOSE 5557 

docker-compose.yml for serverd.py:

 dev: build: . command: ["python", "-u", "./serverd.py"] net: mynet 

docker-compose for clientd.py:

 dev: build: . command: ["python", "-u", "./clientd.py"] net: mynet 
  1. serverd.pyserverd.py一样按预期启动docker-compose up

Sending to tcp://127.0.0.1:5557...

  1. clientd.py不会像这样启动,因为它找不到主机名tcp://serverd_dev_1:5557

     Attaching to countd_dev_1 dev_1 | Traceback (most recent call last): dev_1 | File "./countd.py", line 6, in <module> dev_1 | socket.connect(address) dev_1 | File "zmq/backend/cython/socket.pyx", line 528, in zmq.backend.cython.socket.Socket.connect (zmq/backend/cython/socket.c:5971) dev_1 | File "zmq/backend/cython/checkrc.pxd", line 25, in zmq.backend.cython.checkrc._check_rc (zmq/backend/cython/socket.c:10014) dev_1 | zmq.error.ZMQError: Invalid argument 
  2. 如果我使用tcp://serverd_dev_1:5557replaceURI tcp://serverd_dev_1:5557 ,它不会再崩溃,但是它只是在没有收到来自服务器的任何消息的情况下闲置。 显然我做错了什么,但我不完全确定究竟是什么。 我觉得我一直在跟随Docker文档,如果您有任何想法,我会非常感激。

您的主要问题是您已经使用地址tcp://127.0.0.1:5557configuration了您的服务器。 因为它绑定到本地主机( 127.0.0.1 ),该套接字不会被该容器外的任何东西看到。 所以你需要解决的第一件事是服务器绑定地址。 考虑:

 address = "tcp://0.0.0.0:5557" 

第二个问题是你在客户端使用名字serverd_dev_1 ,但是不清楚这实际上是你的serverd容器的名字(当你运行docker-compose up时,这取决于你正在使用的目录名称)。

通过一个docker-compose.yaml文件,命名更容易pipe理。 例如,我设置这样的事情:

 version: "2" services: serverd: build: serverd command: ["python", "-u", "./serverd.py"] environment: SERVER_LISTEN_URI: tcp://0.0.0.0:5557 clientd: build: clientd command: ["python", "-u", "./clientd.py"] environment: SERVER_CONNECT_URI: tcp://serverd:5557 

这将在专用networking中启动这两个容器(因为这是默认情况下mynet -compose所做的),所以您不需要显式创build或引用mynet

正如你从上面可以推断,我修改了你的代码来从一个环境variables中获得ZMQ的uri,因为这样做更容易实验。 您可以在以下位置find上面的docker-compose.yaml和修改后的代码:

更新

如果你真的想/需要有两个单独docker-compose.yaml文件,我已经更新了示例以包含每个服务文件。 这些示例使用alias选项来提供客户端可以联系服务器的名称,而不pipe您的本地目录布局如何:

 version: "2" services: serverd: build: . command: ["python", "-u", "./serverd.py"] environment: SERVER_LISTEN_URI: tcp://0.0.0.0:5557 networks: mynet: aliases: - serverd networks: mynet: external: True 

此configuration要求您在调出容器之前创buildmynet

Interesting Posts