参照《FlaskWeb开发:基于Python的Web应用开发实战》,也就所谓的“狗书”,比利牛斯獒犬。绕了不少弯。
17.3 云部署
整个项目要用本地的git进行版本控制(个别文件除外)
注册heroku账户,不能用qq邮箱,推荐用google的gmail
安装heroku toolbelt(命令行工具,就像前面的manager一样,安装tookbelt以后才能使用各种heroku命令)
书上说toolbelt由两个程序组成 heroku + foreman,但foreman现在已经被官方弃用,用heroku local替代了(https://devcenter.heroku.com/changelog-items/692)
Heroku Local has replaced Foreman in the Heroku Toolbelt
所以实际上toolbelt包含heroku + heroku local.
下载安装完,就可以在根目录用cmd或者git bash使用heroku的命令。
登陆heroku:不能用书上的 $ heroku login ,否则国内上不去,挂代理会显示 IP address mismatch。
$ heroku login -i
输入heroku的账号密码登陆。ssh公钥如果后面出现问题,就按书上的方法重新上传就好了。
创建程序
$ heroku create <appname>
配置数据库 $ heroku addons:add heroku-postgresql:dev ,把后面的:dev去掉,这里是用来设定数据库类型的,默认我们是hobby-dev,兴趣使然的开发者。
$ heroku addons:add heroku-postgresql
书上说的什么棕色不用管他,查看官方说明就知道,颜色类似1234是编号而已,因为可能会有多数据库。颜色没有高低级别的区分。数据库地位提升,意思是把哪个数据库设置为主数据库,仅此而已。没有什么地位啥的。
由于目前只有一个数据库,所以下面的$ heroku pg:promote HEROKU_POSTGRESQL_BROWN_URL 可以不用管。
配置好数据库以后,heroku会把这个数据库的地址放在heroku的环境变量DATABASE_URL里.(heroku的环境变量不在本地,可以用 $ heroku config 查看heroku的当前所有环境变量)DATABASE_URL在config.py里,之前已经有的。
class ProductionConfig(Config): #生产
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'data.sqlite')
#....
配置日志
heroku启动manage.py时,要执行app = create_app(os.getenv('FLASK_CONFIG') or 'default')
要以生产模式来create,所以要设定FLASK_CONFIG。以下就是在heroku手动设置环境变量的方法。
$ heroku config:set FLASK_CONFIG=heroku
书上给的不够全,同时还要改config.py里的
config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
'default': DevelopmentConfig,
'heroku': HerokuConfig #加上这行
}
配置电子邮件,之前我们的邮件账户密码是在venv里用set设的,或者干脆直接放到代码里。但在生产环境里不可以放代码里,
同样设置到heroku的环境变量里。qq邮箱可用,gmail没试过。参照书本。
web服务器
书上提供gunicorn,和uWSGI。不知道书上为什么提供gunicorn,查了一下,不能在windows用,uWSGI没试过。查资料(https://dormousehole.readthedocs.io/en/latest/tutorial/deploy.html)发现了waitress,那就用waitress来做web服务器。(venv) $ pip install gunicorn
(venv) $ pip install waitress
运行不用(venv) $ gunicorn manage:app ,waitress的运行方法是这样的
(venv) $ waitress-serve manage:app
waitress运行使用的端口不是5000而是8080,执行时可能会报错 OSError: [WinError 10013] 以一种访问权限不允许的方式做了一个访问套接字的尝试。(解决方法:https://blog.csdn.net/gsls200808/article/details/52456136)是因为8080口被占用了,找出来,终止掉就好了。命令行里删不掉可以直接开任务管理器删。
添加需求文件。
-r requirements/prod.txt
waitress==1.4.4
psycopg2==2.8.6
注意除了重新创建这个文件,还要把原来的requirements/common.txt更新一下。导出当前venv里所有扩展包的方法,之前书上有讲。对照着修改
(venv) $ pip freeze >起个名.txt
Procfile文件。不用gunicorn当然web: gunicorn manage:app ,内容改为。(https://docs.pylonsproject.org/projects/waitress/en/latest/usage.html 这一页最底下有一堆,先不用那些附加命令)
web: waitress-serve manage:app
(后面正式push的时候还要改,现在先这样)
foreman不能用了,就用heroku local测试,目的就是让你正式push到heroku之前,先在本地像heroku那样运行一下。heroku local和foreman其实很像,同样需要在.env里找环境变量。直接改名可能改不出.env,可以先随便起个名,再cmd里用
rename 你起的名字.env .env
不用foreman所以下面的(venv) $ foreman run python manage.py deploy ,改为
(venv) $ heroku local:run manage.py deploy
执行后可能会报错,说 没有 table user,或者 表的属性 重复之类的。问题可能出在manage.py的deploy()上
解决方法:可以把upgrade()加个#,或者加一行db.create_all()。重复deploy
启动 (venv) $ foreman start
(venv) $ heroku local
因为web服务器是waitress,占用8080,可能再次出现OSError: [WinError 10013]
使用Flask-SSLify启用安全HTTP,要$ pip install Flask-SSLify
处理代理服务器首部,from werkzeug.contrib.fixers import ProxyFix (参考:https://werkzeug.palletsprojects.com/en/1.0.x/middleware/proxy_fix/?highlight=proxyfix#werkzeug.middleware.proxy_fix.ProxyFix)
from werkzeug.middleware.proxy_fix import ProxyFix
正式部署git push heroku master,第一次时间可能长一点,那边要安装各种包。后面小修改再push就快了。
同样要deploy, $ heroku run python manage.py deploy,要在python后面加个3.
$ heroku run python3 manage.py deploy
重启
$ heroku restart
打开,很可能是出错的。
$ heroku open
出错就用 $ heroku logs --tail 查看日志(建议用cmd执行,这里cmd是彩色,git bash反而是全白的)
我遇到的错误:
日志里有一行Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
(查阅了:https://ruby-china.org/topics/11010)
刚才配置Procfile时,那一堆代码里有一句--listen "*:$PORT" \ ,我们改一下Procfile
web: waitress-serve --listen=*:$PORT manage:app
重新git add,git commit,push,restart解决问题。网页可以用访问了
添加了listen以后,再用heroku local是打不开的,显示: socket.gaierror: [Errno 10109] getaddrinfo failed
ValueError: Invalid host/port specified