У меня странная проблема с простым tcp-подключением к серверу, работающему в докере, которую я не понимаю и не знаю, как действовать.
Я работаю в Windows и использую Docker-Desktop.
Сервер представляет собой простой скрипт Python, который начинается следующим образом:
import socket
from datetime import datetime, timedelta
# listen to tcp on port 27279
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 27279))
s.listen(1)
print("Server is listening")
conn, addr = s.accept()
print(f"Connection from {addr} has been established")
скрипт запускается в контейнере докеров, который запускается с помощью
docker run -p 27180:27279 -it my-image
в журнале контейнера написано Server is listening
и netstat подтверждает, что он действительно прослушивает этот порт.
# netstat -plant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:27279 0.0.0.0:* LISTEN 1/python
когда я пытаюсь подключиться к нему со своей локальной машины, используя PS C:\WINDOWS\system32> ncat localhost 27180
Ничего не произошло.
В Wireshark (edgeshark) я вижу следующие строки
Я интерпретирую это как правильное сопоставление портов, но в соединении отказано.
Я также очень рад любым подсказкам о том, что тестировать/проверять, или любым ресурсам, которые можно прочитать, чтобы лучше понять проблему.
Когда я запускаю тот же скрипт вне контейнера на своем локальном компьютере, он работает без проблем: ncat localhost 27279
(обратите внимание на другой порт, так как в этом случае явно нет сопоставления портов) он работает нормально, в результате чего появляются следующие журналы:
Server is listening
Connection from ('127.0.0.1', 18562) has been established
Я ожидал бы такого же поведения внутри докера.
Я думал, что моя настройка очень похожа на решение, предложенное в Docker, как я могу установить TCP-соединение с контейнером на определенном порту (8080)?, вот только это не работает.
Я попытался перезагрузить контейнер и компьютер на случай обрыва соединений, но безрезультатно.
Я также рассмотрел решение, представленное в разделе Соединение закрывается внешним хостом при подключении к докер-контейнеру через TCP. Теперь IP-адрес, показанный в Wireshark, равен 127.26.9.1
, проблема не устранена.
Этот вопрос Невозможность удаленного подключения к докер-контейнеру также выглядит немного похожим, но я думаю, что он неприменим, поскольку я работаю на своей локальной машине. поэтому брандмауэры не должны быть проблемой (поправьте меня, если я ошибаюсь)
Сетевой режим Docker по умолчанию — режим моста. Что создает «программный мост» согласно их документации.
Он также создает сетевое пространство имен и виртуальный интерфейс, подключенный к этому мосту, для каждого контейнера. Каждый контейнер имеет отдельный шлейф (localhost), который не маршрутизируется даже с опцией -p
.
Вам придется изменить свой скрипт, чтобы прослушивать все интерфейсы, изменив вызов привязки на s.bind(('0.0.0.0', 27279))
. Это заставит скрипт прослушивать собственный виртуальный интерфейс, куда Docker направляет опубликованные порты.
Изменение сетевого режима на режим хоста с использованием флага --net=host
полностью отключит изоляцию пространства имен сети , в результате чего контейнер будет использовать тот же интерфейс обратной связи, что и хост.
Это решение не будет работать на Docker для Windows или Docker для Mac, поскольку оба они запускают контейнеры внутри виртуальной машины, в отличие от изначального запуска Docker в Linux. Это означает, что даже в сетевом режиме хоста они не будут использовать одно и то же устройство обратной связи с хостом.
ваша программа разрешает соединения только с локального хоста, который может быть любым другим процессом, запущенным в контейнере докеров. поскольку вы подключаетесь к этому извне контейнера, ваш скрипт правильно не принимает трафик. Попробуйте обновить свой скрипт для прослушивания на 0.0.0.0.