gpt4 book ai didi

python-3.x - PyZMQ Dockerized pub sub - sub不会收到消息

转载 作者:行者123 更新时间:2023-12-02 18:52:29 27 4
gpt4 key购买 nike

我想构建一个模块化系统,其中的模块通过 ZeroMQ 进行通信。为了提高可用性,我想对其中一些模块进行 Dockerize,这样用户就不必设置环境了。但是,我无法让 Docker 化的发布者让非 Docker 化的订阅者接收其消息。

系统

  • Ubuntu 18.04
  • Python 3.7
  • libzmq 版本 4.2.5
  • pyzmq 版本为 17.1.2
  • Docker 版本 18.09.0,内部版本 4d60db4

最小测试用例

zmq_sub.py

# CC0

import zmq


def main():
# ZMQ connection
url = "tcp://127.0.0.1:5550"
ctx = zmq.Context()
socket = ctx.socket(zmq.SUB)
socket.bind(url) # subscriber creates ZeroMQ socket
socket.setsockopt(zmq.SUBSCRIBE, ''.encode('ascii')) # any topic
print("Sub bound to: {}\nWaiting for data...".format(url))

while True:
# wait for publisher data
topic, msg = socket.recv_multipart()
print("On topic {}, received data: {}".format(topic, msg))


if __name__ == "__main__":
main()

zmq_pub.py

# CC0

import zmq
import time


def main():
# ZMQ connection
url = "tcp://127.0.0.1:5550"
ctx = zmq.Context()
socket = ctx.socket(zmq.PUB)
socket.connect(url) # publisher connects to subscriber
print("Pub connected to: {}\nSending data...".format(url))

i = 0

while True:
topic = 'foo'.encode('ascii')
msg = 'test {}'.format(i).encode('ascii')
# publish data
socket.send_multipart([topic, msg]) # 'test'.format(i)
print("On topic {}, send data: {}".format(topic, msg))
time.sleep(.5)

i += 1


if __name__ == "__main__":
main()

当我打开 2 个终端并运行时:

  • python zmq_sub.py
  • python zmq_pub.py

订阅者正确接收数据(关于主题 b'foo',收到的数据:b'test 1')

Dockerfile

我创建了以下Dockerfile:

FROM python:3.7.1-slim

MAINTAINER foo bar <<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="187e7777586b687975367d7f7f6b" rel="noreferrer noopener nofollow">[email protected]</a>>

RUN apt-get update && \
apt-get install -y --no-install-recommends \
gcc

WORKDIR /app
COPY requirements.txt /app
RUN pip install -r requirements.txt

COPY zmq_pub.py /app/zmq_pub.py

EXPOSE 5550

CMD ["python", "zmq_pub.py"]

然后我使用以下命令成功构建了一个 Dockerized 发布者: sudo docker build 。 -t foo/bar

尝试

尝试 1

现在我有了带有发布者的 docker 容器,我正在尝试让我的非 docker 订阅者接收数据。我运行以下 2 个命令:

  1. python zmq_sub.py
  2. sudo docker run -it foo/bar

我看到我的发布者在容器内发布数据,但我的订阅者什么也没收到。

尝试 2

由于我必须将 dockerized 发布者的内部端口映射到我机器的端口,因此我运行以下 2 个命令:

  1. python zmq_sub.py
  2. sudo docker run -p 5550:5550 -it foo/bar

However, then I receive the following error: docker: Error response from daemon: driver failed programming external connectivity on endpoint objective_shaw (09b5226d89a815ce5d29842df775836766471aba90b95f2e593cf5ceae0cf174): Error starting userland proxy: listen tcp 0.0.0.0:5550: bind: address已在使用。

在我看来,我的订阅者已经绑定(bind)到 127.0.0.1:5550,因此当我尝试映射它时 Docker 无法再执行此操作。如果我将其更改为 -p 5549:5550,Docker 不会给出错误,但情况与尝试 1 相同。

问题

如何让我的 Docker 化发布者向我的非 Docker 化订阅者发布数据?

代码

编辑 1:更新了代码,还提供了如何使用 docker-compose 进行自动 IP 推断的示例。

GitHub:https://github.com/NumesSanguis/pyzmq-docker

最佳答案

这主要是一个 docker 网络问题,并不特定于 pyzmq 或 Zeromq。对于尝试从容器连接到主机的任何内容,您都会遇到同样的问题。

需要明确的是,在这个示例中,您有一个在主机上运行的服务器(zmq_sub.py,它调用bind),并且您希望从在docker内运行的客户端连接到它容器(zmq_pub.py)。

由于 docker 容器是连接的容器,因此您不需要进行任何 docker 端口暴露或转发。 EXPOSE 和转发端口仅用于使连接容器成为可能(即在容器中调用bind),而不是进行出站连接来自 一个容器,这就是这里发生的事情。

这里最主要的是,当涉及到与 docker 联网时,您应该将每个容器视为本地网络上的一台单独的机器。为了能够从其他容器或主机连接,服务应该绑定(bind)到所有接口(interface)(或至少是可访问的接口(interface))。绑定(bind)到容器中的本地主机意味着只有该容器中的其他进程才能与其通信。同样,在主机上绑定(bind) localhost 意味着 docker 容器不应该能够连接。

所以第一个改变是你的绑定(bind) URL 应该是:

url = 'tcp://0.0.0.0:5550'
...
socket.bind(url)

或者选择与您的 Docker 虚拟网络相对应的 IP 地址。

然后,您的 connect url 需要是从容器中看到的主机的 IP。这可以通过 ifconfig 找到。通常任何 IP 地址都可以,但如果您有 docker0 网络,那么这将是合理的选择。

关于python-3.x - PyZMQ Dockerized pub sub - sub不会收到消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53802691/

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