python - Docker Compose 容器中的 Python 请求
问题描述
问题
- 我有一个 2 容器
docker-compose.yml
文件。 - 其中一个容器是一个小型FastAPI应用程序。
- 另一个只是尝试使用 Python 的
requests
包来访问 API。
我可以使用与尝试访问它的 Python 包中完全相同的代码从外部访问应用程序容器,它可以工作,但它不能在包内工作。
docker-compose.yml
version: "3.8"
services:
read-api:
build:
context: ./read-api
depends_on:
- "toy-api"
networks:
- ds-net
toy-api:
build:
context: ./api
networks:
- ds-net
ports:
- "80:80"
networks:
ds-net:
相关requests
代码
from requests import Session
def post_to_api(session, raw_input, path):
print(f"The script is sending: {raw_input}")
print(f"The script is sending it to: {path}")
response = session.post(path, json={"payload": raw_input})
print(f"The script received: {response.text}")
def get_from_api(session, path):
print(f"The datalake script is trying to GET from: {path}")
response = session.get(path)
print(f"The datalake script received: {response.text}")
session = Session()
session.trust_env = False ### I got that from here: https://stackoverflow.com/a/50326101/534238
get_from_api(session, path="http://localhost/test")
post_to_api(session, "this is a test", path="http://localhost/raw")
运行它 REPL 风格
如果我创建一个交互式会话并在requests
代码部分中运行上面的那些确切命令,它可以工作:
>>> get_from_api(session, path="http://localhost/test")
The script is trying to GET from: http://localhost/test
The script received: {"payload":"Yes, you reached here..."}
>>> post_to_api(session, "this is a test", path="http://localhost/raw")
The script is sending: this is a test
The script is sending it to: http://localhost/raw
The script received: {"payload":"received `raw_input`: this is a test"}
需要明确的是:API 代码仍然作为容器运行,并且该容器仍然是使用docker-compose.yml
文件创建的。(换句话说,当从主机访问时,API 容器工作正常。)
在容器内运行
在容器中做同样的事情,我得到以下(相当长的)错误:
read-api_1 | The script is trying to GET from: http://localhost/test
read-api_1 | Traceback (most recent call last):
read-api_1 | File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 159, in _new_conn
read-api_1 | conn = connection.create_connection(
read-api_1 | File "/usr/local/lib/python3.8/site-packages/urllib3/util/connection.py", line 84, in create_connection
read-api_1 | raise err
read-api_1 | File "/usr/local/lib/python3.8/site-packages/urllib3/util/connection.py", line 74, in create_connection
read-api_1 | sock.connect(sa)
read-api_1 | ConnectionRefusedError: [Errno 111] Connection refused
read-api_1 |
read-api_1 | During handling of the above exception, another exception occurred:
.
.
.
read-api_1 | Traceback (most recent call last):
read-api_1 | File "access_api.py", line 99, in <module>
read-api_1 | get_from_api(session, path="http://localhost/test")
read-api_1 | File "access_datalake.py", line 86, in get_from_api
read-api_1 | response = session.get(path)
read-api_1 | File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 543, in get
read-api_1 | return self.request('GET', url, **kwargs)
read-api_1 | File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 530, in request
read-api_1 | resp = self.send(prep, **send_kwargs)
read-api_1 | File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 643, in send
read-api_1 | r = adapter.send(request, **kwargs)
read-api_1 | File "/usr/local/lib/python3.8/site-packages/requests/adapters.py", line 516, in send
read-api_1 | raise ConnectionError(e, request=request)
read-api_1 | requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=80): Max retries exceeded with url: /test (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7ffa9c69b3a0>: Failed to establish a new connection: [Errno 111] Connection refused'))
ai_poc_work_read-api_1 exited with code 1
尝试解决
我认为这是主机如何在容器组中识别自己,或者是否可以访问该来源,所以我已经尝试更改以下内容,但没有成功:
localhost
我没有用作主机,而是使用read-api
.- 实际上,我是从 开始的
read-api
,但运气不好,但是一旦使用localhost
,我至少可以在主机上使用 REPL,如上所示。 - 我也试过
0.0.0.0
了,没有运气。(我没想到会解决它。)
- 实际上,我是从 开始的
- 我已经更改
ORIGINS
了 API 中允许的 CORS,包括尝试读取的容器的所有可能路径,以及仅"*"
用于标记所有 CORS 来源。没运气。
我究竟做错了什么?似乎问题必须与容器有关,或者可能requests
与容器交互,但我不知道是什么。
以下是我发现的一些相关的 GitHub 问题或 SO 答案,但没有一个能够解决:
解决方案
推荐阅读
- python - Python Datacompy 库:如何将报告字符串保存到 csv 文件中?
- django - Celery 4 + Django + Redis,文档中缺少 django 设置部分?
- postgresql - 从两个表在 postgresql 中进行计算
- object - 如何使用 pytest 夹具实例化被测对象?
- reactjs - React 中的方法仅适用于第一个 Mounting 组件
- r - 在 R Shiny 中使用模型,尝试改变一个参数并检查输出如何变化
- android - Android导航弹出动画不起作用
- c - 为什么我们在 xchg() 之前需要 pushcli()?
- javascript - edge.foreach 不是 vis DataView 的函数
- docker - 带有用户命名空间映射的 Docker 构建和 docker-compose 构建