经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Nginx » 查看文章
Flask结合gunicorn和nginx反向代理的生产环境部署及踩坑记录
来源:cnblogs  作者:xzajyjs  时间:2023/7/14 10:22:10  对本文有异议

前言

之前自己写的flask使用gunicorn上线生产环境没有什么问题,但是最近搭建了一个现成的flask项目,当使用python直接运行时不会有问题,而使用gunicorn时则会出现一些问题。


部署过程

运行测试

这里使用pyenv创建了一个虚拟环境,并安装好依赖

  1. pyenv virtualenv 3.9.6 freegpt
  2. pyenv activate freegpt
  3. pip install -r requirements.txt

下面是入口函数run.py

  1. from server.app import app
  2. from server.website import Website
  3. from server.backend import Backend_Api
  4. from json import load
  5. if __name__ == '__main__':
  6. # Load configuration from config.json
  7. config = load(open('config.json', 'r'))
  8. site_config = config['site_config']
  9. # Set up the website routes
  10. site = Website(app)
  11. for route in site.routes:
  12. app.add_url_rule(
  13. route,
  14. view_func=site.routes[route]['function'],
  15. methods=site.routes[route]['methods'],
  16. )
  17. # Set up the backend API routes
  18. backend_api = Backend_Api(app, config)
  19. for route in backend_api.routes:
  20. app.add_url_rule(
  21. route,
  22. view_func=backend_api.routes[route]['function'],
  23. methods=backend_api.routes[route]['methods'],
  24. )
  25. # Run the Flask server
  26. print(f"Running on port {site_config['port']}")
  27. app.run(**site_config)
  28. print(f"Closing port {site_config['port']}")

其中site_config.json文件如下:

  1. {
  2. "site_config": {
  3. "host": "127.0.0.1",
  4. "port": 1234,
  5. "debug": false
  6. },
  7. "use_auto_proxy": false
  8. }

意思是,运行flask服务于127.0.0.1:1234,只运行本地访问,后期我们需要搭建Nginx进行反向代理。

我们先使用python直接运行测试一下看能否跑起来以及能否正常访问。

  1. python run.py

image-20230714004534660

我们在服务器使用curl进行请求

  1. curl 127.0.0.1:1234

image-20230714004621346

数据返回正常,说明可以正常访问。


gunicorn搭建

Gunicorn是一个WSGI HTTP Server,是针对Python的、在Unix系统上运行的、用来解析HTTP请求的网关服务。
它的特点是:能和大多数的Python web框架兼容;使用简单;轻量级的资源消耗;高性能。

首先在当前虚拟环境下安装gunicorn

  1. pip install gunicorn

然后我们使用gunicorn将flask项目跑起来,并且仅对本机开放,端口4444

  1. gunicorn run:app -b 127.0.0.1:4444 --access-logfile access.log --error-logfile error.log &

使用ps命令可以看到当前已经成功在后台运行起来了

  1. ps aux | grep gunicorn

image-20230714005029807

踩坑

但是此时当我们再次使用curl访问127.0.0.1:4444时:

image-20230714005121785

出现了404的错误。

我们查看gunicorn生成的日志文件:

  1. # access.log
  2. 127.0.0.1 - - [13/Jul/2023:12:51:11 -0400] "GET / HTTP/1.1" 404 207 "-" "curl/7.76.1"

可以看到成功的请求到了我们的wsgi server,但是返回了404。在外网论坛上摸索了一番,问题出在了run.py上。

run.py文件中的所有代码都是写在if __name__ == "__main__":之下的,这在python语法中代表着主函数入口。

  • 当使用Python直接运行脚本时(例如:python run.py),if __name__ == '__main__'条件下的代码块会被执行,包括app.run()。这将启动Flask服务器,并让应用程序开始监听指定的主机和端口。
  • 当使用Gunicorn运行应用程序时(例如:gunicorn --bind 127.0.0.1:4444 run:app),if __name__ == '__main__'条件下的代码块不会被执行。因为Gunicorn实际上是将你的代码作为一个模块导入,而不是直接运行该代码。在这种情况下,Gunicorn会在内部处理Flask服务器的启动逻辑,并监听指定的主机和端口。也就因此自己在app.run(**kwargs)中设定的hostportdebug等参数也就失效了。

因此,无论是使用Python直接运行还是使用Gunicorn运行应用程序,app.run()只会在Python直接运行脚本时执行。而在使用Gunicorn运行时,if __name__ == '__main__'条件下的代码块将被跳过,包括app.run()。这是因为Gunicorn已经处理了服务器的启动逻辑。

因此,if __name__ == '__main__'条件的目的是为了确保在直接运行脚本时才执行特定的代码块,而在被导入为模块时跳过这些代码块。这样可以确保在使用Gunicorn启动应用程序时不会重复启动Flask服务器,并避免出现意外行为。


解决方案

既然已经知道了错误的逻辑,那么解决方法就很简单了,只要把除了app.run()的其他代码全部移出if __name__ == "__main__"即可。修改后的run.py如下:

  1. from server.app import app
  2. from server.website import Website
  3. from server.backend import Backend_Api
  4. from json import load
  5. # Load configuration from config.json
  6. config = load(open('config.json', 'r'))
  7. site_config = config['site_config']
  8. # Set up the website routes
  9. site = Website(app)
  10. for route in site.routes:
  11. app.add_url_rule(
  12. route,
  13. view_func=site.routes[route]['function'],
  14. methods=site.routes[route]['methods'],
  15. )
  16. # Set up the backend API routes
  17. backend_api = Backend_Api(app, config)
  18. for route in backend_api.routes:
  19. app.add_url_rule(
  20. route,
  21. view_func=backend_api.routes[route]['function'],
  22. methods=backend_api.routes[route]['methods'],
  23. )
  24. if __name__ == '__main__':
  25. # Run the Flask server
  26. print(f"Running on port {site_config['port']}")
  27. app.run(**site_config)
  28. print(f"Closing port {site_config['port']}")

这样就可以保证python和gunicorn方式均可正常运行。

先kill掉之前正在运行的gunicorn,并重新启动

  1. kill -9 1275864 1275865
  2. gunicorn run:app -b 127.0.0.1:4444 --access-logfile access.log --error-logfile error.log &

可以看到现在请求127.0.0.1:4444已经正确响应了

image-20230714010629837


Nginx反向代理

目前搭建的服务只能服务器自己访问到,下面我们通过nginx反向代理将其映射到对外的80端口

安装配置nginx就不多说了,下面讲讲配置文件的写法。其实很简单

  1. vim /etc/nginx/nginx.conf
  1. # nginx.conf
  2. ...
  3. server {
  4. listen 80;
  5. server_name xxxxxxxx; # 此处填绑定的域名
  6. location / {
  7. proxy_pass http://localhost:4444;
  8. proxy_set_header Host $host:$server_port;
  9. proxy_set_header X-Real-IP $remote_addr;
  10. }
  11. }
  12. ...

然后运行nginx即可

  1. nginx -t
  2. nginx

此时使用本机访问域名的80端口已可以正常访问了。

image-20230714011222108

原文链接:https://www.cnblogs.com/xzajyjs/p/17552599.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号