TCP-соединение с докер-контейнером не удалось

У меня странная проблема с простым 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) я вижу следующие строки

Источник Место назначения Протокол Информация 172.17.0.1 172.17.0.2 TCP 60394 -> 27279 [СИН] 172.17.0.2 172.17.0.1 TCP 27279 -> 60394 [RST, ACK]

Я интерпретирую это как правильное сопоставление портов, но в соединении отказано.

Я также очень рад любым подсказкам о том, что тестировать/проверять, или любым ресурсам, которые можно прочитать, чтобы лучше понять проблему.

что я уже пробовал/вопросы по теме

Когда я запускаю тот же скрипт вне контейнера на своем локальном компьютере, он работает без проблем: 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, проблема не устранена.

Этот вопрос Невозможность удаленного подключения к докер-контейнеру также выглядит немного похожим, но я думаю, что он неприменим, поскольку я работаю на своей локальной машине. поэтому брандмауэры не должны быть проблемой (поправьте меня, если я ошибаюсь)

ваша программа разрешает соединения только с локального хоста, который может быть любым другим процессом, запущенным в контейнере докеров. поскольку вы подключаетесь к этому извне контейнера, ваш скрипт правильно не принимает трафик. Попробуйте обновить свой скрипт для прослушивания на 0.0.0.0.

Chris Doyle 11.04.2024 19:18
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Kubernetes - это портативная, расширяемая платформа с открытым исходным кодом для управления контейнерными рабочими нагрузками и сервисами, которая...
Как создать PHP Image с нуля
Как создать PHP Image с нуля
Сегодня мы создадим PHP Image from Scratch для того, чтобы легко развернуть базовые PHP-приложения. Пожалуйста, имейте в виду, что это разработка для...
0
1
224
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Привязка ко всем интерфейсам

Сетевой режим Docker по умолчанию — режим моста. Что создает «программный мост» согласно их документации.

Он также создает сетевое пространство имен и виртуальный интерфейс, подключенный к этому мосту, для каждого контейнера. Каждый контейнер имеет отдельный шлейф (localhost), который не маршрутизируется даже с опцией -p.

Вам придется изменить свой скрипт, чтобы прослушивать все интерфейсы, изменив вызов привязки на s.bind(('0.0.0.0', 27279)). Это заставит скрипт прослушивать собственный виртуальный интерфейс, куда Docker направляет опубликованные порты.

Альтернативное решение для Linux

Изменение сетевого режима на режим хоста с использованием флага --net=host полностью отключит изоляцию пространства имен сети , в результате чего контейнер будет использовать тот же интерфейс обратной связи, что и хост.

Это решение не будет работать на Docker для Windows или Docker для Mac, поскольку оба они запускают контейнеры внутри виртуальной машины, в отличие от изначального запуска Docker в Linux. Это означает, что даже в сетевом режиме хоста они не будут использовать одно и то же устройство обратной связи с хостом.

Другие вопросы по теме