簡體   English   中英

PyZMQ Dockerized pub sub-sub不會收到消息

[英]PyZMQ Dockerized pub sub - sub won't receive messages

我想建立一個模塊化系統,模塊通過ZeroMQ進行通信。 為了提高可用性,我想要Dockerize(一些)這些模塊,以便用戶不必設置環境。 但是,我無法讓一個dockerized發布者讓非dockerized訂閱者收到它的消息。

系統

  • 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

訂戶無錯誤地接收數據( On topic b'foo', received data: b'test 1'

Dockerfile

我創建了以下Dockerfile

FROM python:3.7.1-slim

MAINTAINER foo bar <foo@spam.eggs>

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 docker sudo docker build . -t foo/bar sudo docker build . -t foo/bar

嘗試

嘗試1

現在我有我的docker容器和發布者,我試圖讓我的非dockerized訂閱者接收數據。 我運行以下2個命令:

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

我在容器發布數據中看到我的發布者,但我的訂閱者什么也沒收到。

嘗試2

有了這個想法,我必須將我的dockerized發布者的內部端口映射到我的機器端口,我運行以下兩個命令:

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

但是,我收到以下錯誤: 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 already in use.

在我看來,我的訂戶已經綁定到127.0.0.1:5550 ,因此當我嘗試映射時,Docker不能再這樣做了。 如果我將其更改為-p 5549:5550 ,Docker不會給出錯誤,但是它與嘗試1的情況相同。

如何讓我的dockerized發布者將數據發布到我的非dockerized訂閱者?

編輯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聯網時,您應該將每個容器視為本地網絡上的單獨機器。 為了可以從其他容器或主機連接,服務應該綁定到所有接口(或至少是可訪問的接口)。 綁定到容器中的localhost意味着只有該容器中的其他進程才能與之通信。 同樣,在主機上綁定localhost意味着docker容器不能連接。

所以第一個改變是你的綁定網址應該是:

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

或者選擇與docker虛擬網絡對應的IP地址。

然后,您的connect URL需要是從容器中看到的主機的IP。 這可以通過ifconfig找到。 通常任何IP地址都可以,但如果你有一個docker0網絡,這將是合乎邏輯的選擇。

我在這篇文章中遇到了同樣的問題。

您的問題是容器localhost( 127.0.0.1 )與其他容器或主機localhost有所不同。

因此,要解決此問題,請在.bind()使用tcp://*:5550而不是127.0.0.1或機器IP。

然后,你應該創建一個公開IP並聲明在容器和主機之間分配IP(我使用docker-compose在上面提到的SO帖子上做這個)。 我認為在您的情況下,您將嘗試以下內容:

EXPOSE 5550

sudo docker run -p 5550:5550 -it foo/bar

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM