uwsgi配置发布web服务器

通常我们本地开发环境使用运行python脚本用的是wsgipycharm更是跟我们内置好了;而生产环境下我们所需要的环境通常是:nginx+uwsgi+virturlenvwrapper,本文简单说下此环境下的配置。

WSGIWeb服务器网关接口。它是一个规范,描述了Web服务器如何与Web应用程序通信,以及Web应用程序如何链接在一起以处理一个请求,(接收请求,处理请求,响应请求)

Django部署

Django的主要部署平台是 WSGI,这是用于Web服务器和应用程序的Python标准。

Djangostartproject管理命令设置一个简单的默认WSGI配置,可以根据需要为您的项目进行调整,并指示任何符合WSGI的应用程序服务器使用。

application
使用WSGI部署的关键概念是应用程序服务器用于与代码通信的 application 可调用。它通常在服务器可访问的Python模块中作为名为 application 的对象提供。

startproject 命令创建包含这样的 application 可调用的文件 <project_name>/wsgi.py. ,它被Django的开发服务器和生产WSGI部署使用。
WSGI服务器从其配置中获取 application 可调用的路径。 Django的内置服务器,即 runserver 命令,从 WSGI_APPLICATION 设置读取它。

以下直接示例演示:

环境准备

Nginx

安装参考:nginx安装及配置多域名初体验

virtualenvwraper

安装参考:virtualenvwraper安装与使用

python3

安装参考:python3安装

uswgi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 进入虚拟环境
root@Tony-PC:/opt/pywww# workon django2

#查看python是否是3.0且指向虚拟环境
(django2) root@Tony-PC:/opt/pywww# python -V
Python 3.6.5
(django2) root@Tony-PC:/opt/pywww# which python
/opt/pyenv/django2/bin/python

# 查看pip指向
(django2) root@Tony-PC:/opt/pywww# pip -V
pip 19.2.2 from /opt/pyenv/django2/lib/python3.6/site-packages/pip (python 3.6)

# 安装uswgi
(django2) root@Tony-PC:/opt/pywww# pip install uwsgi

# 检查uwsgi和uwsgi python版本
(django2) root@Tony-PC:/opt/pywww# uwsgi --version
2.0.18
(django2) root@Tony-PC:/opt/pywww# uwsgi --python-version
3.6.5

uwsgi测试单文件

创建test.py
1
2
3
def application(env, start_response):
start_response('200 ok', [('Content-Type', 'text/html')])
return [b'hello world']
运行该文件:
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
36
37
38
39
40
41
42
43
# uwsgi --http :8001 --wsgi-file test.py
# http :8001: 使用http协议,端口8001
# wsgi-file test.py: 加载指定的文件,test.py

(django2) root@Tony-PC:/opt/pywww/mysite# uwsgi --http :8001 --wsgi-file test.py
*** Starting uWSGI 2.0.18 (64bit) on [Mon Aug 19 18:01:50 2019] ***
compiled with version: 7.3.0 on 19 August 2019 06:30:34
os: Linux-4.15.0-29deepin-generic #31 SMP Fri Jul 27 07:12:08 UTC 2018
nodename: Tony-PC
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 8
current working directory: /opt/pywww/mysite
detected binary path: /opt/pyenv/django2/bin/uwsgi
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
*** WARNING: you are running uWSGI without its master process manager ***
your processes number limit is 31152
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uWSGI http bound on :8000 fd 4
spawned uWSGI http 1 (pid: 14213)
uwsgi socket 0 bound to TCP address 127.0.0.1:42333 (port auto-assigned) fd 3
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
Python version: 3.6.5 (default, May 11 2018, 13:30:17) [GCC 7.3.0]
*** Python threads support is disabled. You can enable it with --enable-threads ***
Python main interpreter initialized at 0x5629304088e0
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 72920 bytes (71 KB) for 1 cores
*** Operational MODE: single process ***
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x5629304088e0 pid: 14212 (default app)
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 14212, cores: 1)

浏览器访问

1
2
3
4
5
# 控制台显示访问信息:
[pid: 4864|app: 0|req: 1/1] 10.10.10.238 () {38 vars in 742 bytes} [Tue Aug 20 09:17:23 2019] GET / => generated 11 bytes in 0 msecs (HTTP/1.1 200
) 1 headers in 44 bytes (1 switches on core 0)
[pid: 4864|app: 0|req: 2/2] 10.10.10.238 () {38 vars in 691 bytes} [Tue Aug 20 09:17:23 2019] GET /favicon.ico => generated 11 bytes in 0 msecs (H
TTP/1.1 200) 1 headers in 44 bytes (1 switches on core 0)

uwsgi测试django程序

代码准备
mysite/urls.py
1
2
3
4
5
6
7
8
9
10
11
from django.contrib import admin
from django.urls import path
from django.shortcuts import HttpResponse
from blog import views
def hello(request):
return HttpResponse('你好,中国')
urlpatterns = [
path('admin/', admin.site.urls),
path('hello', hello),
path('play', views.play)
]
blog/views.py
1
2
3
4
from django.shortcuts import render, HttpResponse

def play(request):
return render(request, 'play.html')
templates/play.html
1
2
3
4
5
6
7
8
9
<html>
<head>
<meta charset="utf8" />
<title>测试网页test</title>
<link type="text/css" rel="stylesheet" href="/static/css.css" />
</head>
<body>
<h1>我们是中国chinese</h1>
</body>
static/css.css
1
h1{color:green}
运行程序
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
36
37
38
39
40
41
42
43
44
45
46
47
# uwsgi --http :8003 --module mysite.wsgi --py-autoreload=1
# http :8003: 使用http协议,端口8003
# --module mysite.wsgi: 加载指定的wsgi模块
# --py-autoreload=1: 热加载
# 此时修改django代码,uWSGI会自动加载django程序,页面生效

(django2) root@Tony-PC:/opt/pywww/mysite# uwsgi --http :8003 --module mysite.wsgi --py-autoreload=1

*** Starting uWSGI 2.0.18 (64bit) on [Tue Aug 20 09:33:03 2019] ***
compiled with version: 7.3.0 on 19 August 2019 06:30:34
os: Linux-4.15.0-29deepin-generic #31 SMP Fri Jul 27 07:12:08 UTC 2018
nodename: Tony-PC
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 8
current working directory: /opt/pywww/mysite
detected binary path: /opt/pyenv/django2/bin/uwsgi
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
your processes number limit is 31152
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uWSGI http bound on :8003 fd 4
uwsgi socket 0 bound to TCP address 127.0.0.1:35147 (port auto-assigned) fd 3
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
Python version: 3.6.5 (default, May 11 2018, 13:30:17) [GCC 7.3.0]
Python main interpreter initialized at 0x555e54571920
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
python threads support enabled
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 145840 bytes (142 KB) for 1 cores
*** Operational MODE: single process ***
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x555e54571920 pid: 5586 (default app)
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 5586)
spawned uWSGI worker 1 (pid: 5588, cores: 1)
spawned uWSGI http 1 (pid: 5589)
Python auto-reloader enabled

访问程序

1
2
3
# 控制台显示访问信息:
[pid: 5588|app: 0|req: 1/1] 10.10.10.238 () {38 vars in 752 bytes} [Tue Aug 20 01:40:32 2019] GET /hello => generated 13 bytes in 4 msecs (HTTP/1.
1 200) 3 headers in 108 bytes (1 switches on core 0)

socket测试django

配置nginx
etc/nginx/nginx.conf
1
2
3
4
5
6
7
8
9
10
11
server{
listen 80;
server_name test.to;
location / {
# nginx自带ngx_http_uwsgi_module模块,起到nginx和uwsgi交互作用
# include 就是一个“引入的作用”,就是将外部一个文件的参数,导入到当前的nginx.conf中生效
include /etc/nginx/uwsgi_params;
# 这里是nginx将请求转发给 uwsgi启动的 8002端口
uwsgi_pass 0.0.0.0:8002;
}
}
本地windows修改hosts
1
10.10.10.125 test.to
运行程序
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
36
37
38
39
40
41
42
43
44
45
# uwsgi --socket :8002 --module mysite.wsgi --py-autoreload=1
# socket :8002: 使用socket,8002
# --module mysite.wsgi: 加载指定的wsgi模块
# --py-autoreload=1: 热加载
# 此时修改django代码,uWSGI会自动加载django程序,页面生效
# socket指的是,uwsgi启动一个socket连接,当你使用nginx+uwsgi的时候,使用socket参数

(django2) root@Tony-PC:/opt/pywww/mysite# uwsgi --socket :8002 --module mysite.wsgi --py-autoreload=1

*** Starting uWSGI 2.0.18 (64bit) on [Tue Aug 20 09:53:32 2019] ***
compiled with version: 7.3.0 on 19 August 2019 06:30:34
os: Linux-4.15.0-29deepin-generic #31 SMP Fri Jul 27 07:12:08 UTC 2018
nodename: Tony-PC
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 8
current working directory: /opt/pywww/mysite
detected binary path: /opt/pyenv/django2/bin/uwsgi
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
your processes number limit is 31152
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uwsgi socket 0 bound to TCP address :8002 fd 3
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
Python version: 3.6.5 (default, May 11 2018, 13:30:17) [GCC 7.3.0]
Python main interpreter initialized at 0x55fd342b62f0
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
python threads support enabled
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 145840 bytes (142 KB) for 1 cores
*** Operational MODE: single process ***
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x55fd342b62f0 pid: 6695 (default app)
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 6695)
spawned uWSGI worker 1 (pid: 6697, cores: 1)
Python auto-reloader enabled
访问程序

可能此时你还没意识到有什么问题,此时我们访问admin试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 控制台用户访问信息
[pid: 6697|app: 0|req: 1/1] 10.10.10.238 () {42 vars in 739 bytes} [Tue Aug 20 01:59:59 2019] GET /play => generated 202 bytes in 9 msecs (HTTP/1.
1 200) 3 headers in 109 bytes (1 switches on core 0)Not Found: /static/css.css
[pid: 6697|app: 0|req: 2/2] 10.10.10.238 () {40 vars in 628 bytes} [Tue Aug 20 01:59:59 2019] GET /static/css.css => generated 2183 bytes in 2 mse
cs (HTTP/1.1 404) 3 headers in 102 bytes (1 switches on core 0)
[pid: 6697|app: 0|req: 3/3] 10.10.10.238 () {40 vars in 710 bytes} [Tue Aug 20 02:00:43 2019] GET /admin => generated 0 bytes in 0 msecs (HTTP/1.1
301) 3 headers in 112 bytes (1 switches on core 0)
[pid: 6697|app: 0|req: 4/4] 10.10.10.238 () {40 vars in 712 bytes} [Tue Aug 20 02:00:43 2019] GET /admin/ => generated 0 bytes in 6 msecs (HTTP/1.
1 302) 7 headers in 265 bytes (1 switches on core 0)
[pid: 6697|app: 0|req: 5/5] 10.10.10.238 () {40 vars in 749 bytes} [Tue Aug 20 02:00:43 2019] GET /admin/login/?next=/admin/ => generated 1819 byt
es in 21 msecs (HTTP/1.1 200) 7 headers in 395 bytes (1 switches on core 0)Not Found: /static/admin/css/base.css
[pid: 6697|app: 0|req: 6/6] 10.10.10.238 () {42 vars in 760 bytes} [Tue Aug 20 02:00:43 2019] GET /static/admin/css/base.css => generated 2216 byt
es in 2 msecs (HTTP/1.1 404) 3 headers in 102 bytes (1 switches on core 0)Not Found: /static/admin/css/login.css
[pid: 6697|app: 0|req: 7/7] 10.10.10.238 () {42 vars in 762 bytes} [Tue Aug 20 02:00:43 2019] GET /static/admin/css/login.css => generated 2219 by
tes in 1 msecs (HTTP/1.1 404) 3 headers in 102 bytes (1 switches on core 0)Not Found: /static/admin/css/responsive.css
[pid: 6697|app: 0|req: 8/8] 10.10.10.238 () {42 vars in 772 bytes} [Tue Aug 20 02:00:43 2019] GET /static/admin/css/responsive.css => generated 22
34 bytes in 1 msecs (HTTP/1.1 404) 3 headers in 102 bytes (1 switches on core 0)

可以看到我们加载的静态资源css等都没有正常显示出来,控制台也都显示静态资源404,后面我们来解决这个问题

uwsgi使用配置文件测试django程序

上面程序运行时每次都要用长命令,这里我们尝试使用配置文件来运行django程序,并解决上面静态资源404的问题。

uwsgi配置文件

uwsgi支持inixml等多种配置方式,本文以 ini 为例, 在/opt/pyuwsgi/目录下新建mysite_uwsgi.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
# mysite_uwsgi.ini file
[uwsgi]

# 指定项目的绝对路径的第一层路径
chdir = /opt/pywww/mysite
# 指定项目的 wsgi.py文件!!!!!!!!!!!!
# 写入相对路径即可,这个参数是以 chdir参数为相对路径
# module与wsgi-file填写一个即可,都代表找到wsgi文件,写法不同
module = mysite.wsgi
#wsgi文件路径,在项目底下
#wsgi-file = mysite/wsgi.py
# 写入虚拟环境解释器的 绝对路径!!!!!!
# 可使用cdvirtualenv进入虚拟环境目录,然后使用pwd查看当前目录
home = /opt/pyenv/django2
# 允许主线程存在(true)
master = true
# 指定uwsgi启动的进程个数(可根据电脑核心数调整)
processes = 4
# 指定uwsgi启动的线程个数
threads = 2
#socket指的是,uwsgi启动一个socket连接,当你使用nginx+uwsgi的时候,使用socket参数
socket = 0.0.0.0:8002
#不用nginx直接当做web服务器使用
#http=0.0.0.0:9000
#socket权限设置
# chmod-socket = 664
# 当服务器退出的时候自动清理环境,删除unix socket文件和pid文件
# vacuum = true

配置nginx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 定义名为uwsgipool的负载均衡池,池中写入uwsgi发布django的socket地址
upstream uwsgipool {
server 0.0.0.0:8005;
}

server{
listen 80;
server_name test.to;
location / {
# nginx自带ngx_http_uwsgi_module模块,起到nginx和uwsgi交互作用
# include 就是一个“引入的作用”,就是将外部一个文件的参数,导入到当前的nginx.conf中生效
include /etc/nginx/uwsgi_params;
# 这里是nginx将请求转发给 uwsgi启动的 8002端口
# uwsgi_pass 0.0.0.0:8005;
# 转发至名为uwsgipool的负载均衡池
uwsgi_pass uwsgipool;
}
}
运行程序
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
36
37
38
39
40
41
42
43
44
45
# 使用mysite_uwsgi.ini的ini配置文件来启动uwsgi
(django2) root@Tony-PC:/opt/pyuwsgi# uwsgi --ini mysite_uwsgi.ini

[uWSGI] getting INI configuration from mysite_uwsgi.ini
*** Starting uWSGI 2.0.18 (64bit) on [Tue Aug 20 11:22:59 2019] ***
compiled with version: 7.3.0 on 19 August 2019 06:30:34
os: Linux-4.15.0-29deepin-generic #31 SMP Fri Jul 27 07:12:08 UTC 2018
nodename: Tony-PC
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 8
current working directory: /opt/pyuwsgi
detected binary path: /opt/pyenv/django2/bin/uwsgi
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
chdir() to /opt/pywww/mysite
your processes number limit is 31152
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uwsgi socket 0 bound to TCP address 0.0.0.0:8005 fd 3
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
Python version: 3.6.5 (default, May 11 2018, 13:30:17) [GCC 7.3.0]
Set PythonHome to /opt/pyenv/django2
*** Python threads support is disabled. You can enable it with --enable-threads ***
Python main interpreter initialized at 0x5601391f2b50
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 364600 bytes (356 KB) for 4 cores
*** Operational MODE: preforking ***
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x5601391f2b50 pid: 9744 (default app)
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 9744)
spawned uWSGI worker 1 (pid: 9746, cores: 1)
spawned uWSGI worker 2 (pid: 9747, cores: 1)
spawned uWSGI worker 3 (pid: 9748, cores: 1)
spawned uWSGI worker 4 (pid: 9749, cores: 1)

查看进程,开启的四个进程正常运行,另外有一个主进程,共5个

1
2
3
4
5
6
7
8
9
root@Tony-PC:/opt# ps -ef | grep uwsgi
root 9744 4738 3 11:22 pts/1 00:00:00 uwsgi --ini mysite_uwsgi.ini
root 9746 9744 0 11:22 pts/1 00:00:00 uwsgi --ini mysite_uwsgi.ini
root 9747 9744 0 11:22 pts/1 00:00:00 uwsgi --ini mysite_uwsgi.ini
root 9748 9744 0 11:22 pts/1 00:00:00 uwsgi --ini mysite_uwsgi.ini
root 9749 9744 0 11:22 pts/1 00:00:00 uwsgi --ini mysite_uwsgi.ini
root 9751 4563 0 11:23 pts/0 00:00:00 grep uwsgi
root@Tony-PC:/opt# netstat -tunlp | grep uwsgi
tcp 0 0 0.0.0.0:8005 0.0.0.0:* LISTEN 9744/uwsgi
访问程序
1
2
3
4
5
6
7
8
9
10
[pid: 9748|app: 0|req: 1/1] 10.10.10.238 () {44 vars in 869 bytes} [Tue Aug 20 03:23:27 2019] GET /admin/login/?next=/admin/ => generated 1819 bytes in 36 msecs (HTTP/1.1 200) 7 headers in 395 bytes (1 switches on core 0)
Not Found: /static/admin/css/base.css
[pid: 9748|app: 0|req: 2/2] 10.10.10.238 () {42 vars in 760 bytes} [Tue Aug 20 03:23:27 2019] GET /static/admin/css/base.css => generated 2216 bytes in 2 msecs (HTTP/1.1 404) 3 headers in 102 bytes (1 switches on core 0)
Not Found: /static/admin/css/login.css
[pid: 9749|app: 0|req: 1/3] 10.10.10.238 () {42 vars in 762 bytes} [Tue Aug 20 03:23:27 2019] GET /static/admin/css/login.css => generated 2219 bytes in 7 msecs (HTTP/1.1 404) 3 headers in 102 bytes (1 switches on core 0)
Not Found: /static/admin/css/responsive.css
[pid: 9747|app: 0|req: 1/4] 10.10.10.238 () {42 vars in 772 bytes} [Tue Aug 20 03:23:27 2019] GET /static/admin/css/responsive.css => generated 2234 bytes in 7 msecs (HTTP/1.1 404) 3 headers in 102 bytes (1 switches on core 0)
[pid: 9748|app: 0|req: 3/5] 10.10.10.238 () {44 vars in 821 bytes} [Tue Aug 20 03:23:46 2019] GET /play => generated 202 bytes in 0 msecs (HTTP/1.1 200) 3 headers in 109 bytes (1 switches on core 0)
Not Found: /static/css.css
[pid: 9748|app: 0|req: 4/6] 10.10.10.238 () {44 vars in 741 bytes} [Tue Aug 20 03:23:46 2019] GET /static/css.css => generated 2183 bytes in 1 msecs (HTTP/1.1 404) 3 headers in 102 bytes (1 switches on core 0)

发现静态资源依然是404

解决静态文件404
mysite/settings.py
1
2
3
4
5
6
# 静态文件目录的绝对地址
STATIC_ROOT = '/opt/pywww/mysite/static'
STATIC_URL = '/static/'
STATICFILES_DIRS=[
os.path.join(BASE_DIR, 'static')
]
nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 定义名为uwsgipool的负载均衡池,池中写入uwsgi发布django的socket地址
upstream uwsgipool {
server 0.0.0.0:8005;
}

server{
listen 80;
server_name test.to;
location / {
# nginx自带ngx_http_uwsgi_module模块,起到nginx和uwsgi交互作用
# include 就是一个“引入的作用”,就是将外部一个文件的参数,导入到当前的nginx.conf中生效
include /etc/nginx/uwsgi_params;
# 这里是nginx将请求转发给 uwsgi启动的 8002端口
# uwsgi_pass 0.0.0.0:8005;
# 转发至名为uwsgipool的负载均衡池
uwsgi_pass uwsgipool;
}
# 配置静态资源目录,与settings.py路径一致
location /static {
alias /opt/pywww/mysite/static;
}
}
收集django静态资源

重启nginx,使用python3 manage.py collectstatic收集静态资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(django2) root@Tony-PC:/opt/pywww/mysite# python manage.py collectstatic

You have requested to collect static files at the destination
location as specified in your settings:

/opt/pywww/mysite/static

This will overwrite existing files!
Are you sure you want to do this?

Type 'yes' to continue, or 'no' to cancel: yes

119 static files copied to '/opt/pywww/mysite/static', 1 unmodified.

119个文件已拷贝至目标目录

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
(django2) root@Tony-PC:/opt/pywww/mysite# tree static
static
├── admin
│   ├── css
│   │   ├── autocomplete.css
│   │   ├── base.css
│   │   ├── changelists.css
│   │   ├── dashboard.css
│   │   ├── fonts.css
│   │   ├── forms.css
│   │   ├── login.css
│   │   ├── responsive.css
│   │   ├── responsive_rtl.css
│   │   ├── rtl.css
│   │   ├── vendor
│   │   │   └── select2
│   │   │   ├── LICENSE-SELECT2.md
│   │   │   ├── select2.css
│   │   │   └── select2.min.css
│   │   └── widgets.css
│   ├── fonts
│   │   ├── LICENSE.txt
│   │   ├── README.txt
│   │   ├── Roboto-Bold-webfont.woff
│   │   ├── Roboto-Light-webfont.woff
│   │   └── Roboto-Regular-webfont.woff
│   ├── img
│   │   ├── calendar-icons.svg
│   │   ├── gis
│   │   │   ├── move_vertex_off.svg
│   │   │   └── move_vertex_on.svg
│   │   ├── icon-addlink.svg
│   │   ├── icon-alert.svg
│   │   ├── icon-calendar.svg
│   │   ├── icon-changelink.svg
│   │   ├── icon-clock.svg
│   │   ├── icon-deletelink.svg
│   │   ├── icon-no.svg
│   │   ├── icon-unknown-alt.svg
│   │   ├── icon-unknown.svg
│   │   ├── icon-viewlink.svg
│   │   ├── icon-yes.svg
│   │   ├── inline-delete.svg
│   │   ├── LICENSE
│   │   ├── README.txt
│   │   ├── search.svg
│   │   ├── selector-icons.svg
│   │   ├── sorting-icons.svg
│   │   ├── tooltag-add.svg
│   │   └── tooltag-arrowright.svg
│   └── js
│   ├── actions.js
│   ├── actions.min.js
│   ├── admin
│   │   ├── DateTimeShortcuts.js
│   │   └── RelatedObjectLookups.js
│   ├── autocomplete.js
│   ├── calendar.js
│   ├── cancel.js
│   ├── change_form.js
│   ├── collapse.js
│   ├── collapse.min.js
│   ├── core.js
│   ├── inlines.js
│   ├── inlines.min.js
│   ├── jquery.init.js
│   ├── popup_response.js
│   ├── prepopulate_init.js
│   ├── prepopulate.js
│   ├── prepopulate.min.js
│   ├── SelectBox.js
│   ├── SelectFilter2.js
│   ├── timeparse.js
│   ├── urlify.js
│   └── vendor
│   ├── jquery
│   │   ├── jquery.js
│   │   ├── jquery.min.js
│   │   └── LICENSE.txt
│   ├── select2
│   │   ├── i18n
│   │   │   ├── ar.js
│   │   │   ├── az.js
│   │   │   ├── bg.js
│   │   │   ├── ca.js
│   │   │   ├── cs.js
│   │   │   ├── da.js
│   │   │   ├── de.js
│   │   │   ├── el.js
│   │   │   ├── en.js
│   │   │   ├── es.js
│   │   │   ├── et.js
│   │   │   ├── eu.js
│   │   │   ├── fa.js
│   │   │   ├── fi.js
│   │   │   ├── fr.js
│   │   │   ├── gl.js
│   │   │   ├── he.js
│   │   │   ├── hi.js
│   │   │   ├── hr.js
│   │   │   ├── hu.js
│   │   │   ├── id.js
│   │   │   ├── is.js
│   │   │   ├── it.js
│   │   │   ├── ja.js
│   │   │   ├── km.js
│   │   │   ├── ko.js
│   │   │   ├── lt.js
│   │   │   ├── lv.js
│   │   │   ├── mk.js
│   │   │   ├── ms.js
│   │   │   ├── nb.js
│   │   │   ├── nl.js
│   │   │   ├── pl.js
│   │   │   ├── pt-BR.js
│   │   │   ├── pt.js
│   │   │   ├── ro.js
│   │   │   ├── ru.js
│   │   │   ├── sk.js
│   │   │   ├── sr-Cyrl.js
│   │   │   ├── sr.js
│   │   │   ├── sv.js
│   │   │   ├── th.js
│   │   │   ├── tr.js
│   │   │   ├── uk.js
│   │   │   ├── vi.js
│   │   │   ├── zh-CN.js
│   │   │   └── zh-TW.js
│   │   ├── LICENSE.md
│   │   ├── select2.full.js
│   │   └── select2.full.min.js
│   └── xregexp
│   ├── LICENSE.txt
│   ├── xregexp.js
│   └── xregexp.min.js
└── css.css

14 directories, 120 files
再次访问程序

1
2
3
4
5
# 资源正常加载
[pid: 9747|app: 0|req: 2/8] 10.10.10.238 () {44 vars in 828 bytes} [Tue Aug 20 04:13:08 2019] GET /play => generated 202 bytes in 5 msecs (HTTP/1.1 200) 3 headers in 109 bytes (1 switches on core 0)
[pid: 9748|app: 0|req: 5/9] 10.10.10.238 () {42 vars in 801 bytes} [Tue Aug 20 04:13:12 2019] GET /admin/ => generated 0 bytes in 0 msecs (HTTP/1.1 302) 7 headers in 265 bytes (1 switches on core 0)
[pid: 9748|app: 0|req: 6/10] 10.10.10.238 () {42 vars in 838 bytes} [Tue Aug 20 04:13:12 2019] GET /admin/login/?next=/admin/ => generated 1819 bytes in 7 msecs (HTTP/1.1 200) 7 headers in 395 bytes (1 switches on core 0)

uwsgi常用命令

1
2
3
#uwsgi --ini uwsgi.ini             # 启动
#uwsgi --reload uwsgi.pid # 重启
#uwsgi --stop uwsgi.pid # 关闭

更多uwsgi配置参考手册https://uwsgi-docs-cn.readthedocs.io/zh_CN/latest/WSGIquickstart.html

supervisor

supervisor 是基于 python 的任务管理工具,用来自动运行各种后台任务,当然你也能直接利用 nohup 命令使任务自动后台运行,但如果要重启任务,每次都自己手动 kill 掉任务进程,这样很繁琐,而且一旦程序错误导致进程退出的话,系统也无法自动重载任务。

安装supervisor

1
root@Tony-PC:/opt/pywww/mysite# pip3 install supervisor

生成supervisor配置文件

1
root@Tony-PC:/opt/pysupervisor# echo_supervisord_conf > /opt/pysupervisor/supervisord.conf

/opt/pysupervisor/supervisord.conf参数说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
supervisord.conf配置文件参数解释
[program:xx]是被管理的进程配置参数,xx是进程的名称
[program:xx]
command=/opt/apache-tomcat-8.0.35/bin/catalina.sh run ; 程序启动命令
autostart=true ; 在supervisord启动的时候也自动启动
startsecs=10 ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
autorestart=true ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启
startretries=3 ; 启动失败自动重试次数,默认是3
user=tomcat ; 用哪个用户启动进程,默认是root
priority=999 ; 进程启动优先级,默认999,值小的优先启动
redirect_stderr=true ; 把stderr重定向到stdout,默认false
stdout_logfile_maxbytes=20MB ; stdout 日志文件大小,默认50MB
stdout_logfile_backups = 20 ; stdout 日志文件备份数,默认是10
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out
stopasgroup=false ;默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程
killasgroup=false ;默认为false,向进程组发送kill信号,包括子进程

写入配置

1
2
[program:mysupervisord]
command = /opt/pyenv/django2/bin/uwsgi --ini /opt/pyuwsgi/mysite_uwsgi.ini

启动supervisor

1
2
3
4
supervisord -c /etc/supervisord.conf #启动supervisor

supervisorctl -c /etxc/supervisord.conf restart my #重启my项目
supervisorctl -c /etc/supervisord.conf [start|stop|restart] [program-name|all]

supervisor其他命令

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
supervisorctl
进入更新新的配置到supervisord交互命令行

二、更新新的配置到supervisord

supervisorctl update
三、重新启动配置中的所有程序

supervisorctl reload
四、启动某个进程(program_name=你配置中写的程序名称)

supervisorctl start program_name
五、查看正在守候的进程

supervisorctl
六、停止某一进程 (program_name=你配置中写的程序名称)

pervisorctl stop program_name
七、重启某一进程 (program_name=你配置中写的程序名称)

supervisorctl restart program_name
八、停止全部进程

supervisorctl stop all
注意:显示用stop停止掉的进程,用reload或者update都不会自动重启。

supervisor报错

大致报错信息:error: , [Errno 113] No route to host: file: /usr/lib64/python2.7/socket.py line: 571

这个报错的原因是supervisorctl没有找到自己的运行配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# supervisorctl -h

supervisorctl -- control applications run by supervisord from the cmd line.

Usage: /usr/bin/supervisorctl [options] [action [arguments]]

Options:
-c/--configuration -- configuration file path (default /etc/supervisord.conf)
-h/--help -- print usage message and exit
-i/--interactive -- start an interactive shell after executing commands
-s/--serverurl URL -- URL on which supervisord server is listening
(default "http://localhost:9001").
-u/--username -- username to use for authentication with server
-p/--password -- password to use for authentication with server
-r/--history-file -- keep a readline history (if readline is available)

action [arguments] -- see below

Actions are commands like "tail" or "stop". If -i is specified or no action is
specified on the command line, a "shell" interpreting actions typed
interactively is started. Use the action "help" to find out about available
actions.

通过上面 default /etc/supervisord.conf 得知 supervisorctl 默认使用的配置文件地址,而 supervisor 进程使用的配置文件地址是: /usr/bin/python /usr/bin/supervisord -c /etc/supervisor/supervisord.conf。

解决方法

1
ln -s /etc/supervisor/supervisord.conf /etc/supervisord.conf

访问测试

正常