1. 前言
《Django开发简单Blog系统》系列中,我们已经完成了一个迷你Web项目。那么,怎么把这个项目发布到线上呢?怎样给它一个域名呢?
思路:nginx + uwsgi
2. 环境准备
2.1. 服务器
阿里云服务器,centos7系统。
2.2. python
升级python到3.6.1,统一线上和本地python环境。
1、下载python3.6.1源码wget https://www.python.org/ftp/python/3.6.1/Python-3.6.1.tar.xz
2、解压源码
1 | xz -d Python-3.6.1.tar.xz |
3、编译源码
1 | mkdir /usr/local/python3 |
如果编译失败,需要先更新编译环境:
1 | gcc -v |
注:我的环境版本为 gcc version 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC) 。
4、替换python
1 | cd /usr/bin |
5、解决遗留问题
所有python相关的应用,如果使用/usr/bin/python开头的脚本,替换为/usr/bin/python2.7。比如:
1 | vim /usr/bin/yum |
2.3. uwsgi
pip install uwsgi
编写测试:
1 | # test.py |
启动测试:uwsgi --http :8001 --wsgi-file test.py
报错:uwsgi: command not found,看来我们需要把python3/bin加入到path。vim /etc/profile
,在文件最底部找到PATH,添加:
1 | :/usr/local/python3/bin |
使配置生效:source /etc/profile
访问 http://ip:8001 ,即可看到Hello World 。
2.4. nginx和mysql
参考《在CentOS7上配置PHP运行环境》,安装好了nginx和mysql。
3. 项目部署
3.1. 代码准备
1、克隆项目到服务器git clone https://github.com/voidking/djsite.git
2、安装djangopip install django
3、安装pymysqlpip install pymysql
3.2. 数据库准备
1、创建数据库
1 | # mysql -uroot -p |
2、修改djsite/djsite/settings.py中的数据库配置vim djsite/djsite/settings.py
3、创建表结构
1 | python manage.py makemigrations |
报错:
1 | django.db.utils.InternalError: (1665, 'Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.') |
修改mysql的binlog格式为混合模式:
1 | # mysql -uroot -p |
删除数据库djsite中的所有表,然后再次执行:
1 | python manage.py migrate |
4. 启动项目
4.1. 数据库问题
1 | cd djsite |
报错:
1 | File "/usr/local/python3/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 36, in <module> |
解决办法:
1 | vim /usr/local/python3/lib/python3.6/site-packages/django/db/backends/mysql/base.py |
进入vim命令模式,输入/version
,按N查找下一个,找到:
1 | if version < (1, 3, 3): |
注释掉它,问题解决。
4.2. url问题
1 | cd djsite |
再次报错:
1 | File "/root/djsite/djsite/urls.py", line 21, in <module> |
解决办法:
1 | vim /usr/local/python3/lib/python3.6/site-packages/django/urls/conf.py |
找到:
1 | if namespace and not app_name: |
注释掉它,问题解决。
4.3. 查看效果
1 | cd djsite |
启动成功,在服务器上测试访问:curl localhost:8000/blog/index
使用浏览器查看 http://ip:8000/blog/index ,却无法访问。这是因为在settings.py中,ALLOWED_HOSTS的配置为:
1 | ALLOWED_HOSTS = [] |
官方文档说:
When DEBUG is True and ALLOWED_HOSTS is empty, the host is validated against [‘localhost’, ‘127.0.0.1’, ‘[::1]’].
修改ALLOWED_HOSTS的配置为:
1 | ALLOWED_HOSTS = ['*'] |
然后启动命令改为:python manage.py runserver 0.0.0.0:8000
,此时即可在浏览器看到部署好的项目。
如果还是不能访问,尝试先关闭防火墙:systemctl stop firewalld
5. nginx配置
1、首先,在万网上配置域名解析,添加A记录,解析到阿里云服务器IP。假设解析好的域名为django.voidking.com。
2、在nginx的vhost中,添加django.voidking.com.conf,内容为:
1 | server { |
3、重启nginx,./nginx -s reload
4、测试访问
服务器:curl django.voidking.com/blog/index
本地浏览器:http://django.voidking.com/blog/index
至此,django项目已经部署成功,没有用到uwsgi。如果给django添加守护进程,那么我们的部署就接近完美了。那么,uwsgi又能干什么呢,我们继续研究。
6. uwsgi
6.1. 一般启动
1、编写wsgi.py文件
编写django_wsgi.py文件,将其放在与文件manage.py同一个目录下。
1 |
|
2、启动项目uwsgi --http :8000 --chdir ~/djsite/ --module django_wsgi
3、查看启动结果lsof -i :8000
,ps aux | grep uwsgi
4、测试访问
http://ip:8000/blog/index
此时,页面是没有样式的,也就是说静态资源加载失败。
5、配置静态资源uwsgi --http :8000 --chdir ~/djsite/ --module django_wsgi --static-map=/static=static
此时,页面样式就正常了。
6.2. 高级启动
1、新建uwsgi.ini,与manage.py在同一级目录。
1 | [uwsgi] |
2、启动uwsgiuwsgi uwsgi.ini
3、测试访问
http://ip:8000/blog/index
7. 守护进程
7.1. 安装supervisor
关闭shell后,uwsgi服务就很快关闭了。为了让它后台运行,需要让它变成守护进程。
参考《CentOS安装配置Supervisor》,安装配置好supervisor。
7.2. 守护uwsgi
1、在/etc/supervisor中新建djsite.conf文件:
1 | [program:djsite] |
2、重启supervisor
1 | systemctl stop supervisord |
附:重启djsite命令
1 | supervisorctl -c /etc/supervisord.conf restart djsite |
3、测试访问
http://ip:8000/blog/index
页面显示正常,至此守护进程配置成功。
4、退出supervisor环境source deactivate
,守护进程并没有受到影响。
8. nginx+uwsgi
以上,我们的djsite项目已经通过uwsgi方式启动起来,并且可以保持后台运行。nginx配置不改变的情况下,我们可以正常访问 http://django.voidking.com/blog/index 。此时,nginx作为反向代理,和uwsgi间通过http交互。
接下来,就配置下nginx和uwsgi通过socket结合的方式。原理:用户发送http请求到nginx,nginx通过socket把请求交给uwsgi,uwsgi拿到django的处理结果,通过socket返还给nginx,nginx通过http返回结果给用户。
1、因为nginx和uwsgi通过socket方式交互,我们需要修改uwsgi.ini的配置为:
1 | [uwsgi] |
2、/etc/supervisor/djsite.conf
,修改为
1 | [program:djsite]command=/usr/local/python3/bin/uwsgi uwsgi.ini |
3、重启supervisorsystemctl stop supervisord
systemctl start supervisord
4、修改nginx配置djsite.voidking.com.conf:
1 | server { |
5、重启nginx./nginx -s reload
6、测试访问
此时,访问 http://ip:8000/blog/index 失败,访问 http://django.voidking.com/blog/index 正常。因为8000端口不再提供http服务,而是一个和nginx连接的socket。
7、static
请问,此时的静态资源,是通过uwsgi获取的?还是通过nginx直接获取的?做一个测试即可,修改uwsgi为:
1 | [uwsgi] |
此时,uwsgi不再提供静态资源。重启supervisor,页面样式正常,可见,静态资源是通过nginx获取的。之所以可以获取到,是因为我们之前在djsite/settings.py中配置了:
1 | STATICFILES_DIRS = ( |
9. 小结
至此,django部署完毕,我们实现了三种部署方法:
- nginx + django(http方式)
- nginx + uwsgi(http方式)
- nginx + uwsgi(socket方式)
在此过程中,解决了一些奇怪的bug,学习了升级python的方法,学习了使用pyenv安装多版本python的方法(类似的还有anaconda),学习了给django或者uwsgi添加守护进程的方法,收获颇丰。