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

Jim*_*y C 6 python configuration-files docker

我正在尝试用macOS中的ZeroMQ建立Docker网络的玩具示例,其中serverd.pyclientd.py客户端发送消息,客户端只需使用PUSH/PULL显示它.如果我在容器外面运行它们就可以正常工作,但是当我在单独的容器中运行时,我很难让它们进行通信.看起来我clientd.py无法连接到容器名称,尽管它们位于同一个桥接网络中.我尝试用分配的IP地址替换主机名serverd_dev_1,但这也不起作用.

这是我的设置:

  1. 我创建了一个新的网络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": {}
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 我创建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)
Run Code Online (Sandbox Code Playgroud)

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))
Run Code Online (Sandbox Code Playgroud)

我有两个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
Run Code Online (Sandbox Code Playgroud)

clientd.py的Dockerfile:

FROM python:3.6

RUN mkdir src
ADD clientd.py /src/
RUN pip install pyzmq
WORKDIR /src/
EXPOSE 5557
Run Code Online (Sandbox Code Playgroud)

serverd.py的docker-compose.yml:

dev:
  build: .
  command: ["python", "-u", "./serverd.py"]
  net: mynet
Run Code Online (Sandbox Code Playgroud)

用于clientd.py的docker-compose:

dev:
  build: .
  command: ["python", "-u", "./clientd.py"]
  net: mynet
Run Code Online (Sandbox Code Playgroud)
  1. serverd.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
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果我tcp://serverd_dev_1:5557tcp://172.18.0.2:5557它替换URI 不再崩溃,但它只是空闲而没有从服务器接收任何消息.显然我做错了什么,但我不完全确定究竟是什么.我觉得我一直在尽可能地关注Docker文档,如果您有任何想法,我将非常感激.

lar*_*sks 10

您的主要问题是您已使用地址配置服务器tcp://127.0.0.1:5557.因为它绑定到localhost(127.0.0.1),所以该容器之外的任何东西都不会看到该套接字.所以你需要修复的第一件事是服务器绑定地址.考虑:

address = "tcp://0.0.0.0:5557"
Run Code Online (Sandbox Code Playgroud)

第二个问题是您serverd_dev_1在客户端中使用该名称,但不清楚这实际上是您的服务器容器的名称(这取决于您运行时使用的目录名称docker-compose up).

使用单个docker-compose.yaml文件可以更轻松地管理命名.例如,我设置如下:

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
Run Code Online (Sandbox Code Playgroud)

这将在专用网络中启动两个容器(因为这是docker-compose默认执行的操作),因此您无需显式创建或引用mynet.

正如您可以从上面推断的那样,我修改了您的代码以从环境变量中获取ZMQ uri,因为这样可以更容易地进行实验.您可以在以下位置找到上面的docker-compose.yaml和修改后的代码:

更新

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

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
Run Code Online (Sandbox Code Playgroud)

此配置要求您mynet在启动容器之前创建.