[英]Python not resolving host (timed out) when running with Gunicorn inside a Docker container (weasyprint needs to do that)
我有一個 Django 應用程序在 docker 容器中運行,它使用 Gunicorn 為應用程序提供服務。 本應用使用Weasyprint生成一個PDF,動態加載一個CSS。 這個 CSS 由應用程序提供服務,並且工作正常(並立即加載): host_pointing_to_that_same_machine.com/dynamic_css_path.css
(它不是 static 文件,它實際上是在 django 輸出 CSS 的 URL 中定義的路徑)
那是 weasyprint 代碼:
css = weasyprint.CSS(url=request.build_absolute_uri(reverse('dynamic_css_path')))
response = HttpResponse(pdf.write_pdf(stylesheets=[css]), content_type='application/pdf')
這會正確創建 URL,如果我使用 django 內置服務器 (python manage.py runserver) 而不是 gunicorn,一切正常,無論是在我的開發機器上還是在 docker 內的遠程服務器上等等。
但是當我通過 gunicorn 提供應用程序時: gunicorn project.wsgi:application --bind 0.0.0.0:8000
然后 python 無法解析主機名,我通過以下方式證明了這一點:
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
一切都好。
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))
返回 200; 一切還好。
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) 在腳本中執行這些代碼行,讓 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
但是如果我更改代碼而不是 host_pointing_to_that_same_machine.com 嘗試加載任何未指向該機器的域,例如http://example.com或任何東西:
# docker logs container_name
status: 200
我將采用其他數千種方法中的任何一種來實現我想要的結果,但是,這仍然困擾着我,我想知道這個問題和潛在的答案是否會對面臨這個問題的其他人有用,無論他們是嘗試使用 Weasyprint 或任何其他需要進行 http 查詢的腳本。
我在這里留下了 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/
如果主機指向同一台機器,您需要通過在 \etc\hosts 文件中創建主機條目來解析主機。 對於 docker 容器,您可以通過將以下配置包含到您的作曲家文件中來做到這一點:
extra_hosts:
- "host_pointing_to_that_same_machine.com:192.168.X.X"
將 ip 替換為您指向 ip 的域。注意:如果有多個容器,您可能還需要為其他容器包含 extra_hosts。
對我來說也有同樣的事情,解決方案是我只和一名工人一起通過 gunicorn 運行了 django,就像這樣:
python manage.py migrate &&
gunicorn your_project.wsgi:application --bind 0.0.0.0:8888
解決方案是將 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.