uwsgi+Nginx+Django部署项目

时间:2022-02-26 03:41:52

一、前言

在部署项目前,你已有一个能够在你本机测试过,能正常启动的Django项目(毕竟本文主要讲解部署Django项目),以及掌握了Linux系统的一些基本命令。

相关链接:

Centos7安装python3和pip

Centos7安装MySQL5.7(yum)

pipreqs(找当前项目依赖的包)

virtualenv(虚拟环境)

二、WSGI、uWSGI、uwsgi详解

WSGI:(Web Server Gateway Interface)服务器网关接口,是一种协议。要实现WSGI协议,必须同时实现Web服务器和Web应用,因为它描述的是Web服务器(如nginx、uWSGI等服务器)如何与Web应用(如用Django框架写的程序)进行通信。

uWSGI:是一个Web服务器,实现了WSGI协议、uwsgi协议、http协议等。它要做的就是把http协议转化成语言支持的网络协议。比如把http协议转化成WSGI协议,让Python可以直接使用。 Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。

uwsgi:是一种线路协议,并非是通信协议,在此常用于在uWSGI服务器与其他网络服务器的数据通信。uwsgi协议是一个uWSGI服务器自有的协议,它用于定义传输信息的类型。它与WSGI相比是两样东西。

三、uwsgi安装与基本使用

uwsgi官网

pip3 install uwsgi

基本测试

新建一个test.py:

def application(env, start_response):
    start_response("200 OK", [("Content-Type", "text/html")])
    return [b"Hello World"]

在服务器上执行命令启动Web服务器:

uwsgi --http :8000 --wsgi-file test.py
# 或:
uwsgi --http :9002 --wsgi-file test.py --master --processes 4

参数说明:

--http       # 指定了http监听地址和端口
--wsgi-file  # 指定了应用程序入口
--master # 允许主进程存在,用来管理其他进程
--processes # 开启4个进程

PS:如果执行了上面命令显示 uwsgi: command not found

则配置软链接,方便使用:

ln -s python安装路径/bin/uwsgi /usr/bin/uwsgi
例如我的:
ln -s /usr/local/python3/bin/uwsgi /usr/bin/uwsgi

启动成功后,打开浏览器,访问"服务器公网IP:8000″(或者在本机访问""http://localhost:8000),就可以看到"Hello World"字样了。

PS:我使用的是阿里云服务器,如果你也是;项目部署好了,在浏览器打不开的话,可以登录服务器控制台,添加安全组规则即可,具体请自行百度。

用uwsgi启动flask

# app.py
from flask import Flask
app = Flask(__name__)

@app.route("/")
def index():
    return "这是我的第一个flask程序!"

if __name__ == "__main__":
    app.run()

PS:如果是flask程序,需要再加 --callable app

uwsgi --http :8000 --wsgi-file app.py --callable app

用uwsgi启动django

uwsgi+Nginx+Django部署项目

修改配置文件,将 ALLOWED_HOSTS 设置为:当前服务器IP或*,如:

ALLOWED_HOSTS = ["*",]

启动django:

uwsgi --http :8000 --chdir /usr/local/django/mysite/ --wsgi-file mysite/wsgi.py

根据配置文件启动

1、创建配置文件 mysite.ini

[uwsgi]
# 指定ip端口(直接运行设置为http、用nginx则设置为socket)
http = 0.0.0.0:8000
# 执行项目的目录
chdir = /usr/local/django/mysite/
# Django的wsgi.py文件
module = mysite.wsgi  # 相当于mysite/wsgi.py
# 允许主进程存在
master = true
# 开启的进程数量
processes = 4
# 后台运行
daemonize2 = true
# uwsgi.pid文件可以用来重启和停止uwsgi服务
pidfile = %(chdir)/uwsgi/uwsgi.pid
# uwsgi.status可以用来查看uwsgi的服务状态
stats = %(chdir)/uwsgi/uwsgi.status
# 当服务器退出的时候自动清理环境 
vacuum = true
# 将日志打到指定的日志文件
logto = /tmp/mysite.log

PS:如果有虚拟环境可以添加上虚拟环境路径配置,virtualenv = /envs/env_mysite

2、根据配置文件启动(注意路径)

# 启动
uwsgi --ini mysite.ini
# 停止
uwsgi --stop uwsgi.pid
# 重启
uwsgi --reload uwsgi.pid
# 查看uwsgi的服务状态
uwsgi --connect-and-read uwsgi.status

此时访问时,会出现找不到静态文件的错误。

想要uwsgi处理静态文件,需要先将django的静态文件收集到制定目录,然后再设置对应关系。

1、收集django静态文件

  • 在django的配置文件中添加:STATIC_ROOT = os.path.join(BASE_DIR, "allstatic");
  • 执行 python3 manage.py collectstatic 命令,至此django项目所有相关静态文件都会收集到指定目录。

2、设置uwsgi静态文件对应关系

在上面的 mysite.ini 文件中加入以下配置:

# static-map(映射一个资源到静态文件区)
static-map = /static=/usr/local/django/mysite/allstatic

还有(看你需不需要配置):

static-map = /media=/usr/local/django/mysite/media
static-map = /images=/usr/local/django/mysite/images

再次使用配置文件方式启动,所有静态文件就可以加载了。

四、Nginx

Nginx是一款轻量级的高性能Web服务器/反向代理服务器。我们可以利用Nginx做反向代理、负载均衡以及处理静态文件。

安装:点击这里

下面的所有配置都是为Django项目配置的

uwsgi官网:使用uwsgi和Nginx设置Django和Web服务器

配置nginx

首先要确保你安装的Nginx中有uwsgi_params文件哦,如下;没有可以从这里获取:点我

uwsgi+Nginx+Django部署项目

配置nginx.conf:

建议将原来的配置保存下来,留着备用。

uwsgi+Nginx+Django部署项目uwsgi+Nginx+Django部署项目
user root;
worker_processes 4;

error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    # include为你的nginx对应路径
    include             /usr/local/nginx/conf/mime.types;
    default_type        application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;

    tcp_nodelay         on;
    keepalive_timeout   65;

    upstream django {
        server 127.0.0.1:8001; 
    }

    server {
        listen      80;

        charset     utf-8;

        client_max_body_size 75M;

        location /static {
            # 项目收集静态文件路径
            alias /usr/local/django/mysite/allstatic;
        }

        location / {
            uwsgi_pass  django;
            include     uwsgi_params;
        }
    }
}
nginx.conf

这个nginx.conf文件告诉nginx从文件系统中提供媒体和静态文件,以及处理需要django干预的请求。对于大型部署,让一台服务器处理静态/媒体文件,另一台服务器处理django应用程序,被认为是一种良好的做法,就目前而言,这样做会很好。

部署静态文件

在运行nginx之前,必须收集静态文件夹中的所有Django静态文件。这一步我们已经在上面完成了。

配置uwsgi(ini文件)

[uwsgi]
socket = 127.0.0.1:8001  # 注意这里的修改
chdir = /usr/local/django/mysite/
module = mysite.wsgi
master = true
processes = 4
daemonize2 = true
pidfile = %(chdir)/uwsgi/uwsgi.pid
stats = %(chdir)/uwsgi/uwsgi.status
vacuum = true
logto = /tmp/mysite.log
static-map = /static=/usr/local/django/mysite/allstatic

启动uwsgi和nginx(注意路径)

# 启动uwsgi
uwsgi --ini mysite.ini
# 启动nginx(因为我那篇nginx随笔没有成功将nginx配置成服务,所以这里就这样启动)
cd /usr/local/nginx/sbin/
./nginx

五、使用supervisor来管理process

官方文档

项目正式部署的时候,我们通常会将其转化为系统的守护进程,将其放到后台运行,但是其并不会为我们监控进程的运行状态,一旦进程崩溃,我们的项目就无法继续提供服务。所以我们要借助supervisor,帮助我们启动uwsgi并维护(uwsgi进程关闭时,自动将其启动起来)。

1、安装

yum install supervisor

原文件 /etc/supervisord.conf(仅做纪录):

uwsgi+Nginx+Django部署项目uwsgi+Nginx+Django部署项目
; Sample supervisor config file.

[unix_http_server]
file=/var/run/supervisor/supervisor.sock   ; (the path to the socket file)
;chmod=0700                 ; sockef file mode (default 0700)
;chown=nobody:nogroup       ; socket file uid:gid owner
;username=user              ; (default is no username (open server))
;password=123               ; (default is no password (open server))

;[inet_http_server]         ; inet (TCP) server disabled by default
;port=127.0.0.1:9001        ; (ip_address:port specifier, *:port for all iface)
;username=user              ; (default is no username (open server))
;password=123               ; (default is no password (open server))

[supervisord]
logfile=/var/log/supervisor/supervisord.log  ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB       ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10          ; (num of main logfile rotation backups;default 10)
loglevel=info               ; (log level;default info; others: debug,warn,trace)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=false              ; (start in foreground if true;default false)
minfds=1024                 ; (min. avail startup file descriptors;default 1024)
minprocs=200                ; (min. avail process descriptors;default 200)
;umask=022                  ; (process file creation umask;default 022)
;user=chrism                 ; (default is current user, required if root)
;identifier=supervisor       ; (supervisord identifier, default is 'supervisor')
;directory=/tmp              ; (default is not to cd during start)
;nocleanup=true              ; (don't clean up tempfiles at start;default false)
;childlogdir=/tmp            ; ('AUTO' child log dir, default $TEMP)
;environment=KEY=value       ; (key value pairs to add to environment)
;strip_ansi=false            ; (strip ansi escape codes in logs; def. false)

; the below section must remain in the config file for RPC
; (supervisorctl/web interface) to work, additional interfaces may be
; added by defining them in separate rpcinterface: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor/supervisor.sock ; use a unix:// URL  for a unix socket
;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
;username=chris              ; should be same as http_username if set
;password=123                ; should be same as http_password if set
;prompt=mysupervisor         ; cmd line prompt (default "supervisor")
;history_file=~/.sc_history  ; use readline history if available

; The below sample program section shows all possible program subsection values,
; create one or more 'real' program: sections to be able to control them under
; supervisor.

;[program:theprogramname]
;command=/bin/cat              ; the program (relative uses PATH, can take args)
;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
;numprocs=1                    ; number of processes copies to start (def 1)
;directory=/tmp                ; directory to cwd to before exec (def no cwd)
;umask=022                     ; umask for process (default None)
;priority=999                  ; the relative start priority (default 999)
;autostart=true                ; start at supervisord start (default: true)
;autorestart=true              ; retstart at unexpected quit (default: true)
;startsecs=10                  ; number of secs prog must stay running (def. 1)
;startretries=3                ; max # of serial start failures (default 3)
;exitcodes=0,2                 ; 'expected' exit codes for process (default 0,2)
;stopsignal=QUIT               ; signal used to kill process (default TERM)
;stopwaitsecs=10               ; max num secs to wait b4 SIGKILL (default 10)
;user=chrism                   ; setuid to this UNIX account to run the program
;redirect_stderr=true          ; redirect proc stderr to stdout (default false)
;stdout_logfile=/a/path        ; stdout log path, NONE for none; default AUTO
;stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
;stdout_logfile_backups=10     ; # of stdout logfile backups (default 10)
;stdout_capture_maxbytes=1MB   ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false   ; emit events on stdout writes (default false)
;stderr_logfile=/a/path        ; stderr log path, NONE for none; default AUTO
;stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups=10     ; # of stderr logfile backups (default 10)
;stderr_capture_maxbytes=1MB   ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false   ; emit events on stderr writes (default false)
;environment=A=1,B=2           ; process environment additions (def no adds)
;serverurl=AUTO                ; override serverurl computation (childutils)

; The below sample eventlistener section shows all possible
; eventlistener subsection values, create one or more 'real'
; eventlistener: sections to be able to handle event notifications
; sent by supervisor.

;[eventlistener:theeventlistenername]
;command=/bin/eventlistener    ; the program (relative uses PATH, can take args)
;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
;numprocs=1                    ; number of processes copies to start (def 1)
;events=EVENT                  ; event notif. types to subscribe to (req'd)
;buffer_size=10                ; event buffer queue size (default 10)
;directory=/tmp                ; directory to cwd to before exec (def no cwd)
;umask=022                     ; umask for process (default None)
;priority=-1                   ; the relative start priority (default -1)
;autostart=true                ; start at supervisord start (default: true)
;autorestart=unexpected        ; restart at unexpected quit (default: unexpected)
;startsecs=10                  ; number of secs prog must stay running (def. 1)
;startretries=3                ; max # of serial start failures (default 3)
;exitcodes=0,2                 ; 'expected' exit codes for process (default 0,2)
;stopsignal=QUIT               ; signal used to kill process (default TERM)
;stopwaitsecs=10               ; max num secs to wait b4 SIGKILL (default 10)
;user=chrism                   ; setuid to this UNIX account to run the program
;redirect_stderr=true          ; redirect proc stderr to stdout (default false)
;stdout_logfile=/a/path        ; stdout log path, NONE for none; default AUTO
;stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
;stdout_logfile_backups=10     ; # of stdout logfile backups (default 10)
;stdout_events_enabled=false   ; emit events on stdout writes (default false)
;stderr_logfile=/a/path        ; stderr log path, NONE for none; default AUTO
;stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups        ; # of stderr logfile backups (default 10)
;stderr_events_enabled=false   ; emit events on stderr writes (default false)
;environment=A=1,B=2           ; process environment additions
;serverurl=AUTO                ; override serverurl computation (childutils)

; The below sample group section shows all possible group values,
; create one or more 'real' group: sections to create "heterogeneous"
; process groups.

;[group:thegroupname]
;programs=progname1,progname2  ; each refers to 'x' in [program:x] definitions
;priority=999                  ; the relative start priority (default 999)

; The [include] section can just contain the "files" setting.  This
; setting can list multiple files (separated by whitespace or
; newlines).  It can also contain wildcards.  The filenames are
; interpreted as relative to this file.  Included files *cannot*
; include files themselves.

[include]
files = supervisord.d/*.ini
View Code

2、配置 vim /etc/supervisord.conf

uwsgi+Nginx+Django部署项目uwsgi+Nginx+Django部署项目
[supervisord]
http_port=/var/tmp/supervisor.sock ; (default is to run a UNIX domain socket server)
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB        ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10           ; (num of main logfile rotation backups;default 10)
loglevel=info                ; (logging level;default info; others: debug,warn)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=false               ; (start in foreground if true;default false)
minfds=1024                  ; (min. avail startup file descriptors;default 1024)
minprocs=200                 ; (min. avail process descriptors;default 200)
;http_port=127.0.0.1:9001    ; (alternately, ip_address:port specifies AF_INET)
;sockchmod=0700              ; AF_UNIX socketmode (AF_INET ignore, default 0700)
;sockchown=nobody.nogroup    ; AF_UNIX socket uid.gid owner (AF_INET ignores)
;umask=022                   ; (process file creation umask;default 022)
;user=chrism                 ; (default is current user, required if root)
;directory=/tmp              ; (default is not to cd during start)
;nocleanup=true              ; (don't clean up tempfiles at start;default false)
;childlogdir=/tmp            ; ('AUTO' child log dir, default $TEMP)
;environment=KEY=value       ; (key value pairs to add to environment)
;http_username=user          ; (default is no username (open system))
;http_password=123           ; (default is no password (open system))

[supervisorctl]
serverurl=unix:///var/run/supervisor/supervisor.sock ; use a unix:// URL  for a unix socket
;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
;username=chris              ; should be same as http_username if set
;password=123                ; should be same as http_password if set
;prompt=mysupervisor         ; cmd line prompt (default "supervisor")
;history_file=~/.sc_history  ; use readline history if available

; 下面的示例程序部分显示了所有可能的程序子部分值,创建了一个或多个"真实"程序:能够在supervisor下控制它们的部分。

[program:mysite]
command=/usr/local/bin/uwsgi /usr/local/django/mysite/uwsgi/uwsgi.ini ; 运行的程序 (相对使用PATH路径, 可以使用参数)
priority=999                 ; 程序运行的优先级(越小越优先)
autostart=true               ; supervisord启动时,该程序也启动
autorestart=true             ; 异常退出时,自动重启
startsecs=10                 ; 程序启动后持续10s后未发生异常,才表示启动成功
startretries=3               ; 异常后,自动重启次数
exitcodes=0,2                ; exit异常抛出的是0.2时才认为是异常
stopsignal=QUIT              ; 用于杀死进程的信号
stopwaitsecs=10              ; 向进程发出stopsignal后等待OS向supervisord返回SIGCHILD的时间,若超时则supervisord将使用SIGKILL杀进程 
user=root                    ; 设置启动该程序的账号为chrism
log_stdout=true              ; 如果为True,则记录程序日志
log_stderr=false             ; 如果为True,则记录程序错误日志
logfile=/var/log/cat.log     ; 程序日志路径
logfile_maxbytes=1MB         ; 日志文件最大大小
logfile_backups=10           ; 日志文件最大数量
View Code

3、启动

supervisord -c /etc/supervisord.conf