![](/img/trans.png)
[英]PUB/SUB model of pyzmq not receiving messages inside a multiprocessing.Process
[英]PyZMQ Dockerized pub sub - sub won't receive messages
我想建立一個模塊化系統,模塊通過ZeroMQ進行通信。 為了提高可用性,我想要Dockerize(一些)這些模塊,以便用戶不必設置環境。 但是,我無法讓一個dockerized發布者讓非dockerized訂閱者收到它的消息。
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個終端並運行時:
訂戶無錯誤地接收數據( On topic b'foo', received data: b'test 1'
)
我創建了以下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
現在我有我的docker容器和發布者,我試圖讓我的非dockerized訂閱者接收數據。 我運行以下2個命令:
python zmq_sub.py
sudo docker run -it foo/bar
我在容器發布數據中看到我的發布者,但我的訂閱者什么也沒收到。
有了這個想法,我必須將我的dockerized發布者的內部端口映射到我的機器端口,我運行以下兩個命令:
python zmq_sub.py
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.