ZeroMQ не может связаться между двумя контейнерами Docker

Я пытаюсь настроить игрушечный пример Docker для работы в сети с ZeroMQ в macOS, где serverd.py отправляет сообщение clientd.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": {}
    }
    
  2. я создал serverd.py а также clientd.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:

Dockerfile для serverd.py:

FROM python:3.6

RUN mkdir src
ADD serverd.py /src/
RUN pip install pyzmq
WORKDIR /src/
EXPOSE 5557

Dockerfile для clientd.py:

FROM python:3.6

RUN mkdir src
ADD clientd.py /src/
RUN pip install pyzmq
WORKDIR /src/
EXPOSE 5557

docker-compose.yml для serverd.py:

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

docker-compose для clientd.py:

dev:
  build: .
  command: ["python", "-u", "./clientd.py"]
  net: mynet
  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
    
  2. Если я заменю URI tcp://serverd_dev_1:5557 с tcp://172.18.0.2:5557 он больше не падает, но просто простаивает, не получая никаких сообщений от сервера. Очевидно, я делаю что-то не так, но я не совсем уверен, что именно. Я чувствую, что следил за документацией Docker как можно ближе и был бы очень признателен, если бы у вас были какие-либо идеи.

1 ответ

Решение

Ваша основная проблема заключается в том, что вы настроили свой сервер с адресом tcp://127.0.0.1:5557, Потому что это связано с localhost (127.0.0.1), этот сокет не будет виден никому вне этого контейнера. Поэтому первое, что вам нужно исправить, это адрес привязки сервера. Рассматривать:

address = "tcp://0.0.0.0:5557"

Вторая проблема заключается в том, что вы используете имя serverd_dev_1 в клиенте, но не ясно, на самом деле это будет имя вашего контейнера serverd (это будет зависеть от имен каталогов, используемых при запуске 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

Это запустит оба контейнера в выделенной сети (потому что это то, что docker-compose делает по умолчанию), поэтому вам не нужно явно создавать или ссылаться mynet,

Как вы, вероятно, можете сделать из вышеизложенного, я изменил ваш код, чтобы получить URI ZMQ из переменной среды, потому что это облегчало эксперименты. Вы можете найти вышеупомянутый 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

Эта конфигурация требует, чтобы вы создали mynet прежде чем поднять контейнеры.

Другие вопросы по тегам