Я хочу построить модульную систему с модулями, связывающимися через ZeroMQ.Чтобы повысить удобство использования, я хочу Dockerize (некоторые) из этих модулей, чтобы пользователям не приходилось настраивать среду.Тем не менее, я не могу заставить докерализованного издателя получать сообщения, полученные не докеризированным подписчиком.
Система
- 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
Попытки
Попытка 1
Теперь у меня есть докерКонтейнер с издателем, я пытаюсь, чтобы мой не докеризованный подписчик получил данные.Я запускаю следующие 2 команды:
python zmq_sub.py
sudo docker run -it foo/bar
Я вижу своего издателя внутри контейнера, публикующего данные, но мой подписчикНичего не получает.
Попытка 2
С мыслью, что мне нужно сопоставить внутренний порт моего докеризированного издателя с портом моей машины, я запускаю следующие 2 команды:
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.
Вопрос
Как мне заставить моего докеризованного издателя публиковатьданные для моего недокурсированного абонента?
Код
Редактировать 1: Код обновлен, чтобы также дать пример того, как использовать docker-compose
для автоматического IP-вывода.
GitHub: https://github.com/NumesSanguis/pyzmq-docker