gpt4 book ai didi

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

转载 作者:IT老高 更新时间:2023-10-28 21:35:30 25 4
gpt4 key购买 nike

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

这是我的设置:

  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.pyclientd.py 并将它们与它们的 Dockerfile 和 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))

我有两个 Dockerfile 和 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

用于 serverd.py 的 docker-compose.yml:

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

clientd.py 的 docker-compose:

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

发送到 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 文档,如果您有任何想法,我将不胜感激。

最佳答案

您的主要问题是您的服务器配置了地址 tcp://127.0.0.1:5557。因为它绑定(bind)到 localhost (127.0.0.1),所以该套接字对于该容器之外的任何东西都是不可见的。因此,您需要修复的第一件事是服务器绑定(bind)地址。考虑:

address = "tcp://0.0.0.0:5557"

第二个问题是您在客户端使用名称 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

这将在专用网络中启动两个容器(因为这是 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

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

关于python - ZeroMQ 无法在两个 Docker 容器之间进行通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45772053/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com