内容提要
在项目部署过程中,使用flask内置的开发环境服务器无法满足要求,选择了gunicorn+nginx+supervisor进行部署。启动后发现数据库连接报错,排查后发现是由于.gunicorn没有正确加载.env文件中的信息导致的。通过在setting.py文件中手动加载.env文件解决了问题。
延伸解读
问题根源:加载顺序导致环境变量失效
文章指出,在wsgi.py中调用load_dotenv后,setting.py中仍读取不到环境变量,原因是setting.py在wsgi.py之前执行。这意味着环境变量的加载必须发生在配置模块导入之前,否则后续代码无法获取已加载的值。这一细节提醒开发者,在Flask项目中,配置文件的导入顺序可能影响环境变量的可用性。
解决方案对比:-e参数与手动加载
文章提到两种解决方式:一是通过gunicorn的-e参数逐个传递环境变量,但变量增多时不便;二是在配置文件中手动调用load_dotenv。作者最终选择在setting.py中添加load_dotenv('.env'),因为其项目在虚拟环境中运行,无法使用systemd的EnvironmentFile方案。读者可根据部署环境选择合适方法。
排查思路:从现象到定位
作者从gunicorn启动后返回500错误入手,查看日志发现数据库连接密码非法,进而检查.env文件配置,并通过在setting.py中打印环境变量值,发现均为None,从而定位到gunicorn未加载.env文件。这种通过打印关键变量来验证加载状态的方法,在排查类似环境配置问题时具有参考价值。
Q&A
为什么用gunicorn启动Flask项目后访问会返回500错误?
因为gunicorn没有正确加载.env文件中的环境变量,导致数据库连接时读取不到正确的密码等信息,从而出现权限拒绝错误,最终返回500。
如何解决gunicorn启动Flask时无法读取.env文件的问题?
在配置文件中手动加载.env文件,具体是在setting.py(或wsgi.py)中添加:from dotenv import load_dotenv; load_dotenv('.env')。注意要确保加载代码在读取环境变量之前执行。
gunicorn启动时可以通过什么参数直接设置环境变量?
可以使用-e或--env参数,例如:gunicorn -b 127.0.0.1:5000 -e user=123 -e pwd=123。但环境变量多时这种方法不方便。
为什么在wsgi.py中加载.env文件后,setting.py中仍然读取不到环境变量?
因为setting.py文件执行在wsgi.py文件之前,所以在wsgi.py中手动加载环境变量对setting.py不起作用。需要在setting.py中提前加载.env文件。
除了手动加载.env文件,还有哪些解决gunicorn读取环境变量的方法?
可以修改gunicorn.service配置,指定EnvironmentFile参数;或者使用gunicorn的-e参数直接传递环境变量。但前者在虚拟环境中可能不适用,后者在变量多时不便。
使用gunicorn部署Flask项目时,为什么flask run能正常读取.env而gunicorn不能?
因为flask run命令会自动加载.env文件,而gunicorn不会自动加载,需要手动通过dotenv的load_dotenv函数加载。