简体   繁体   English

Docker 中的 Python 请求组合容器

[英]Python requests in Docker Compose containers

Problem问题

  • I have a 2-container docker-compose.yml file.我有一个 2 容器docker-compose.yml文件。
  • One of the containers is a small FastAPI app.其中一个容器是一个小型FastAPI应用程序。
  • The other is just trying to hit the API using Python's requests package.另一个只是尝试使用 Python 的requests package 来访问 API。

I can access the app container from outside with the exact same code as is in the Python package trying to hit it, and it works , but it will not work within the package.我可以使用与 Python package 中的代码完全相同的代码从外部访问应用程序容器,并且它可以工作,但它在 ZEFE90A8E604A7C640E88D03AD67F 中不起作用。

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:

Relevant requests code相关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")

Running It REPL-Style运行它 REPL 风格

If I create an interactive session and run those exact commands above in the requests code portion, it works:如果我创建一个交互式 session 并在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"}

To be clear: the API code is still being run as a container, and that container was still created with the docker-compose.yml file.需要明确的是:API 代码仍在作为容器运行,并且该容器仍然是使用docker-compose.yml文件创建的。 (In other words, the API container is working properly, when accessed from the host.) (换句话说,当从主机访问时,API 容器工作正常。)

Running Within Container在容器内运行

Doing the same thing within the container, I get the following (fairly long) errors:在容器中做同样的事情,我得到以下(相当长的)错误:

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

Attempts to Solve尝试解决

I thought it was with how the host identified itself within the container group, or whether that origin could be accessed, so I have already tried to change the following, with no success:我认为这是主机如何在容器组中识别自己,或者是否可以访问该来源,所以我已经尝试更改以下内容,但没有成功:

  • Instead of using localhost as the host, I used read-api .我没有使用localhost作为主机,而是使用了read-api
    • Actually, I started with read-api , and had no luck, but once using localhost , I could at least use REPL on the host machine, as shown above.实际上,我是从read-api开始的,但运气不好,但是一旦使用localhost ,我至少可以在主机上使用 REPL,如上所示。
    • I also tried 0.0.0.0 , no luck.我也试过0.0.0.0 ,没有运气。 (I did not expect that to fix it.) (我没想到会解决它。)
  • I have changed what CORS ORIGINS are allowed in the API, including all of the possible paths for the container that is trying to read, and just using "*" to flag all CORS origins.我已经更改了 API 中允许的 CORS ORIGINS ,包括尝试读取的容器的所有可能路径,并且仅使用"*"标记所有 CORS 来源。 No luck.没运气。

What am I doing wrong?我究竟做错了什么? It seems the problem must be with the containers, or maybe how requests interacts with containers, but I cannot figure out what.似乎问题一定出在容器上,或者可能是requests如何与容器交互,但我不知道是什么。

Here are some relevant GitHub issues or SO answers I found, but none solved it:以下是我找到的一些相关 GitHub 问题或 SO 答案,但没有解决:

Within the Docker network, applications must be accessed with the service names defined in the docker-compose.yml .在 Docker 网络中,必须使用docker-compose.yml中定义的服务名称访问应用程序。

If you're trying to access the toy-api service, use如果您尝试访问toy-api服务,请使用

get_from_api(session, path="http://toy-api/test")

You can access the application via http://localhost/test on your host machine because Docker exposes the application to the host machine.您可以在主机上通过http://localhost/test访问应用程序,因为 Docker 将应用程序暴露给主机。 However, loosely speaking, within the Docker network, localhost does not refer to the host's localhost but only to the container's localhost .但是,粗略地说,在 Docker 网络中, localhost不是指主机的localhost ,而只是指容器的localhost And in the case of the read-api service, there is no application listening to http://localhost/test .而在read-api服务的情况下,没有应用程序监听http://localhost/test

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM