近期用python的Django写了一个小程序,想部署到服务器上面。网上搜了一下,发现所有使用nginx的解决方案基本上都是来源于这篇文章。所以就把这篇文章翻译了一下,加深自己的理解。
这篇教程适用于想在生产服务器上搭建应用的Django使用者。只需要几部就可以让你用nginx和uWSGI搭建一个Django应用。它涵盖所有三个组件,提供一个完整的Web应用程序和服务器软件搭建方案。(It covers all three components, providing a complete stack of web application and server software.)
DJango是一个高质量的Web开发框架,鼓励快速、简介、务实的设计(pragmatic design)
nginx是一款免费、开源、高并发访问的HTTP服务器和反向代理以及IMAP/POP3 代理服务器
这篇教程的一些笔记
这只是一篇入门教程,它的目的不是提供一个全面的参考指南,不会为开发者提供一个详细的开发指南
nginx和uWSGI是DJango开发者的好选择,但不是唯一的或者说“官方”的选择。每一种方案都有优点,值得你去尝试。
这种方法也许是一种好的方法,但不是唯一的方法,从某些方面来说他甚至不是最好的方法
然而,这是一个可靠和简单的方法,这里涵盖的材料将向您介绍概念和程序,您将需要熟悉用于部署Django的任何软件。
在熟悉了这些配置和这些步骤之后,如果你能够探索其他的方法也能达到相同的目的
这篇教程假定你的系统已经完成了一些配置
假定你使用的是进行可以进行包管理的Unix系列的系统。然而如果你有类似“Mac OS系统该怎样配置”这样的问题,你会很容易找到这类问题的答案。
这篇教程使用的是Django1.4或者更新版本,它能够在你新建的项目中创建一个wsgi模块。如果你使用的是更早期的版本的话,你需要自己去创建一个wsgi模块
概念
一个Web服务面向世界。它能够直接从系统提供一些文件(比如说HTML、图像、CSS等等)。然而,他不能直接从Django中获取,这需要一些东西来运行这些应用,比如来自客户端的请求和响应。
一个Web服务网关接口==WSGI,就是干这件事情的。WSGI是一个python的标准。
uWSGI是WSGI的一个实现工具,在这篇教程中我们将设置uWSGI从而创建一个Unix socket服务。服务响应通过WSGi协议来对传给web应用。最后,我们完成的主要原理图如下:
the web client <-> the web server <-> the socket <-> uwsgi <-> Django->->->->
在开始设置uWSGI之前需要做的准备
virtualenv
确保你在虚拟环境下安装软件(稍后我们将介绍在原生系统中安装uWSGI)
1 | virtualenv uwsgi-tutorial |
Django
在虚拟环境下安装Django,创建一个项目,并且通过cd来进入这个项目
1 | pip install Django |
关于域名和端口
教程中默认你的域名为:example.com 你可以替换成你的域名或者Ip地址
跟Django默认使用的端口一样,在这里我们将始终使用8000端口作为服务的对外端口。当然你也可以使用其他的你想用的端口,但是我使用这个端口并没有和之前的配置发生任何冲突。
基本uWSGI安装和配置
在你的虚拟环境中安装uWSGI
pip install uwsgi
当然还有其他的方式安装,不过这种方法是最好的一种。注意你必须要安装好相关的依赖包。例如在Debain或者像Ubuntu这样与Debain类似的系统中,你就需要安装pythonX.Y-dev(X.Y是你的python版本号)
基础测试
创建一个叫test.py的文件:1
2
3
4
5# test.py
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b"Hello World"] # python3
#return ["Hello World"] # python2
笔记
注意python3需要使用bytes()
运行uWSGI:
uwsgi –http :8000 –wsgi-file test.py
选项的意思:
http :8000 使用http的8000端口
wsgi-file test.py 加载指定文件
当你使用浏览器访问8000端口的时候应该会看到“Hello,World”的字样
检查如果是这样的话,说明一下这些部分没有问题了;
the web client <-> uWSGI <-> Python->->
测试你的Django应用
现在uWSGI做着同样的事情,只不过运行的是Django应用而不是test.py模块
如果你还没有做到这里,确保你的mysite项目能够工作:
python manage.py runserver 0.0.0.0:8000
如果他能够正常工作,就用uWSGI运行它:
uwsgi –http :8000 –module mysite.wsgi
- module mysite.wsgi 加载指定的uWSGI模块
在你的浏览器中查看,如果服务能够正常运行,就意味着uWSGI能够从虚拟环境中运行Django应用,现在就到了这一步:
the web client <-> uWSGI <-> Django->->
我们一般不让客户端直接和uWSGI联系。这是Web服务器的工作,在其中扮演者中间人的角色。
Nginx基本配置
安装nginx
1 | sudo apt-get install nginx |
现在通过浏览器访问网站的80端口,你应该会看到nginx的一条信息:Welcome to nginx!。这就说明一下环节是打通的:
the web client <-> the web server->
如果其他应用已经占据了80端口,但是你还是想使用nginx服务,你就要更改nginx监听另外的端口。在这篇教程中,我们将使用8000端口。
在你的网站中配置nginx
你需要uwsgi_params 文件,它能够然nginx又uWSGI支配,你可以从这里下载
将它复制到你的项目目录下,接下来nginx将会使用到它。
现在创建一个mysite_nginx.conf文件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34# mysite_nginx.conf
# the upstream component nginx needs to connect to
upstream django {
# server unix:///path/to/your/mysite/mysite.sock; # for a file socket
server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}
# configuration of the server
server {
# the port your site will be served on
listen 8000;
# the domain name it will serve for
server_name .example.com; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
location /media {
alias /path/to/your/mysite/media; # your Django project's media files - amend as required
}
location /static {
alias /path/to/your/mysite/static; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /path/to/your/mysite/uwsgi_params; # the uwsgi_params file you installed
}
}
这个配置文件告诉nginx服务文件系统中那些媒体和静态文件,并且处理来自Django的请求。为你长远打算你也可以让一个服务处理media/static,另外一个服务处理Django请求,但在这里,这样刚刚好。
创建一个链接到/etc/nginx/sites-enabled让nginx能够识别它:
sudo ln -s ~/path/to/your/mysite/mysite_nginx.conf /etc/nginx/sites-enabled/
部署静态文件
在运行nginx之前,你要在static目录下收集Django用到的静态文件,首先你要在mysite/settings.py中加上:1
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
然后运行
python manage.py collectstatic
基本nginx测试
重启nginx服务
sudo /etc/init.d/nginx restart
为了检查media文件是否正确,在/path/to/your/project/project/media directory添加一张图片media.png ,然后访问http://example.com:8000/media/media.png 。如果起作用,至少说明nginx能够提供服务。
你可以不重启nginx服务,而是先关掉他,然后再重新打开,这样你就会发现一些问题。
nginx、uWSGI和test.py
让我们将nginx与‘hello word’的test.py应用连接起来
uwsgi –socket :8001 –uwsgi-file test.py #刚才nginx对内的端口是8001
除了这个部分,这次跟前面一样:
socket :8001 #使用uwsgi协议,8001端口
nginx同时也配置成在那个端口与uWSGI相连接,外网连接的端口是8000端口
点击一下,说明我们现在所处的阶段是:
the web client <-> the web server <-> the socket <-> uWSGI <-> Python->->->->
于此同时你也可以访问uWSGI的对外端口:8000,但是有非常大的可能他是不会工作的因为你的浏览器使用的是http而不是uWSGI,虽然你能够在你的终端上看到来自uWSGI的输出
使用Unix sockets来代替端口
现在为止我们已经使用了TCP端口(因为它很简单),但是事实上用Unix sockets比端口更好——他会减少很多麻烦(here’s less overhead)
编辑文件 mysite_nginx.conf ,把它改成这样:
1 | server unix:///path/to/your/mysite/mysite.sock; # for a file socket |
然后重启nginx服务
重新运行uWSGI:
uwsgi –socket mysite.sock –wsgi-file test.py
这个时候socket告诉uWSGI他要用哪个文件
在浏览器里面再次打开连接http://example.com:8000/ 吧
如果不起作用
检查你的nginx日志文件(/var/log/nginx/error.log),如果你看到下面的错误:
connect() to unix:///path/to/your/mysite/mysite.sock failed (13: Permissiondenied)
也许你需要管理权限允许nginx使用socket
尝试:
uwsgi –socket mysite.sock –wsgi-file test.py –chmod-socket=666 # (very permissive)
或者:
uwsgi –socket mysite.sock –wsgi-file test.py –chmod-socket=664 # (more sensible)
你可能还需要添加你的用户到nginx的用户群中去(可能是类似www-data这样的),这样nginx就可以读写你的socket了
nginx的日志文件值得你在终端一直打开,这样你就可以很容易排除错误
使用uWSGI和nginx来运行Django应用
让我们来运行我们的Django 应用:
uwsgi –socket mysite.sock –module mysite.wsgi –chmod-socket=664
现在uWSGI和nginx应该不只是显示‘hello,world’了,而是你的Django应用。
配置一个.ini文件来让你的uWSGI运行
我们可以将一些我们常用的uWSGI选项加入一个文件中,然后让uWSGI去运行这个文件,这能够让我们更好得管理我们的配置
创建一个文件mysite_uwsgi.ini
1 | # mysite_uwsgi.ini file |
然后用这个文件运行uWSGI:
uwsgi –ini mysite_uwsgi.ini # the –ini option is used to specify a file
(注意这里同时也要给socket加权限才可以)
测试Django应用是否运行成功
在本地系统中运行uWSGI
到目前为止,uWSGI只能够在我们的虚拟环境下运行,为了开发我们要将他放在本地系统中
退出虚拟环境:
deactivate
在本地系统安装uWSGI:
1 | sudo pip install uwsgi |
uWSGI的Wiki中有一个安装说明,在安装之前,值得你去考虑使用哪个版本并且使用最合适的方式去安装它
再一次检查你能够跟之前一样运行uWSGI:
uwsgi –ini mysite_uwsgi.ini # the –ini option is used to specify a file
Emperor 模式
uWSGI能够运行emperor模式。再这个模式下,能够监视uWSGI的配置文件,并且为每种情况产生样例(will spawn instances (‘vassals’) for each one it finds.)
每次只要配置文件修改了,emperor就会自动重启服务:1
2
3
4
5
6
7# create a directory for the vassals
sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals
# symlink from the default config directory to your config file
sudo ln -s /path/to/your/mysite/mysite_uwsgi.ini /etc/uwsgi/vassals/
# run the emperor
uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data
你可能要用到超级用户的权限来运行:
sudo uwsgi –emperor /etc/uwsgi/vassals –uid www-data –gid www-data
选项的含义:
- emperor : 去哪里找到服务
- uid: 启动的用户id
- gid:启动的群id
检查一下站点服务,它应该能够成功运行
让uWSGI自启动
最后一步就是让以上这些在开机的时候能够自启动
你只需要编辑/etc/rc.local 并添加:
/usr/local/bin/uwsgi –emperor /etc/uwsgi/vassals –uid www-data –gid www-data –daemonize /var/log/uwsgi-emperor.log
更加全面的ini配置文件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35[uwsgi]
uid = www # 设置启动的用户组
gid = www
chdir = /alidata/www/fdcode/devops # 指定项目目录
module = wsgi # 加载wsgi.py模块
master = true # 启动主进程,一般设置true或 1
processes = 2 # 设置启动的进程数
listen = 100 # 设置socket监听队列大小,超出队列的请求将会被拒绝
;socket = /var/run/uwsgi/uwsgi.sock # 设置socket监听
socket = :9090 # 设置端口监听
pidfile = /var/run/uwsgi/uwsgi.pid # 指定pid文件
vacuum = true # 当服务器退出的时候自动删除unixsocket文件和pid文件。
enable-threads = true # 允许用内嵌的语言启动线程。这将允许你在app程序中产生一个子线程
buffer-size = 32768 # 设置用于uwsgi包解析的内部缓存区大小为64k。默认是4k。
reload-mercy = 8 # 设置在平滑的重启(直到接收到的请求处理完才重启)一个工作子进程中,等待这个工作结束的最长秒数。这个配置会使在平滑地重启工作子进程中,如果工作进程结束时间超过了8秒就会被强行结束(忽略之前已经接收到的请求而直接结束)
max-requests = 5000 # 为每个工作进程设置请求数的上限。当一个工作进程处理的请求数达到这个值,那么该工作进程就会被回收重用(重启)。你可以使用这个选项来默默地对抗内存泄漏
limit-as = 512 # 通过使用POSIX/UNIX的setrlimit()函数来限制每个uWSGI进程的虚拟内存使用数。这个配置会限制uWSGI的进程占用虚拟内存不超过256M。如果虚拟内存已经达到256M,并继续申请虚拟内存则会使程序报内存错误,本次的http请求将返回500错误。
harakiri = 60 # 一个请求花费的时间超过了这个harakiri超时时间,那么这个请求都会被丢弃,并且当前处理这个请求的工作进程会被回收再利用(即重启)
daemonize = /alidata/log/uwsgi/uwsgi_server.log # 使进程在后台运行,并将日志打到指定的日志文件或者udp服务器
总结一波
在一开始的流程图中各段的实现:
the web client <-> the web server
通过nginx服务器,监听的是8000端口。配置文件:mysite_nginx.conf->the web server <-> the socket
nginx配置文件指定socket, 在配置文件中添加sock路径 我这里是htmltest/htmltest.sock 配置文件:mysite_nginx.conf->the socket <-> uwsgi
通过指定socket(给出socket的路径) 配置文件:mysite_uwsgi.ini (注意要在配置中给uWSGI权限)->uwsgi <-> Django
通过指定服务模块 配置文件:mysite_uwsgi.ini->
第一次翻译文章,如果有什么恰当的地方望指正。