Как запросить контейнер докеров с хоста?

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

Traceback (most recent call last):
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/requests/adapters.py", line 449, in send
    timeout=timeout
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/urllib3/connectionpool.py", line 727, in urlopen
    method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/urllib3/util/retry.py", line 410, in increment
    raise six.reraise(type(error), error, _stacktrace)
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/urllib3/packages/six.py", line 734, in reraise
    raise value.with_traceback(tb)
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/urllib3/connectionpool.py", line 677, in urlopen
    chunked=chunked,
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/urllib3/connectionpool.py", line 426, in _make_request
    six.raise_from(e, None)
  File "<string>", line 3, in raise_from
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/urllib3/connectionpool.py", line 421, in _make_request
    httplib_response = conn.getresponse()
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/http/client.py", line 1344, in getresponse
    response.begin()
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/http/client.py", line 306, in begin
    version, status, reason = self._read_status()
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/http/client.py", line 267, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/socket.py", line 589, in readinto
    return self._sock.recv_into(b)
urllib3.exceptions.ProtocolError: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))

или это:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/requests/api.py", line 76, in get
    return request('get', url, params=params, **kwargs)
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/requests/sessions.py", line 530, in request
    resp = self.send(prep, **send_kwargs)
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/requests/sessions.py", line 643, in send
    r = adapter.send(request, **kwargs)
  File "/home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/requests/adapters.py", line 516, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='172.17.0.2', port=8000): Max retries exceeded with url: /hello (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f5312c54690>: Failed to establish a new connection: [Errno 111] Connection refused'))

Вот команда, которую я использую при запуске контейнера:

docker run -it --publish 8000:8000 my_server:v1

И скрипт Python, который я запускаю для отправки запроса:

import requests
print(requests.get("http://172.17.0.2:8000/hello").text

Вот эта команда, которую я использовал для поиска IP-адреса контейнера:

$ docker inspect d6c7d98b9fdd | grep IP
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
                    "IPAMConfig": null,
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,

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

Спасибо заранее за вашу помощь.


person ava_punksmash    schedule 10.02.2021    source источник


Ответы (1)


--publish 8000:8000 создает правило переадресации портов для направления пакетов, полученных через порт хоста 8000 (значение слева), на порт 8000 контейнера (значение справа). То есть вы можете добраться до своего контейнера с помощью <hostIpOrName>:8000. На хосте вы можете использовать localhost:8000.

Вам лучше не использовать IP-адрес контейнера в своем коде, потому что он может часто меняться.

Следует также отметить, что для того, чтобы это работало, ваш бэкэнд должен прослушивать что-то, кроме IP-адреса loopback (127.0.0.1 или аналогичный). Используйте 0.0.0.0, чтобы разрешить приложению принимать подключения с любого IP-адреса. Для ray этого можно добиться с помощью serve.start(http_host="0.0.0.0").

person anemyte    schedule 10.02.2021
comment
Я пробовал print(requests.get("http://127.0.0.1:8000/hello").text), но это не сработало :/ - person ava_punksmash; 10.02.2021
comment
@ava_punksmash Приложение внутри контейнера прослушивает любой IP-адрес (0.0.0.0) или только localhost/128.0.0.1? Если это последнее, то любая внешняя связь невозможна, если только вы не отключите сетевую изоляцию, запустив контейнер в сетевом режиме хоста. - person anemyte; 10.02.2021
comment
спасибо за ваш ответ, я запускаю экземпляр ray serve, который сам подключен к лучевому кластеру. Насколько я понимаю, это сервер, подключенный к другому серверу. Но сказано, что он прослушивает 127.0.0.1:8000: 2021-02-10 01:43:34,664 INFO worker.py:657 -- Connecting to existing Ray cluster at address: 172.17.0.2:6379 (pid=128) 2021-02-10 01:43:35,222 INFO controller.py:346 -- Starting router with name 'SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-node:172.17.0.2-0' on node 'node:172.17.0.2-0' listening on '127.0.0.1:8000' (pid=153) INFO: Started server process [153] - person ava_punksmash; 10.02.2021
comment
Если вы не знакомы с ray serve и хотели бы узнать больше: docs. ray.io/en/master/serve/index.html - person ava_punksmash; 10.02.2021
comment
@ava_punksmash Это именно тот случай. Вам нужно заставить его прослушивать любой IP-адрес, чтобы вы могли получить к нему доступ с хоста или другой машины в сети: serve.start(http_host="0.0.0.0") - person anemyte; 10.02.2021
comment
ОК я понимаю, прежде чем запустить его внутри контейнера, я начал, запустив его на хосте, он мне говорит (pid=7720) 2021-02-10 11:31:16,721 INFO controller.py:346 -- Starting router with name 'SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-node:192.168.1.43-0' on node 'node:192.168.1.43-0' listening on '0.0.0.0:8000' (pid=7744) Task exception was never retrieved (pid=7744) future: <Task finished coro=<HTTPProxyActor.run() done, defined at /home/user/miniconda3/envs/dl_project/lib/python3.7/site-packages/ray/serve/http_proxy.py:158> exception=OSError(98, 'Address already in use')> - person ava_punksmash; 10.02.2021
comment
Я думаю, я должен найти то, что уже работает - person ava_punksmash; 10.02.2021
comment
@ava_punksmash, вероятно, контейнер. - person anemyte; 10.02.2021
comment
Итак, я работаю над этим, теперь он работает локально, я попробую его в контейнере. - person ava_punksmash; 10.02.2021