简体   繁体   English

Python 在 Docker 容器内运行 Gunicorn 时未解析主机(超时)(weasyprint 需要这样做)

[英]Python not resolving host (timed out) when running with Gunicorn inside a Docker container (weasyprint needs to do that)

I have a Django app running in a docker container, which serves the app using Gunicorn.我有一个 Django 应用程序在 docker 容器中运行,它使用 Gunicorn 为应用程序提供服务。 This app uses Weasyprint to generate a PDF, which loads a CSS dynamically.本应用使用Weasyprint生成一个PDF,动态加载一个CSS。 This CSS is served by the app, and it works fine (and loads instantly): host_pointing_to_that_same_machine.com/dynamic_css_path.css这个 CSS 由应用程序提供服务,并且工作正常(并立即加载): host_pointing_to_that_same_machine.com/dynamic_css_path.css

(it's NOT a static file, it's actually a path defined in the django URLs that outputs CSS) (它不是 static 文件,它实际上是在 django 输出 CSS 的 URL 中定义的路径)

That's the weasyprint code:那是 weasyprint 代码:

css = weasyprint.CSS(url=request.build_absolute_uri(reverse('dynamic_css_path')))
        response = HttpResponse(pdf.write_pdf(stylesheets=[css]), content_type='application/pdf')

This creates that URL correctly, and everything works good if instead of gunicorn I use the django built-in server (python manage.py runserver), both in my development machine and at the remote server inside the docker and so.这会正确创建 URL,如果我使用 django 内置服务器 (python manage.py runserver) 而不是 gunicorn,一切正常,无论是在我的开发机器上还是在 docker 内的远程服务器上等等。

But when I serve the app via gunicorn: gunicorn project.wsgi:application --bind 0.0.0.0:8000但是当我通过 gunicorn 提供应用程序时: gunicorn project.wsgi:application --bind 0.0.0.0:8000

Then python is unable to resolve the host name, which I proved by doing:然后 python 无法解析主机名,我通过以下方式证明了这一点:

1) Entering the docker's app console and trying it: 1)进入docker的应用程序控制台并尝试:

docker exec -it container_name /bin/ash
# ping host_pointing_to_that_same_machine.com
# ping any_other_host_pointing_an_external_machine.com

Everything is fine.一切都好。

2) Entering Django's console inside the docker container: 2)在docker容器内进入Django的控制台:

# python manage.py shell
>>> import urllib
>>> r = urllib.request.urlopen(url='http://host_pointing_to_that_same_machine.com', timeout=10)
>>> print('status: '+str(r.status))

Returns 200;返回 200; everything OK.一切还好。

3) Entering python's shell inside the docker container: 3)在docker容器里面输入python的shell:

# python
>>> from urllib import request
>>> r = request.urlopen(url='http://host_pointing_to_that_same_machine.com', timeout=10)
>>> print('status: '+str(r.status))
status: 200

4) Executing these lines of code inside the script, having Gunicorn serving them: 4) 在脚本中执行这些代码行,让 Gunicorn 为它们服务:

# docker logs container_name
Internal Server Error: /admin/app_name/path_to_pdf_generating_script/
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/utils/decorators.py", line 142, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/contrib/admin/sites.py", line 223, in inner
    return view(request, *args, **kwargs)
  File "/srv/apps/project/admin/PdfMakingAdmin.py", line 125, in method_called_by_the_view
    timeout=10)
  File "/usr/local/lib/python3.6/urllib/request.py", line 223, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/local/lib/python3.6/urllib/request.py", line 526, in open
    response = self._open(req, data)
  File "/usr/local/lib/python3.6/urllib/request.py", line 544, in _open
    '_open', req)
  File "/usr/local/lib/python3.6/urllib/request.py", line 504, in _call_chain
    result = func(*args)
  File "/usr/local/lib/python3.6/urllib/request.py", line 1346, in http_open
    return self.do_open(http.client.HTTPConnection, req)
  File "/usr/local/lib/python3.6/urllib/request.py", line 1321, in do_open
    r = h.getresponse()
  File "/usr/local/lib/python3.6/http/client.py", line 1331, in getresponse
    response.begin()
  File "/usr/local/lib/python3.6/http/client.py", line 297, in begin
    version, status, reason = self._read_status()
  File "/usr/local/lib/python3.6/http/client.py", line 258, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "/usr/local/lib/python3.6/socket.py", line 586, in readinto
    return self._sock.recv_into(b)
socket.timeout: timed out

But if I change the code and instead of host_pointing_to_that_same_machine.com tries to load any domain that is not pointing to that machine, like http://example.com or anything:但是如果我更改代码而不是 host_pointing_to_that_same_machine.com 尝试加载任何未指向该机器的域,例如http://example.com或任何东西:

# docker logs container_name
status: 200

I'm going for any of the other thousand ways I have to achieve the results I want, but still, this is bugging me and I wonder if this question and potential anwers are going to be useful for other people facing that, wether they are trying to use Weasyprint or any other script that needs to make http queries.我将采用其他数千种方法中的任何一种来实现我想要的结果,但是,这仍然困扰着我,我想知道这个问题和潜在的答案是否会对面临这个问题的其他人有用,无论他们是尝试使用 Weasyprint 或任何其他需要进行 http 查询的脚本。

I'm leaving here the full traceback that weasyprint throws when trying the original code:我在这里留下了 weasyprint 在尝试原始代码时抛出的完整回溯:

Environment:


Request Method: GET
Request URL: http://host_pointing_to_that_same_machine.com/admin/path-to-app/

Django Version: 2.0
Python Version: 3.6.8

Traceback:

File "/usr/local/lib/python3.6/site-packages/weasyprint/urls.py" in fetch
  284.         result = url_fetcher(url)

File "/usr/local/lib/python3.6/site-packages/weasyprint/urls.py" in default_url_fetcher
  248.                            timeout=timeout, context=ssl_context)

File "/usr/local/lib/python3.6/urllib/request.py" in urlopen
  223.     return opener.open(url, data, timeout)

File "/usr/local/lib/python3.6/urllib/request.py" in open
  526.         response = self._open(req, data)

File "/usr/local/lib/python3.6/urllib/request.py" in _open
  544.                                   '_open', req)

File "/usr/local/lib/python3.6/urllib/request.py" in _call_chain
  504.             result = func(*args)

File "/usr/local/lib/python3.6/urllib/request.py" in http_open
  1346.         return self.do_open(http.client.HTTPConnection, req)

File "/usr/local/lib/python3.6/urllib/request.py" in do_open
  1321.             r = h.getresponse()

File "/usr/local/lib/python3.6/http/client.py" in getresponse
  1331.                 response.begin()

File "/usr/local/lib/python3.6/http/client.py" in begin
  297.             version, status, reason = self._read_status()

File "/usr/local/lib/python3.6/http/client.py" in _read_status
  258.         line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")

File "/usr/local/lib/python3.6/socket.py" in readinto
  586.                 return self._sock.recv_into(b)

During handling of the above exception (timed out), another exception occurred:

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  35.             response = get_response(request)

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  128.                 response = self.process_exception_by_middleware(e, request)

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/usr/local/lib/python3.6/site-packages/django/utils/decorators.py" in _wrapped_view
  142.                     response = view_func(request, *args, **kwargs)

File "/usr/local/lib/python3.6/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  44.         response = view_func(request, *args, **kwargs)

File "/usr/local/lib/python3.6/site-packages/django/contrib/admin/sites.py" in inner
  223.             return view(request, *args, **kwargs)

File "/srv/apps/app_name/admin/PdfAdmin.py" in attendee_list
  134.         css = weasyprint.CSS(url=request.build_absolute_uri(reverse('view_to_dynamic_css')))

File "/usr/local/lib/python3.6/site-packages/weasyprint/__init__.py" in __init__
  322.         with result as (source_type, source, base_url, protocol_encoding):

File "/usr/local/lib/python3.6/contextlib.py" in __enter__
  81.             return next(self.gen)

File "/usr/local/lib/python3.6/site-packages/weasyprint/__init__.py" in _select_source
  407.         with fetch(url_fetcher, url) as result:

File "/usr/local/lib/python3.6/contextlib.py" in __enter__
  81.             return next(self.gen)

File "/usr/local/lib/python3.6/site-packages/weasyprint/urls.py" in fetch
  286.         raise URLFetchingError('%s: %s' % (type(exc).__name__, str(exc)))

Exception Type: URLFetchingError at /admin/app_name/path-to-pdf-generator/
Exception Value: timeout: timed out

在示例中,您正在访问http://host_pointing_to_that_same_machine.com,但在错误日志中,我看到您正在尝试访问http://host_pointing_to_that_same_machine.com/admin/path-to-app/

In case of host pointing to the same machine you needed to resolve the host by making a host entry into your \etc\hosts file.如果主机指向同一台机器,您需要通过在 \etc\hosts 文件中创建主机条目来解析主机。 For docker container you can do that by including below configuration into your composer file:对于 docker 容器,您可以通过将以下配置包含到您的作曲家文件中来做到这一点:

extra_hosts:
  - "host_pointing_to_that_same_machine.com:192.168.X.X"

Replace the ip with your domain pointing ip. Note: If there multiple container u might be needed to include the extra_hosts for others as well.将 ip 替换为您指向 ip 的域。注意:如果有多个容器,您可能还需要为其他容器包含 extra_hosts。

there was a same thing for me, solution was that i've runned django via gunicorn only with one worker, like that:对我来说也有同样的事情,解决方案是我只和一名工人一起通过 gunicorn 运行了 django,就像这样:

  python manage.py migrate && 
gunicorn your_project.wsgi:application --bind 0.0.0.0:8888

the solution is to increase gunigorn workers from 1 to 2 ) with option --workers like that:解决方案是将 gunigorn worker 从 1 增加到 2 ),并使用 --workers 选项:

python manage.py migrate &&
gunicorn your_project.wsgi:application --workers=3 --bind 0.0.0.0:8888

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

相关问题 使用 venv 运行 docker 容器时找不到 gunicorn - gunicorn not found when running a docker container with venv 在Docker容器中运行python脚本时导入错误? - Import error when running python script inside docker container? 如何从在 docker 容器中运行的 python selenium 脚本在主机上打开 chrome? - How do I open chrome on the host from a python selenium script running in a docker container? 在 nginx docker 容器内运行 python 脚本 - Running a python script inside an nginx docker container 使用 vscode 从主机调试 docker 容器中运行的 python 代码 - debug python code running in docker container from host using vscode Docker:运行容器时“无法将主机名“plagdb”转换为地址” - Docker: "could not translate host name "plagdb" to address" when running a container 尝试从主机连接到docker容器内的python套接字 - Trying to connect to a python socket inside a docker container from host Docker 在容器内挂载主机目录时运行失败 - Docker run failing when mounting host dir inside a container 在 Docker 容器错误的时区内运行 python 脚本 - Running python script inside Docker container wrong timezone 在docker容器内运行pudb - Running pudb inside docker container
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM