AWS Elastic Beanstalk部署Dash-on-Flask应用遇内部服务器错误
说明
Dash是Plotly推出的用于构建仪表盘的Python包,Flask是用于构建Python Web框架的Python包。我使用Python 3.6,所有依赖包版本见下方requirements.txt。
问题现象
本地在127.0.0.1:8050运行时,Dash应用正常工作。但执行$ eb deploy部署到AWS Elastic Beanstalk(EB)后,访问EB URL时显示:
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.
More information about this error may be available in the server error log.
文件结构
~/AWS/servers/flask-s |-- eb-virt | |-- bin | |-- include | |-- lib | `-- pip-selfcheck.json | |-- eb-flask <--- 我在此目录执行eb init | |-- application.py | |-- requirements.txt | |-- .gitignore | |-- .elasticbeanstalk | `-- config.yml
AWS EB配置(执行$ eb config得到)
aws:elasticbeanstalk:container:python: NumProcesses: '1' NumThreads: '15' StaticFiles: /static/=static/ WSGIPath: application.py
application.py代码
import flask import os import dash import dash_core_components as dcc import dash_html_components as html #app = dash.Dash(__name__) #server = app.server server = flask.Flask(__name__) application = dash.Dash(__name__, server=server) application.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"}) application.layout = html.Div([ html.H2('Hello World'), dcc.Dropdown( id='dropdown', options=[{'label': i, 'value': i} for i in ['LA', 'NYC', 'MTL']], value='LA' ), html.Div(id='display-value') ]) @application.callback(dash.dependencies.Output('display-value', 'children'), [dash.dependencies.Input('dropdown', 'value')]) def display_value(value): return 'You have selected "{}"'.format(value) if __name__ == '__main__': application.run_server(debug=True) #app.run_server()
requirements.txt
certifi==2018.4.16 chardet==3.0.4 click==6.7 dash==0.21.1 dash-core-components==0.22.1 dash-html-components==0.10.1 dash-renderer==0.12.1 decorator==4.3.0 Flask==1.0.2 Flask-Compress==1.4.0 gunicorn==19.8.1 idna==2.6 ipython-genutils==0.2.0 itsdangerous==0.24 Jinja2==2.10 jsonschema==2.6.0 jupyter-core==4.4.0 MarkupSafe==1.0 nbformat==4.4.0 numpy==1.14.3 pandas==0.23.0 plotly==2.6.0 python-dateutil==2.7.3 pytz==2018.4 requests==2.18.4 six==1.11.0 traitlets==4.3.2 urllib3==1.22 Werkzeug==0.14.1
尝试过的操作
- 本地执行
(eb-virt) $ python application.py可正常访问,HTTP请求响应正常; - 尝试启用日志时,本地运行出现错误:
application.logger.addHandler(handler) AttributeError: 'Dash' object has no attribute 'logger';部署后日志文件为空,无错误内容。
我帮你排查了下,这个问题大概率出在WSGI应用对象的命名和Dash与Flask的绑定逻辑上。AWS Elastic Beanstalk默认会在application.py里找名为application或者app的WSGI兼容对象,但你当前代码里的application是Dash实例,而EB需要的是Flask的server对象来作为WSGI入口。
第一步:调整application.py的代码
把你的代码改成下面这样,重点是最后把Flask的server对象赋值给application,让EB能识别到正确的WSGI入口:
import flask import os import dash import dash_core_components as dcc import dash_html_components as html # 先创建Flask的server实例 server = flask.Flask(__name__) # 把Dash应用绑定到这个Flask server上 app = dash.Dash(__name__, server=server, url_base_pathname='/') app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"}) app.layout = html.Div([ html.H2('Hello World'), dcc.Dropdown( id='dropdown', options=[{'label': i, 'value': i} for i in ['LA', 'NYC', 'MTL']], value='LA' ), html.Div(id='display-value') ]) @app.callback(dash.dependencies.Output('display-value', 'children'), [dash.dependencies.Input('dropdown', 'value')]) def display_value(value): return 'You have selected "{}"'.format(value) # 关键:把Flask server赋值给application,让EB能找到WSGI入口 application = server if __name__ == '__main__': app.run_server(debug=True)
第二步:确认EB配置没问题
你当前执行eb config得到的WSGIPath: application.py是正确的,这部分不用改。
第三步:重新部署应用
执行eb deploy重新部署,之后访问EB的URL应该就能正常加载你的Dash应用了。
额外的排查技巧
如果还是遇到问题,推荐通过AWS控制台查看EB的日志:
- 登录AWS控制台,进入Elastic Beanstalk服务
- 选中你的应用环境,点击左侧菜单的「日志」
- 选择「请求日志」->「最近的日志」,下载后就能看到详细的报错信息,比如依赖缺失、路径错误这类具体问题
另外,你也可以在本地用gunicorn模拟生产环境运行,提前发现问题:
gunicorn application:application
如果本地用gunicorn能正常跑起来,那部署到EB基本就没问题了。
内容的提问来源于stack exchange,提问作者Jack

