这段时间准备做网站的应用。没有做过这方面的内容,选型比较困难。最终选了较为简单的Flask框架作为起点。
Flask框架有本OReilly动物系列的《Flask Web开发》俗称 狗书。对于未接触过网站开发的人,想叩开网络开发大门的人呢来说值得一看。涵盖的内容和基础都有了,后续想要再升入就比较容易。
部署环境:
1、Debian 7.5 32位
2、Nginx 1.6.2(系统自带)
3、Python 3.5.1 (Stable)
4、uWSGI 2.0.13.1(Stable/LTS)Server IP:192.168.1.7 (内部测试服务器地址,后面会直接用这个地址测试)
部署目录: /home/abc/blog/
系统自带的是Python2的版本,这里使用的是Py3。不影响部署。
安装Python3版本可以参考《Debian安装 python 3.5.1》
部署的程序是狗书上的Blog实例,使用SQLite作为数据库。
如想使用MySQL作为数据库,参考《python3的flask工程数据库从SQLite迁移到MySQL》
一、安装 Nginx
直接使用系统提供的包比较容易。
$ sudo apt-get install nginx
安装最新版本,可以去官网下载最新稳定版本自己编译。
参照: 编译部署NGINX
二、安装uWSGI
直接使用pip
进行安装比较便捷
pip install uwsgi
提示: 如果安装完成后,敲uwsgi命令找不到,可能是uwsgi不在搜索目录内。找到uwsgi 把命令链接到 /use/bin 下,方便后面使用。
基本测试
创建一个WSGI application程序test.py
。
# test.py
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b"Hello World"] # python3
#return ["Hello World"] # python2
创建这个文件主要是为后面测试uWSGI是否正常工作,方便排障。
运行 uWSGI:
uwsgi --http :8000 --wsgi-file test.py
在本地浏览器中输入 http://192.168.1.7:8000 ,看到hello world
恭喜你,uWSGI正常运作。
三、配置Nginx
uWSGI虽然很高效,可以直接访问。不过Nginx、apache做前端web服务器更专业。这些就交给专业的Nginx,uWSGI就负责内部路由就可以了。
创建一个flaskblog_nginx.conf配置
# flask blog configuration
upstream flaskblog {
# server unix:///tmp/flaskblog.sock;
server 127.0.0.1:3031;
}
server {
listen 80;
# server_name _;
location / {
uwsgi_pass flaskblog;
include /home/abc/blog/uwsgi_params;
}
}
上面配置中有个 uwsgi_params
的文件,是Nginx和uWSGI交互的配置参数。可以直接从Nginx的安装目录找到他,复制到你的工程配置目录中。
找不到可以搜索一下
$ sudo find / -name uwsgi_params
配置文件连接到Nginx的站点启动目录中
$ sudo ln -s /home/abc/blog/faskblog_nginx.conf /etc/nginx/sites-enabled/
注: 站点启动目录是在nginx.conf配置文件的http段配置的。
重启Nignx
$ sudo /etc/init.d/nginx restart
启动uWSGI的test.py
$ uwsgi --socket 127.0.0.1:3031 --wsgi-file test.py
在本地浏览器中访问 http://192.168.1.7 ,看到hello world。恭喜!Nginx+uWSGI正常运作。
如果无法正常访问。如出现502 Bad Gateway
,也不用急排查一下问题。
问题排查:
1、Nginx中的socket端口配置和运行的uWSGI的端口是否一致
2、端口是否被占用
3、Nginx的站点运行目录是否有问题,看看nginx.conf
文件中http段有没有包含。没有包含站点运行目录的在最后加一行。如:include /etc/nginx/sites-enabled/*;
4、uwsgi_params
配置文件确定在配置的目录中存在
四、启动站点
app的启动文件是manage.py
,根据实际情况改为自己的app启动文件。
$ uwsgi --socket 127.0.0.1:3031 --wsgi-file manage.py --callable app
启动Flask和启动示例test.py
多了一个参数 --callable app
是启动Flask的app。
现在就可以使用本地浏览器访问你的网站。
问题:如果无法正常访问,但test.py
能正常访问那就可能app有些问题。
错误:
Internal Server Error
可能是你的环境不对
上述环境错误,可能是你python的运行没有包。如你用的虚拟环境,运行时没设置。
加运行参数 --virtualenv <path>
。这个参数可以告诉uWSGI使用python虚拟环境的目录配置。
uwsgi --socket 127.0.0.1:3031 --wsgi-file manage.py --callable app --virtualenv /home/abc/blog/venv/
再测试一下,看看是否OK!
没OK?创建简单排查工程
创建一个简单的排查问题工程文件testapp.py,里面使用flask框架创建的app。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "<h1>I am app test</h1>"
测试一下,最简单的工程能不能执行。
狗书配置部分
狗书的blog须要配置一些环境变量才能使用。mail章中会用到的邮箱和密码。
提示:测试时可以把环境变量放在当前用户配置文件
~/.bash_profile
中。免得重新启动系统丢失,省去重新输入的麻烦。
export MAIL_USERNAME='fpack@163.com'
export MAIL_PASSWORD='xxxxxxxxxx'
export FLASKY_ADMIN='fpack@163.com'
export FLASK_CONFIG='production'
export DATABASE_URL='sqlite:////var/www/data.sqlite'
把环境设置为生成模式production
。 生成模式的数据库放到/var/www
目录下。确保www-data用户能有权限读写。
配置完成使用部署命令,生成生产环境数据库。(在虚拟环境中运行)
(venv)$ python manage.py deploy
或者可以直接把sqlite数据库文件复制到 /var/www 目录中,给www-data用户权限
$ sudo chown www-data:www-data /var/www/data.sqlite
提示:
www-data --- 这个用户和用户组是用于启动网站的。如果你用其它用户或组,那就给那个用户和组设置权限
五、设置站点自动运行
上面已经实现
client <--> Nginx <--> uWSGI <--> Python(Flask)
把先前的所有参数整理一下,最终放到app执行目录中自动执行。
5.1、创建uWSGI的ini文件
创建一个uwsgi的ini配置文件flaskblog_uwsgi.ini
。把先前用命令执行的参数放进来
[uwsgi]
socket = 127.0.0.1:3031
# socket = /tmp/flaskblog.sock
wsgi-file = manage.py
callable = app
processes = 4
threads = 2
stats = 127.0.0.1:9191
virtualenv = /home/abc/blog/venv/
chdir = /home/abc/blog
# ... may be needed
# 666 --- very permissive
# 664 --- more sensible
# 777 --- ^_^
# chmod-socket = 664
vacuum = true
新加参数说明:
virtualenv --- 工程虚拟环境目录
chdir --- 工程路径
vacuum -- 退出时清理环境
processes&threads --- 多搞几个进程和线程,让App快点?
使用 uWSGI运行一下看看效果
$ uwsgi flaskblog_uwsgi.ini
这样看起来清爽多了。
5.2、创建uwsgi启动目录
提示:如果有就直接把这个配置链接过去。
uWSGI自启动,有个霸气的名字Emperor mode (皇帝模式)。其实和Nignx的站点启动目录sites-enabled
是一样的性质。
既然是皇帝就须要奴隶,建个奴隶围栏,然后把奴隶关进去。
$ sudo mkdir /etc/uwsgi
$ sudo mkdir /etc/uwsgi/vassals
$ sudo ln -s /home/abc/blog/flaskblog_uwsgi.ini /etc/nginx/sites-enabled/
现在有一个奴隶了,不能让他闲着。用鞭子抽他,让他干活。
$ /usr/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data --daemonize /var/log/uwsgi-emperor.log
皇帝要休息,不能整天盯着奴隶干活,叫个监工 www-data
,把报告放在 /var/log/uwsgi-emperor.log
。
现在可以在本地浏览器看一下,奴隶们的活干的漂亮不漂亮了。^_^
5.3、收尾放到启动文件中执行。
最后把刚才的命令加到rc.local
启动配置中,放在exit 0前面一行。
$ sudo vim /etc/rc.local
重新启动liunx,
$ sudo reboot
这样整个服务器生产环境就搭建好,已经可以正式上线。
六、改用高效的socket内部“管道”
在先前的配置中 socket = /tmp/flaskblog.sock
,有这样一句话。这是liunx提供的一种Unix domain sockets
的要比使用端口效率更高。
上面没说是因为可能会遇到权限问题,会比较麻烦所以放在最后。出现问题可以改成原来的socket,不影响网站上线,可以慢慢研究权限。
当uwsgi程序启动时,会自动生成一个flaskblog.sock
文件。flaskblog_nginx.conf
中配置和flaskblog_uwsgi.ini
中保持一致就可以了。
把这个文件放在 /tmp
目录下是保证 www-data
用户启动的uwsgi和nginx都能正常读写。
使用ls -l看flaskblog.sock
文件的权限是www-data
。
$ ls /tmp -l
total 0
srwxrwxrwx 1 www-data www-data 0 Jun 16 15:36 flaskblog.sock
srwxr-xr-x 1 abc abc 0 Jun 16 16:57 testapp.sock
如果Nginx访问testapp.sock
这个就会出问题,因为没有权限出现502 Bad Gateway
。
在Nginx的错误日志/var/log/nginx/error.log
中可以看到没权限的提示信息。
$ sudo cat /var/log/nginx/error.log
...
... connect() to unix:///tmp/testapp.sock failed (13: Permission denied) while connecting to upstream ...
...
这种情况通过加权限参数 --chmod-socket=666
让所有用户都有读写权限。
uwsgi --socket /tmp/testapp.sock --wsgi-file test.py --chmod-socket=666
这样就不会出现502错误,Nginx可以正常访问unix socket。
结束!
祝你能顺利完成网站上线,欢迎多多光临我的小站蘑菇房 moguf.com
代码和配置:
github: https://github.com/cmacro/flaskblog