Loading

Python Web 项目部署

记录下一般的 Python web 项目开发后如何部署到外部服务器上,供用户访问。

1 简要

本质三件事:

  • 租个服务器(含公网 ip)+配置环境
    电脑 + 公网IP
    自己电脑 + 拉专线
    
  • 代码放在服务器
  • 程序运行起来

2 搞一台云服务器

租一个 linux 系统的云服务器,并获得一个公网 IP,例如直接购买云服务厂商提供的云服务器。

如果是购买的云服务器,默认是会有访问限制的,当配置一个新的 web 服务后,我们需要在服务器的管理页面配置相对应的安全组规则,使得服务器能接受指定端口的出入流量,以便外部访问我们的 web 服务(例如网站)。

下面是某云服务器厂商的产品安全组示例:

3 代码同步

将本地开发代码上传到服务器上,这里现在有很多的方式。

  1. 本地将代码传到 git 或者 gitee 上,在服务器上再从 git 或者 gitee 上拉下来代码。

    PS:.gitignore,这个可以直接参考 git 上有人整理好的:https://github.com/github/gitignore/blob

  2. 使用 ftp 工具将文件上传到服务器,例如使用 winscp。

4 服务器前置知识

4.1 python 之 WSGI、uWSGI、uwsgi

参考:

简单来说:

  • WSGI(Web Server Gateway Interface)是一个 Python Web 应用程序与 Web 服务器之间的接口规范,它定义了应用程序和服务器之间的标准接口,使得应用程序可以在不同的 Web 服务器上运行。WSGI 协议使得不同的 Python Web 框架(例如 Flask、Django 等)能够在不同的 Web 服务器上运行,这些服务器可以是 Apache、Nginx 等。
  • uwsgi:uwsgi 是一个与 uWSGI 服务器相关的协议。uwsgi 协议是一种二进制协议,它定义了 uWSGI 服务器与应用程序之间的通信协议。
  • uWSGI:uWSGI 是一个 Web 服务器,它是一个用 C 语言编写的 Web 应用程序容器,支持运行 Python、Ruby、Perl 等多种编程语言。uWSGI 服务器可以作为一个独立的应用服务器,也可以与其他 Web 服务器(如 Nginx、Apache)一起使用,通过 WSGI 协议与 Python 应用程序通信。

总结:

  • WSGI,是一种描述 web 服务器(如 nginx,uWSGI 等服务器)如何与 web 应用程序(如用 Django、Flask 框架写的程序)通信协议。
  • uwsgi 协议是一个 uWSGI 服务器自有的协议,它用于定义传输信息的类型(type of information),每一个 uwsgi packet 前 4byte 为传输信息类型描述,用于与 nginx 等代理服务器通信,它与 WSGI 相比是两样东西。
  • uWSGI 是实现了 uwsgi 和 WSGI 两种协议的 Web 服务器。

请求传递关系:

5 服务器环境配置

1)安装 gcc【可选】

主要是用于编译 python(如果已安装可忽略)

yum install gcc -y

2)安装 python3.9

这里可以通过下面方式手动安装,当然也可以直接安装 anaconda。

  1. 安装 python 依赖

    yum install zlib zlib-devel -y
    yum install bzip2 bzip2-devel -y
    yum install ncurses ncurses-devel -y
    yum install readline readline-devel -y
    yum install openssl openssl-devel -y
    yum install xz lzma xz-devel -y
    yum install sqlite sqlite-devel -y
    yum install gdbm gdbm-devel -y
    yum install tk tk-devel -y
    yum install mysql-devel -y
    yum install python-devel -y
    yum install libffi-devel -y
    
  2. 下载 python 源码

    # 安装 wget
    yum install wget -y
    
    # 下载源码包
    wget https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tgz
    
  3. 解压 & 编译 & 安装

    # 先解压 python 源码
    tar -xvf Python-3.9.5.tgz
    # 进入解压后的目录
    cd Python-3.9.5
    # 编译
    ./configure
    make all
    make install
    
  4. 测试:

    python --version
    # or
    python3 --version
    
  5. python 解释器配置国内镜像源

    pip3.9 config set global.index-url https://pypi.douban.com/simple/
    

3)安装虚拟环境

可以安装 virtualenv,也可以直接安装 miniconda 然后基于 conda 来管理虚拟环境。

安装 miniconda:

wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh

# 校验文件完整性
sha256sum Miniconda3-latest-Linux-x86_64.sh

# 运行安装程序,并按照提示完成安装
bash Miniconda3-latest-Linux-x86_64.sh

# 安装完成后,需要重新打开终端或运行以下命令来更新环境变量
source ~/.bashrc

# 验证 Miniconda 是否正确安装,可以运行以下命令来查看 Miniconda 版本
conda --version

当然也可以去清华镜像源先将指定版本的 miniconda 或者 anaconda 包下下来,然后本地安装。

4)安装 uWSGI

uWSGI 官方文档:https://uwsgi-docs-zh.readthedocs.io/zh-cn/latest/WSGIquickstart.html

使用 uWSGI 运行 web 程序比默认直接运行 app.py 性能好多了。

  1. 首先安装依赖包:

    yum install python3-devel
    
  2. 进入项目虚拟环境,安装 uWSGI

    pip install uwsgi
    

    如果报错:ERROR: Could not build wheels for uwsgi, which is required to install pyproject.toml-based projects,可以直接换用 conda 安装:

    conda install -c conda-forge uwsgi
    

    参考:https://blog.csdn.net/weixin_45800258/article/details/132810710

  3. 配置防火墙开启端口【根据需要,我采用的华为云,只需在安全组配置就行了】

    sudo firewall-cmd --permanent --add-port=8099/tcp
    sudo firewall-cmd --reload
    
  4. 基于 uwsgi 运行 Web 项目(以 Flask 项目为例)

    先进项目目录:cd xxx

  • 方式 1:命令参数

    uwsgi --http :8099 --wsgi-file app.py --callable app
    # --http选项指定监听的IP地址和端口号,--wsgi-file选项指定你的应用程序的入口文件
    

    自然也可以通过选项来调整 uWSGI 的配置,例如:

    • --processes:指定 worker 进程的数量
    • --threads:指定每个 worker 进程的线程数
  • 方式 2:文件参数(推荐)

    参数配置参考:

    首先建议在项目目录下创建一个 uwsgi 文件夹,用来存储 uwsgi 相关文件,示例:

    创建配置文件 uwsgi.ini(这个文件名可自定义),下面是模板

    • 极简模板:

      [uwsgi]
      http = 0.0.0.0:8099
      chdir = /root/coding/pros/python/cv_competence	# flask 项目目录
      wsgi-file = app.py			# flask 项目要运行的项目入口程序
      callable = app
      processes = 2
      # virtualenv = /root/miniconda3/envs/py_web		# 指定虚拟环境(uwsgi 会用该虚拟环境来运行项目)
      buffer-size=32768
      
    • 详细模板(注意 ini 文件的注释)

      [uwsgi]
      
      ; # 启动文件,也即应用入口文件
      wsgi-file = app.py
      ; # 应用名 就是flask文件中的 app(flask 实例)
      callable = app
      ; # 在 app 加载前切换到当前目录,指定运行目录
      chdir = /root/coding/pros/python/cv_competence
      ; # 虚拟环境路径(conda info --envs)
      venv = /root/miniconda3/envs/py_web
      
      ; # 启动路由
      http=0.0.0.0:8099
      
      ; # 并发设置
      ; # 启用 process manager,管理 worker 进程,worker 进程都是这个 master 进程的子进程
      master = True       ; # 使用 max-requests 必须采用这个选项
      workers = 2         ; # 一般为 CPU 核数 * 2 (processess一样效果)
      ; # processes = 2       # 指定开启的工作进程数量(这里是开启2个工作进程)
      max-requests = 5000   ; # 最大请求数
      ; # 设置每个工作进程的线程数
      threads = 2     ; # 线程比进程开销更小一点。如果没有使用 threads 那么 thread 直接不工作的,必须使用 enable_threads。
      listen = 1024   ; # 每个进程排队的请求数量,默认为 100 太小了。并发数 = procsses * threads * listen
      ; # 设置用于 uwsgi 包解析的内部缓存区大小为64k。默认是4k。
      buffer-size = 32768
      thunder-lock = true     ; # 避免惊群效应
      harakiri=30             ; # 所有进程在 30s 没有响应后傻屌
      
      ; # 监控设置
      ; # stats = 127.0.0.1:9191  # 可以使用 uwsgi top 监控
      python-autoreload=1  # 自动重载,开发时非常方便
      
      ; # 指定pid文件的位置,记录主进程的pid号。
      pidfile = /root/coding/pros/python/cv_competence/uwsgi/uwsgi.pid
      ; # 当服务器退出的时候自动删除 unix socket 文件和 pid 文件。
      vacuum = true
      ; # 使进程在后台运行,并将日志打到指定的日志文件或者udp服务器
      daemonize = /root/coding/pros/python/cv_competence/uwsgi/uwsgi.log
      ; # 设置最大日志文件大小
      log-maxsize = 5000000
      
      ; 格式化日志打印
      logformat-strftime=true
      log-date=%%Y-%%m-%%d %%H:%%M:%%S
      log-format=[%(ftime)] pid: %(pid) %(addr) => host: %(host)%(uri)(%(method)) in %(secs)s %(status) total-size: %(size) bytes
      

    执行命令来启动服务:

    # 激活虚拟环境
    conda activate py_web
    
    # 启动服务
    uwsgi --ini uwsgi/uwsgi.ini
    
    # 以后台方式运行,加个 &
    uwsgi --ini uwsgi/uwsgi.ini &
    
    # 重启uwsgi服务
    uwsgi --reload uwsgi/uwsgi.pid
    
    # 停止uwsgi服务
    uwsgi --stop uwsgi/uwsgi.pid
    # 或者通过 ps -ef | grep uwsgi 查看进程及 pid,然后使用 kil -9 [pid] 来杀死进程
    

    注意事项:

    • 此时 run() 函数中添加 host='0.0.0.0',不起作用,由 uwsgi 暴露端口和 ip。

5)CentOS 配置程序开机自启动【可选】

好处是:系统自己重启后,服务会自动启动(类似于 windows 的开机自启)

参考:

方式 1:rc.local 文件中添加自启动命令
  1. 首先编辑 rc.local 文件(没有会新建一个)

    vim /etc/rc.d/rc.local
    
  2. 在文件末尾 exit 之前加上你开机需要执行的命令即可(写绝对路径,添加到系统环境变量的除外)

    # 例如通过 nohup 执行 flask 中的 app.py 文件
    # 可以指定用哪个 env 环境来执行
    nohup /root/miniconda3/envs/face_jiance/bin/python /home/python/face_jiance/app.py > /home/python/face_jiance/nohup.out 2>&1 &
    

    类比到 uwsgi.ini 文件,就是:

    /root/miniconda3/envs/py_web/bin/uwsgi --ini /root/coding/pros/python/cv_competence/uwsgi/uwsgi.ini
    # 注意这里由于是在开机自启时运行,并没有事先激活虚拟环境,所以运行时需指定运行环境,或者写个 sh 脚本也行
    
  3. 为 rc.local 配置可执行权限

    chmod +x /etc/rc.d/rc.local
    
方式 2:创建自启动 systemd 配置

参考:

  1. 编辑 service 文件

    sudo vim /etc/systemd/system/cv_competence_project.service
    

    输入下面内容:

    [Unit]
    Description=uWSGI instance to serve myproject
    After=network.target	// 表示在网络服务启动之后运行服务
    
    [Service]
    User=root		// 执行命令的用户
    WorkingDirectory=/root/coding/pros/python/cv_competence
    Environment="PATH=/root/miniconda3/envs/py_web/bin"
    ExecStart=/root/miniconda3/envs/py_web/bin/uwsgi --ini uwsgi.ini
    
    [Install]
    WantedBy=multi-user.target
    
  2. 启动服务并将其添加到系统自启动项中

    sudo systemctl start cv_competence_project.service
    sudo systemctl enable cv_competence_project.service
    

    执行完该命令后,可以使用systemctl命令来查看该服务的状态:

    sudo systemctl status cv_competence_project.service
    

    也可以在任何时候使用以下命令停止服务并从自启动项中删除:

    sudo systemctl stop cv_competence_project.service
    sudo systemctl disable cv_competence_project.service
    

6)安装 nginx(用于接收所有的浏览器请求并对不同的请求进行转发/分发)【可选】

插眼:https://www.bilibili.com/video/BV18M41127Mf/?p=14&spm_id_from=pageDriver&vd_source=bda72e785d42f592b8a2dc6c2aad2409

7)制作两个脚本方便重启、停止服务【可选】

见:https://www.bilibili.com/video/BV18M41127Mf?t=325.7&p=15



参考:

posted @ 2024-02-02 15:14  sinatJ  阅读(155)  评论(0编辑  收藏  举报