编辑
2024-07-07
🧰语言-python
00
请注意,本文编写于 347 天前,最后修改于 225 天前,其中某些信息可能已经过时。

目录

部署上线
传统部署VS云部署VS静态部署
1. 基本部署流程
1.1 更新程序步骤
2. 部署前的准备
2.1 更新程序配置
3. 创建生产环境专用的程序
3.1 设置迁移工具
3.2 程序日志
日志不需要传入到Git仓库中的方法?
4. 部署到Linux服务器
4.1 登录远程主机,安装基本库和工具
4.2 安全防护措施
4.3 推送代码并初始化程序环境
4.4 使用gunicorn运行程序
4.5 使用nginx提供反向代理
4.6 使用Supervisor管理进程
5. 更新部署后的程序
6. 在PythonAnywhere和HeroKu部署

部署上线

什么是部署? 部署指的是把程序托管到拥有公网ip的远程服务器(计算机)上,这样程序可才可以被互联网上的所有人通过IP或映射到IP的域名访问到

传统部署VS云部署VS静态部署

  • 传统部署
    1. 类似于毛胚房,需要自己动手设置所有环境
    2. 通常会通过虚拟主机服务提供商来租用虚拟主机,这些服务被成为IaaS(设施即服务)。主流的有Amazon Ec2、阿里云云的ECS
    3. 传统部署比较灵活,一切都由你自己来掌控,不过同时需要耗费较多的经历去进行环境搭设和维护,需要运维人员来维护。
    4. 如果不想把时间都花费到运维上,只想尽快让你的程序部署上线,可以考虑使用云部署
  • 云部署
    1. 精装修的公寓,程序只需要接通电源就可以运行
    2. 云部署即Pass(平台即服务)。简单来说,云部署服务提供了一个完善的平台,提供了所有底层基础设施,我们只需要推送程序代码即可。
    3. 使用云部署,可以省去配置服务器、设置数据库、配置网络服务器以及设置防火墙等步骤。使用简单的方式即可集成第三方工具、添加数据库、设置邮件服务等,使用起来非常灵活
    4. 例如paas的有HeroKu PythonAnywhere,Webfaction,Goolge App Engine等。普通人推荐HeroKu
  • 静态部署
    1. 静态部署是先借助工具将程序静态化处理,比如使用扩展Frozen-Flask,静态处理就是把程序中的所有动态页面全部转换成对应的HTML文件,分目录放置。
    2. 静态处理后的程序部署成本非常低,而且有大量免费的静态部署服务,比如Github Pages\Netlify等
    3. 一般适用于不需要接受用户输入、不产生动态输出的程序,比如个人博客

1. 基本部署流程

如果你将程序代码托管在在线代码托管平台比如Github\BitBucket\Gitlab等,那么使用Git部署程序的过程非常简单,和在你自己的电脑上运行程序的基本相同,大致流程如下:

* 在本地执行测试 * 将文件添加到Git仓库并提交(git add & git commit) * 在本地将代码推送到代码托管平台(git push) * 在远程主机上从代码通过平台复制程序仓库 git clone * 创建虚拟环境并安装依赖 * 创建实例文件夹,添加部署特定的配置文件或是创建.env文件存储环境变量并导入。 * 初始化程序和数据库,创建迁移环境 * 使用Web服务器运行程序

## 1.1 更新程序步骤

* 在本地执行测试 * 将文件添加到Git仓库并提交 git add & git commit * 在本地将代码推送到代码托管平台 git push * 在远程文件上从代码托管平台拉去程序仓库 git pull * 如果有依赖变动,或是数据库表结构变动,那么执行依赖安装和数据库迁移操作 * 重启Web服务器

2. 部署前的准备

## 2.1 更新程序配置

  • .env文件。不同的环境需要不同的配置,将某些包含敏感信息的配置变量优先从环境变量获取,比如数据库URL、Email服务器配置信息等。将这些关键信息填写到.env文件中。记得将文件放到.gitignore中
  • SECRET_KEY 。我们需要要为保存程序密钥的SECRET_KEY配置变量生成一个随机字符,更换开发时填入的占位字符。
    python
    # 随机密钥的生成方式有很多。比如,os模块的urandom()方法可以用来生成随机密码 import os os.urandom((12)) # 如果使用python3.6,可以使用secrets模块提供的token_bytes()、token_hex()、token_urlsafe()方法 import secrets token_urlsafe(16) # 或者使用uuid
  • 如果需要执行flask相关的命令,需要配置.flaskenv的文件

在PythonAnywhere部署程序时,因为PythonAnywhere使用的数据库服务会在5分钟断开连接,需要将flask_sqlalchemy提供SQLALCHEMY_POOL_RECYCLE配置变量的值设为300一下,用来设置数据库连接池的回收时间,比如:

shell
SQLALCHEMY_POOL_RECYCLE=280

3. 创建生产环境专用的程序

## 3.1 设置迁移工具 详情查看5数据库

## 3.2 程序日志

  1. 将日志写入到文件中
python
import logging from logging.handlers import RotatingFileHandler def create_app(config_name=None): register_logger(app) def register_logger(): app.logger.setLevel(loggging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_handler = RotatingFileHandler('logs/bluelog.log',maxBytes=10*1024*1024,backupCount=10) file_handler.setFormatter(formatter) file_handler.setLevel(logging.INFO) if not app.debug: app.logger.addHandler()

代码解释:

  • 为了让日志记录器记录INFO等级的日志时间,我们首先将app.logger的等级设为INFO。
  • 然后创建一个logging.Formatter对象设置日志的输出格式。
  • 为避免日积月累产生一个巨大的日志文件,我们使用RotatingFileHandler类(从logging.handlers模块导入)创建一个轮转文件类型的日志处理器,实例化这个类传入日志文件目标路径、最大文件尺寸和备份数量。
  • 当日志文件的大小超过实例化传入的maxBytes参数设定的值时(单位为字节byte,我们这里设为10MB),它会循环覆盖之前的记录
  • 将backupCount参数设为10次,会依次创建10个日志文件,10个文件全部存满10MB后会开始覆盖之前的文件;
  • TimeRotatingFileHandler类,它会根据设定的时间间隔(通过实例化传入参数设定)来定期覆盖日志数据

日志不需要传入到Git仓库中的方法?

  • 在项目根目录下创建一个logs文件夹
  • 在logs目录下文件一个.gitkeep文件,并在.gitignore中写入一个*.log规则,这会确保将logs目录添加到Git仓库,但是忽略所有以.log结尾的日志文件
  1. 云部署平台的日志 云部署平台会从stdout(标准输出)和stderr(标准错误输出)收集日志,如果要吧程序部署到云平台上,需要创建一个StreamHanler类型的日志处理器来替代上面的RotatingFileHandler处理器

  2. 通过邮件发送关键日志 在生产环境重,低等级的信息可以记录到日志文件重,而关键的信息(比如Error等级以上)则需要通过邮件发送给管理员,以便及时休闲服问题

为了在日志信息重插入出发这个日志事件的请求信息,我们创建一个自定义的RequestFormatter类,它继承自logging.Formatter类,添加了几个自定义字段来插入请求信息。

python
import requests import logging def register_logger(): class RequestFormatter(logging.Formatter): def format(self, record): record.url = requests.url record.remote_addr = request.remote_addr return super(RequestFormatter,self).format(record) request_formatter = RequestFormatter( '[%(asctime)s] %(remote_addr)s requested %(url)s \n %(levelname)s in %(module)s: %(message)s' )

使用SMTPHandler类可以创建一个SMTP处理器,传入的参数太多从相应的Flask-Mail配置变量获取。我们将这个邮件日志处理器的等级设为logging.ERROR,当发生Error等级及以上的日志事件时会将日志通过邮件发送给管理员

python
import os import logging from logging.handlers import SMTPHandler def register_logger(): mail_handler = SMTPHandler( mailhost=os.getenv('MAIL_SERVER'), fromaddr=os.getenv('MAIL_USERNAME'), toaddrs=os.getenv('BLUELOG_ADMIN_EMAIL'), subject='Application Error', credentials=(os.getenv('MAIL_USERNAME'),os.getenv('MAIL_PASSWORD')) ) mail_handler.setLevel(logging.ERROR) mail_handler.setFormatter(request_formatter) if not app.debug: app.logger.addHandler(mail_handler)

除了传统的日志记录,我们还可以使用第三方错误追踪工具来处理程序中的错误。流行的选择是Sentry,当在程序中集成Sentry后,它可以在程序出现异常时通过我们设置的各种方式发送提醒(除了邮件,还可以集成Slack、Whatsapp、IRC等第三方工具)

更重要的是,我们可以在的控制面板中查看关于这个异常的相关代码、上下文变量的值、函数调用堆栈、以及异常触发的次数、涉及的客户端信息等一系列数据,这能够帮助我们及时找出问题的根源并解决问题。

Sentry更多学习连接

Sentry掘金博客连接

4. 部署到Linux服务器

准备:

  • 远程主机
  • 购买一个域名
  • 域名解析

4.1 登录远程主机,安装基本库和工具

4.2 安全防护措施

4.3 推送代码并初始化程序环境

4.4 使用gunicorn运行程序

4.5 使用nginx提供反向代理

4.6 使用Supervisor管理进程

我们直接通过命令来运行gunicorn,这并不十分可靠。我们需要一个工具来自动在后台运行它,同时监控它的运行状况,并在系统出错或是重启时自动重启程序。 在/etc/supervisor.d/创建wiki.ini 视个人情况,创建配置文件

shell
[program:eric_web] command=pipenv run gunicorn -w 2 -b 127.0.0.1:5001 wsgi:app --preload # 需要执行的命令 directory=/root/program/EricWeb #命令执行的目录 environment =PYTHONPATH="$PYTHONPATH:/root/.local/share/virtualenvs/EricWeb-qMyTWs2e/bin" #环境变量 user=root #用户 stopsignal=INT autostart=true #是否自启动 autorestart=true #是否自动重启 startsecs=60 #自动重启时间间隔(s) stderr_logfile=/var/log/eric_web/webs.err.log #错误日志文件 stdout_logfile=/var/log/eric_web/webs.out.log #输出日志文件

重启

shell
supervisorctl reload

除了命令行工具supervisorctl,Supervisor还提供了Web客户端,你可以通过在/etc/supervisor/supervisord.conf中写入下面的配置来开启:

shell
[inet_http_server] ; inet (TCP) server disabled by default port=*:9001 ; (ip_address:port specifier, *:port for all iface) username=yourname ; (default is no username (open server)) password=yourpassword

; 后边的语法代表注释

5. 更新部署后的程序

不过,尽量避免这种方式,先在测试环境测试ok了之后,再提交到生产环境中

  1. 在本地更新代码
  2. 通过生成虚拟数据再浏览器中手动调试
  3. 调试满意后执行一系列测试
  4. 测试通过后将代码推送到代码托管平台,触发持续集成服务器进行测试
  5. 登录远程主机,使用git pull命令拉取更新
  6. 执行必要的操作,比如更新数据库结构,安装新的依赖等。
  7. 重新启动gunicorn

6. 在PythonAnywhere和HeroKu部署

都是国外的,而且基于Amazon来实现的,有一定的延迟,不适合国内生产。

本文作者:Eric

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!