ubuntu+django+uwsgi+nginx前后端分离部署完整版

1.部署之前确定你已经将你的项目上传到你的服务器当中。在我之前的文章已经提到,本文默认项目已经运行成功,并且django项目中允许所有地址进行访问。下面也有我之前的部署,其实按照下面做到虚拟环境能够运行django就可以继续向下读了。

2. 将uwsgi安装到你的virtualenv中,初步设定项目名字为induapp,项目存放在/home/ubuntu/induapp

pip install uwsgi

基础测试(这也是uwsgi文档直接就有的)

创建一个test.py文件

# test.py
def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"] # python3

运行uwsgi:

uwsgi --http :8000 --wsgi-file test.py

如果云主机能够直接外网访问的话

在浏览器访问 http://公网IP:8000即可,会提供一个“hello world”消息

如果云主机禁止外网访问

curl 127.0.0.1:8000

也能看到效果

这样意味下面的组建已经正常,不需要重复验证

web client <-> uWSGI <-> python

3.uwsgi测试运行django项目

uwsgi --http :8000 --module induapp.wsgi

module induapp.wsgi:加载指定的wsgi模块

跟上面相同的做法来验证是否能够访问到django项目,这样意味下面的组建已经正常,不需要重复验证

web client<->uWSGI<->Django

4.基本的nginx

安装nginx

sudo apt-get install nginx
sudo /etc/init.d/nginx start

同上我们能够在浏览器访问80端口或者curl访问80端口

如果会报错的话,这里建议两个比较快的命令

vim /var/log/nginx/error.log

或者

sudo nginx -t

如果正常运行,意味着

web client<->the web server

其实默认的80端口很容易会被占用,并且你想要在哪里使用nginx,那么你将必须重新配置nginx来提供另一个端口的服务,所以我们选择8080来当作后台的端口,8001来当作前台的端口。

4.为站点配置nginx

首先我们需要uwsgi_params文件,可用在uwsgi发行版本的nginx目录下,或者下面的连接就有,直接复制到induapp项目根目录中,不需要进行修改。

现在就可以在项目induapp根目录下面创建induapp_nginx.conf的文件,然后编写下面文件。

# 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:8000; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on
    listen      8080;
    # the domain name it will serve for
    server_name 127.0.0.1; # 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 /home/ubuntu/induapp/media;  # your Django project's media files - amend as required
    }

    location /static {
        alias /home/ubuntu/induapp/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     /home/ubuntu/induapp/uwsgi_params; # the uwsgi_params file you installed
    }
}

将这个文件链接到/etc/nginx/sites-enabled,这样nginx就可以看到它了:
sudo ln -s ~/induapp/induapp_nginx.conf /etc/nginx/sites-enabled/

5.基本nginx测试

sudo /etc/init.d/nginx restart

让nginx来测试test.py

我们可以查看端口号占用情况并杀掉进程

netstat -apn|grep 8000
kill -9 <pid>
uwsgi --socket :8000 --wsgi-file test.py

显然可以看出,已经配置了nginx在8000端口与uWSGI通信,而对外使用8080端口,访问8080端口来进行检查。

6.使用Unix socket而不是端口

使用Unix socket会比端口更好,开销更少。

编写induapp_nginx.conf,修改它来匹配:

upstream django {
    server unix:///home/ubuntu/induapp/induapp.sock; # for a file socket
    # server 127.0.0.1:8000; # for a web port socket (we'll use this first)
}

然后重启nginx

sudo /etc/init.d/nginx restart

再次运行uwsgi

uwsgi --socket mysite.sock --wsgi-file test.py

这次,socket会告诉uwsgi使用哪个文件

在浏览器或者curl尝试访问8080端口

如果那不行

检查nginx错误日志(/var/log/nginx/error.log)。如果你看到像这样的信息:

connect() to unix:///path/to/your/mysite/mysite.sock failed (13: Permission denied)

那么可能你需要管理这个socket上的权限,从而允许nginx使用它。

尝试:

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日志的输出在终端窗口中滚动,这样,在解决问题的时候,你就可以容易的参考它们了。

6.使用uwsgi和nginx运行django应用

运行我们的Django应用

uwsgi --socket mysite.sock --module mysite.wsgi --chmod-socket=664

现在,uWSGI和nginx应该不仅仅可以为一个”Hello World”模块服务,还可以为你的Django项目服务。

在induapp项目中配置induapp_uwsgi.ini文件

[uwsgi]
project = induapp
base = /home/ubuntu
socket = 127.0.0.1:8000

chdir = %(base)/%(project)
home = %(base)/anaconda3/envs/djangoEnv
module = %(project).wsgi

master = true
processes = 10

socket = %(base)/%(project)/%(project).sock
chmod-socket = 666
vacuum = true

pythonpath = /home/ubuntu/anaconda3/envs/djangoEnv/lib/python3.6/site-packages

值得注意的是要是没有最后一行的pythonpath很可能在初始化uwsgi应用的时候出现 no moudle named xxx的错误。

chdir是项目路径,home是虚拟环境路径。

使用这个文件运行

uwsgi --ini induapp_uwsgi.ini # the --ini option is used to specify a file

打印出来的结果能够预测Django站点是否预期工作

7.系统安装uwsgi

停用虚拟环境

source deactivate

然后在系统中安装uWSGI:

sudo pip install uwsgi

再次检查是否能运行

uwsgi --ini induapp_uwsgi.ini

Emperor模式

# 系统启动时运行uWSGI
# 最后一步是让这一切在系统启动的时候自动发生。
# 对于许多系统来说,最简单 (如果不是最好的)的方式是使用 rc.local 文件。
# 编辑 /etc/rc.local 然后在”exit 0”行前添加:
/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid ubuntu --gid ubuntu --daemonize /var/log/uwsgi-emperor.log

选项表示:

  • emperor: 查找vassals (配置文件)的地方
  • uid: 进程一旦启动后的用户id
  • gid: 进程一旦启动后的组id

文档中的用户是www-data,

/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data --daemonize /var/log/uwsgi-emperor.log

但常常因为权限不够高,访问时候会出现502的错误,所以我们这里直接使用Ubuntu来提高我们的权限。

7.完成前台的部署

将前台的静态文件打包到一个文件夹上传到服务器中,我们这里是/home/ubuntu/knowGraph

我们在项目根目录创建induapp_web_nginx.conf文件并进行编写。

server {
        listen       8001;
        server_name  127.0.0.1;

        location / {
            root /home/ubuntu/knowledgeGraph;
            index index.html;
        }
        location /neo4j {
            proxy_pass http://127.0.0.1:8080;
            proxy_send_timeout 1800;
            proxy_read_timeout 1800;
            proxy_connect_timeout 1800;
            client_max_body_size 2048m;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header  Host              $http_host;   # required for docker client's sake
            proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
            proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
            proxy_set_header  X-Forwarded-Proto $scheme;
        }
        location /admin {
            proxy_pass http://127.0.0.1:8080;
            proxy_send_timeout 1800;
            proxy_read_timeout 1800;
            proxy_connect_timeout 1800;
            client_max_body_size 2048m;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header  Host              $http_host;
            proxy_set_header  X-Real-IP         $remote_addr;
            proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
            proxy_set_header  X-Forwarded-Proto $scheme;

        }
}

下面就是对这个文件的解析

该文件监听的是8001端口,location / 对应的是前端静态文件的初始化界面。/neo4j和/admin对应的是django的url。基本上格式可以不做修改,我们值得注意的是proxy_pass http://127.0.0.1:8080(也就是刚刚我们后台运行在nginx的端口。)注意的是http://127.0.0.1:8080后面不应该带/号,不然访问127.0.0.1:8001/neo4就会变成访问127.0.0.1:8080,跟我们想要的结果不同。

将这个文件链接到/etc/nginx/sites-enabled,这样nginx就可以看到它了: sudo ln -s ~/induapp/induapp_web_nginx.conf /etc/nginx/sites-enabled/

最后的最后,重启服务

sudo /etc/init.d/nginx restart
uwsgi --ini induapp_uwsgi.ini -d /home/induapp/induapp.log

nginx+uwsgi启动Django项目

1.安装项目环境

  • 系统环境:ubuntu16.04
  • python环境:python3.5.2
  • Django版本:django1.11.7
  • nginx环境:nginx_1.10.3
  • 虚拟环境:virtualenv15.1.0
  • uwsgi版本:uwsgi2.0.17.1

安装并进入项目虚拟环境:

sudo apt-get install virtualenv
virtualenv -p python3 env_my_project 
source env_my_project/bin/activate
pip install -r requirements.txt 

2.项目配置及运行测试

修改项目配置文件:
cp my_project/settings_local.py.example my_project/settings_local.py

修改es配置文件:
cp rs_es/es_settings.py.example rs_es/es_settings.py

wsgi.py:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_project.settings_local")
application = get_wsgi_application()

项目运行测试:
python manage.py collectstatic  # 收集静态文件
python manage.py makemigrations
python manage.py migrate
python manage.py runserver 0.0.0.0:8001

未分类

3.NGINX和UWSGI相关配置

sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/my_project
sudo ln -s /etc/nginx/sites-available/my_project /etc/nginx/sites-enabled/
sudo vim /etc/nginx/sites-enabled/my_project

nginx配置:
upstream my_project{
    server unix:///var/run/my_project.sock;
}

server {
    listen      8001;  //服务的端口号   服务通过nginx与uwsgi通信来启动

    server_name 192.168.xx.xx;  //nginx代理的ip  
    charset     utf-8;

    # max upload size
    client_max_body_size 10M;

    # send all non-media requests to the Django server.
    location / {
        uwsgi_pass  my_project;
        include     /etc/nginx/uwsgi_params;
    }

    location /static/ {
        root /home/ubuntu/my_project;
    }
}

Uwsgi配置:
sudo mkdir /var/log/uwsgi
sudo chmod -R 777 /var/log/uwsgi

uwsgi.ini:
[uwsgi]
chdir=/home/ubuntu/my_project
home=/home/ubuntu/my_project/env_my_project
module=my_project.wsgi:application

socket=/var/run/my_project.sock
chmod-socket = 666

master=True
processes = 5
max-requests=5000

# clear environment on exit
vacuum=True

pidfile=/var/run/my_project.pid
daemonize=/var/log/uwsgi/my_project.log

# git pull 自动重启服务
touch-reload=.git/index

4.配置Emperor mode监听和系统自动启动uwsgi

配置Emperor mode监听
sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals
sudo ln -s /home/ubuntu/my_project/uwsgi.ini /etc/uwsgi/vassals/

系统自动启动uwsgi
sudo vim /etc/rc.local
/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals

5.通过uwsgi启动django服务

启动uwsgi
uwsgi --ini uwsgi.ini

重启nginx
sudo service nginx restart

启动django服务
sudo uwsgi --reload /var/run/my_project.pid

此时在浏览器通过ngnix代理出来的ip和端口即可访问服务

Django+uwsgi+nginx+angular.js项目

这次部署的前后端分离的项目:

前端采用angular.js,后端采用Django(restframework),他俩之间主要以json数据作为交互

Django+uwsgi的配置可以参考我之前的博客:http://www.cnblogs.com/52-qq/p/8873328.html

这篇博客里面都是静态页面,而不是采用restapi的形式,不过都是类似的,配置完之后采用uwsgi启动Django项目

前端:吧前端所有的代码拷贝在Django项目根路径下(也可以不用,当然我这么说是为了方便),

然后直接在nginx中配置,就可以了(不过前端框架也需要启动)

未分类

这段代码的配置才是比较重要的,类似的vue项目的部署也都类似

docker compose实战部署django

第一步,因为应用将要运行在一个满足所有环境依赖的 Docker 容器里面,那么我们可以通过编辑 Dockerfile 文件来指定 Docker 容器要安装内容。内容如下:

FROM python:3

ENV PYTHONUNBUFFERED 1

RUN mkdir /code

WORKDIR /code

ADD requirements.txt /code/

RUN pip install -r requirements.txt

ADD . /code/

第二步,在 requirements.txt 文件里面写明需要安装的具体依赖包名。

Django>=1.8,<2.0

psycopg2

第三步, docker-compose.yml 文件将把所有的东西关联起来。它描述了应用的构成(一个web 服务和一个数据库)、使用的 Docker 镜像、镜像之间的连接、挂载到容器的卷,以及服务开放的端口。

version: "3"

services:

    db:

        image: postgres

    web:

        build: .

        command: python3 manage.py runserver 0.0.0.0:8000

        volumes:

            – .:/code

        ports:

            – "8000:8000"

        links:

            – db

现在我们就可以使用 docker-compose run 命令启动一个 Django 应用了。

$ docker-compose run web django-admin.py startproject django_example .

Compose 会先使用 Dockerfile 为 web 服务创建一个镜像,接着使用这个镜像在容器里运行django-admin.py startproject composeexample 指令。这将在当前目录生成一个 Django 应用。

$ ls

Dockerfile docker-compose.yml django_example manage.py requ

irements.txt

如果你的系统是 Linux,记得更改文件权限。

sudo chown -R $USER:$USER .

首先,我们要为应用设置好数据库的连接信息。用以下内容替换 django_example/settings.py文件中 DATABASES = … 定义的节点内容。

DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.postgresql',

         'NAME': 'postgres',

         'USER': 'postgres',

         'HOST': 'db',

         'PORT': 5432,

    }

}

这些信息是在 postgres 镜像固定设置好的。然后,运行 docker-compose up :

$ docker-compose up

django_db_1 is up-to-date

Creating django_web_1 …

Creating django_web_1 … done

Attaching to django_db_1, django_web_1

db_1 | The files belonging to this database system will be owned by user "postgres".

db_1 | This user must also own the server process.

db_1 |

db_1 | The database cluster will be initialized with locale "en_US.utf8".

db_1 | The default database encoding has accordingly been set to "UTF8".

db_1 | The default text search configuration will be set to "english".

web_1 | Performing system checks…

web_1 |

web_1 | System check identified no issues (0 silenced).

web_1 |

web_1 | November 23, 2017 – 06:21:19

web_1 | Django version 1.11.7, using settings 'django_example.settings'

web_1 | Starting development server at http://0.0.0.0:8000/

web_1 | Quit the server with CONTROL-C.

这个 Django 应用已经开始在你的 Docker 守护进程里监听着 8000 端口了。打开127.0.0.1:8000 即可看到 Django 欢迎页面。

你还可以在 Docker 上运行其它的管理命令,例如对于同步数据库结构这种事,在运行完docker-compose up 后,在另外一个终端进入文件夹运行以下命令即可:

$ docker-compose run web python manage.py syncdb

Django+Linux+Uwsgi+Nginx项目部署文档

WSGI

在生产环境中使用WSGI作为python web的服务器

WSGI:全拼为Python Web服务器网关接口,Python Web服务器网关接口,是项目默认会生成一个wsgi.py文件,确定了设置模块,uWSGI实现了WSGI的所有接口,是一个快速,自我修复,开发人员和系统管理员友好的服务器,C语言编写,效率高

Nginx

使用nginx的的作用主要包括负载均衡,反向代理

项目通过Django+Uwsgi+Nginx进行线上服务器部署

1、文件打包传服务器,通过xshell

文件 > 传输 > ZMODEM > 用ZMODEM发送 > 文件或压缩包

Linux下压缩包解压命令:

zip格式 : unzip 压缩包路径

tar.gz格式 : tar zxvf 压缩包路径

(rar格式压缩包解压较为复杂,尽量别传rar格式)

2、Xshell使用技巧

文件 > 新建,开启多终端

建议开多终端,这样对uwsgi、Nginx、项目代码进行调试修改时,可以避免在一个终端下来回切换目录,提高工作效率,具体开终端的个数根据实际需求来定,并且右击tab终端名重命名,更加方便知道哪个终端对应做哪些事情
未分类

3、修改配置文件问题

不管修改uwsgi的配置文件uwsgi.ini还是修改nginx配置文件nginx.conf,修改完都必须重启服务才能生效,并且启动服务要在指定的目录下面重启

4、Uwsgi的安装

方法1、pip install uwsgi(有网的情况下)

方法2、没网情况下去官网下载uwsgi压缩包,为tar.gz格式,传到服务器,进行解压,解压路径/lib/目录下面,然后切换到uwsgi文件目录,执行以下两个命令,即可完成安装,示意图如下(解压路径可以自定义,记下来,方便以后进行维护)

python setup.py  build

python setup.py  install

未分类

5、Django项目中配置uwsgi

1、项目目录(例如本例中DataBusines)下创建uwsgi.ini文件,配置如下

本地测试一般用:127.0.0.1即可,端口可以自定
未分类

线上的话用线上服务器IP,端口自定,该配置访问地址需要和nginx.conf中的配置一样
未分类
例如:这是后面的nginx.conf配置文件,两者地址和端口需要一致
未分类

6、Uwsgi的使用(启动、查看进程、关闭)

启动uwsgi.ini,需要切换到项目目录

启动uwsgi: uwsgi –ini uwsgi.ini

查看uwsgi进程:ps ajx|grep uwsgi

关闭uwsgi:

查阅相关资料文档,提到多种命令关闭方式,关闭命令的意义在于修改配置文件后,

一般需要重启uwsgi才会生效

1、uwsgi –stop uwsgi.pid(不好用,经常报pid找不到)

2、sudo pkill -f uwsgi -9(不好用,有可能报错,无效的-9)

3、killall -9 uwsgi(该命令最好用)
未分类

7、通过uwsgi网页访问

因为uwsgi本身就是web服务器,我们可以通过更改配置直接通过uwsgi进行访问网页

如下图:我们在服务器通过vi更改配置文件为http请求模式,更改后保存并重启uwsgi服务器,在我们自己的浏览器访问设置的IP和端口,成功显示页面,证明uwsgi配置成功

http模式: 直接用uwsgi时使用

socket模式: 使用Nginx时使用
未分类
未分类

8、Nginx的安装

方法1、pip install nginx(官方提供有该方法,但是之前在本地测试遇到坑,没有配好,建议通过方法二中压缩包方式安装)

方法2、没网情况下去官网下载nginx压缩包,为tar.gz格式,传到服务器,进行解压,解压路径/lib/目录下面,然后切换到nginx文件目录,执行以下三个命令,进行安装

./configure

make

sudo make install

未分类
执行完以上命令后,nginx被安装在了/usr/local/nginx/,安装成功
未分类

9、nginx的使用(启动、查看进程、关闭)

进入nginx安装目录:cd /usr/local/nginx/

启动nginx: sudo sbin/nginx

查看nginx进程: ps ajx|grep nginx

关闭uwsgi:

查阅相关资料文档,提到多种命令关闭方式,关闭命令的意义在于修改配置文件后,一般需要重启nginx才会生效

1、sudo sbin/nginx –s stop(不好用,报异常无效的-s)

2、sudo pkill -f uwsgi -9(不好用,报错,无效的-9)

3、killall -9 nginx(该命令最好用)

命令报错示意
未分类

10、nginx的配置文件nginx.conf配置

具体如图中所示,配置文件目录/usr/local/nginx/conf/nginx.conf,配置文件的修改需要通过vi进行修改
未分类
未分类

11、静态资源配置

配置静态资源目录是因为让静态资源通过nginx可以直接返回,不需要通过uwsgi,也就是让uwsgi只处理后端逻辑,不处理静态资源,优化性能

1、静态资源在nginx.conf中的配置,路径可以自定义
未分类
2、在服务器上创建如下目录

sudomkdir –vp /var/www/DataBusines/static/

3、修改目录权限

sudochmod 777 /var/www/DataBusiness/static/

4、项目代码中配置settings,加入该目录(本地演示在IDE中,线上可以用vi)
未分类

5、收集所有静态文件到static_root指定目录

服务器上切换到项目目录(DataBusines),执行如下命令收集

python  manage.py collectstatic

6、查看静态资源目录
未分类

12、更改uwsgi.ini配置

刚才在做uwsgi时候,用了http配置,现在nginx正式搭建起来,需要改成socket配置,修改完毕要重启uwsgi
未分类
Settings.py需要debug设置为不调试,允许访问的地址设置为服务器地址
未分类
以上步骤完成后,访问服务器主机地址和端口,如果nginx.conf中配置的为80端口,则地址栏不需要输入端口,因为浏览器请求端口也是默认为80端口,非80端口的需要自己在ip后面添加
未分类

部署 Django 项目背后的原理:为什么需要 Nginx 和 Gunicron这些东西?

相信用过 Django 的同学一定会被 “Very easy to setup” 惊艳到。只要一行命令,就可以在 admin 界面看到一个完整的登陆注册。但是到了部署的时候,你一定会被网上复杂的部署教程搞的头晕,为啥本地开发这么简单,到了服务器却需要又是 Nginx,又是 uWSGI 这种东西呢?

未分类
摘自The Full Stack Python Guide to Deployments 一书

本文试图解释这些程序在一个 Web 服务中扮演的角色,为什么部署 Python web程序需要它们。本文不介绍如何部署 Django 应用等,这一类教程网上有很多,读者可自行搜索。其中 Nginx 和 Apache 算是一类的,可以替换。Gunicorn 和 uWSGI 的角色是类似的。同理最后端的 Web 框架是一类的,比如 Django 和 Flask。本文的内容替换以上任意一个应该也适用。

如果你读了网上任意一篇教程,你应该知道一个完整的部署应该类似这样:

HTTP Server <-----> WSGI <-----> App

最后后面的 App 我们知道,只要 runserver 就可以访问了,但是 Django 的文档明确说明:

DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through security audits or performance tests. (And that’s how it’s gonna stay. We’re in the business of making Web frameworks, not Web servers, so improving this server to be able to handle a production environment is outside the scope of Django.)

即 Django 做的事情只是一个框架,不会去关心一些安全问题、HTTP 的性能问题等。所以我们需要一个专业的 HTTP 服务器。这就出现了 Nginx 或 Apache。那么如何将 HTTP 服务器和我们的应用连接起来呢?动态网站问世的时候,就出现了 CGI 协议。注意这是一个协议,定义了HTTP 服务器如何通过后端的应用获取动态内容。可以简单的理解成 HTTP 服务器通过CGI 协议调用后端应用吧!WSGI 可以理解成 Python 的 CGI。uWSGI 和 Gunicorn 是这种 WSGI 的一些实现。这样,就出现了上面提到的三层的部署。

但是,为什么我们还需要 Nginx 呢?这些 WSGI 程序本身不是也提供访问吗?

uWSGI 和 Gunicorn 本身就是一个便携的 web 服务器了,Nginx 作为一个经过更长时间验证的 HTTP 服务器来说,它有很多 uWSGI 没有支持的 feature。比如:

  1. 处理静态资源更加优秀,E-Tag 的设置,Gzip 压缩等
  2. 处理网络连接,降低网络负载。例如 reuqest_buffering ,加入部署一个 uWSGI 程序,如果有慢的请求存在,uWSGI 必须等待整个 HTTP 请求发过来之后才开始处理请求。但是如果前置 Nginx,那么 Nginx 会帮你收到整个 HTTP 请求之后才交给 uWSGI 处理,也就是说,uWSGI获得的永远会是完整的 HTTP 请求,不会占用一个线程在等待。
  3. 甚至缓存动态的内容,例如将博客的首页缓存 5 分钟
  4. 作为一个负载均衡的前置,这样每一层的实例数量可以横向扩展
  5. Nginx 本身是作为一个服务存在的,几乎在任何 Linux 版本上安装之后都可以用 initd 启动,就像 MySQL 那样。uWSGI 一般是需要自己将其配置成服务的。(虽然前置了 Nginx 依然是需要配置 uWSGI)
  6. ……

此外,这样分开的好处还是得,到达 uWSGI 和 Gunicorn 的请求的情况变得简单了很多,Nginx 处理了一层,将过滤和处理之后的请求交给 uWSGI 或 Gunicorn。这使得这些 WSGI 程序的实现简单了一些,简化了开发的工作。专业的事情交给专业的人去做。

当然,并不是所有的项目都需要这么复杂的部署,有一个可选的是将 WSGI 程序嫁接到 HTTP 服务器上,比如 Apache httpd + mod_wsgi, Nginx + mod_uwsgi 等。

Django+Ngnix+Gunicorn+Mysql部署Centos的坑

环境配置

  • Centos 7
  • Python 3.6.5
  • Virtualenvwrapper 4.8.2
  • Django 2.0.5
  • Mysql 5.7.22
  • Ngnix 1.12.2
  • Gunicorn 19.8.1

注:这并不是什么教程

python虚拟环境配置

Virtualenvwrapper安装失败

试试这条命令 :-p

sudo pip install virtualenvwrapper --upgrade --ignore-installed six

简答解释就是包six版本有点低,详细解释点此

找不到virtualenvwrapper.sh文件

按照官方文档上说是安在 /usr/local/bin/virtualenvwrapper.sh,但是并没有,每个系统的情况不一样,使用如下命令

pip uninstall virtualenvwrapper

不用担心,这并不会立刻移除virtualenvwrapper,会输出以下内容,再输入n取消安装

Uninstalling virtualenvwrapper-4.8.2:
  /usr/bin/virtualenvwrapper.sh
  /usr/bin/virtualenvwrapper_lazy.sh
  /usr/lib/python2.7/site-packages/virtualenvwrapper-4.8.2-py2.7-nspkg.pth
  /usr/lib/python2.7/site-packages/virtualenvwrapper-4.8.2.dist-info/DESCRIPTION.rst
  /usr/lib/python2.7/site-packages/virtualenvwrapper-4.8.2.dist-info/INSTALLER
  /usr/lib/python2.7/site-packages/virtualenvwrapper-4.8.2.dist-info/METADATA
  ......
  Proceed (y/n)?

看第一行,这下知道在哪里的吧,对于我的centos7来说是在 /usr/bin/virtualenvwrapper.sh 下

具体见此https://stackoverflow.com/questions/12647266/where-is-virtualenvwrapper-sh-after-pip-install/41676706#41676706

Mysql配置

安装教程https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-centos-7 ,比较靠谱

中文乱码

问题可能出现在两个地方,一个是Django的配置文件中,还有一个就是Mysql的配置出问题

Django数据配置

找到project的settings.py,修改这两个地方,注意,对于较新版本的django,把zh-cn改成了zh-Hans

LANGUAGE_CODE = 'zh-Hans'

TIME_ZONE = 'Asia/Shanghai'

Mysql数据配置

先登录到你的mysql中,执行如下命令

SHOW VARIABLES LIKE 'character_set_%';

发现大多数行的值都不是utf-8,而是latin1

那么,找到mysql的配置文件my.cnf

对于 MySQL 5.7+,执行以下命令,别的情况见此

mysqladmin --help | grep 'Default options' -A 2

输出的第二行就是文件的所在

Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf

打开此文件 /etc/my.cnf

添加如下内容如下,别的地方别修改

[mysqld]
collation-server = utf8_unicode_ci
init-connect='SET NAMES utf8'
character-set-server = utf8

...

[mysql]
default-character-set=utf8

改完之后记得重启mysql服务

sudo systemctl restart mysqld

gunicorn找不到 django.core.xxx

找到gunicorn的所在地

which gunicorn

应为是在python虚拟环境下安装的,所以一般在//.virtualenvs//bin/gunicorn,如果不是这样的话终极解决方案是把要输入 gunicorn 的地方全改成 //.virtualenvs//bin/gunicorn

Django 静态文件404

在production模式下Django并不支持静态文件的处理,这一切都要交给一个服务器处理,比如此处的Nginx,千万要记住!!!!!!

Nginx无法正常启动

(ps1:centos7安装Nginx的教程见此,比较靠谱)

(ps2:默认相关防火墙已开启)

在输入

sudo systemctl start nginx
sudo systemctl status nginx

发现其启动失败,则多半是你配置文件写错的结果,输入一下命令排错

sudo nginx -t

修改完之后记得刷新哦

sudo service nginx restart
#或者
sudo service nginx reload

在阿里云上Ubuntu环境通过nginx+uwsgi部署Django项目

年前阿里云打折,1核1G的云服务器一年只要300多块,果断就租了1年的。既然服务器已经到手,怎么能不把自己写的项目部署上去呢,其实网上关于nginx+uwsgi部署Django项目的文章有很多,但是这些文章要不就是很久之前的,要不就是互相抄袭,一路过来都是坑,这里重点吧在部署时候遇到的坑着重介绍一下:

1. 首先部署django项目

首先是django项目,由于我是使用Anaconda来进行版本控制的,而django项目是在Python2.7环境下开发的,首先是新建一个Python2.7的环境:

#创建python27环境
conda create --name python27 python=2.7
#激活该环境
source activate python27
#通过conda安装django
conda install django

环境准备好后,从GitHub上将项目拉取下来

git clone https://github.com/sunny0826/xxx

修改setting.py文件

#debug模式默认开启,这里要关闭
DEBUG = False
#这里将外网IP配置进来
ALLOWED_HOSTS = ['127.0.0.1','xx.xx.xx.xx']

启动项目:

#来项目目录下执行
python manage.py runserver 8000

然后在外网ip:8000路径下查看项目启动情况

2. 阿里云配置安全组

由于是服务器在阿里云上,所以直接访问时访问不到的,所以要在阿里云平台配置安全组(类似于防火墙)

首先打开阿里云平台,登录,点击安全组配置:

未分类

点击配置规则

未分类

点击添加安全组规则

未分类

按要求填写安全组规则

未分类

优先级1位最高优先级,端口可以设置范围,并且可以设置授权访问的对象
设置完之后,就可以在公网IP访问到我们的django项目了

3. 安装配置uwsgi

确定django项目可以正常运行了,ctrl+c停止项目,下面我们来安装uwsgi:
在安装uwsgi非常简单,只需要pip安装即可,但是由于之前使用的是Python27环境,这里记得要激活Python27环境,否则就安装到默认的Python路径了

#uWSGI 是一个(巨大的) C 应用,所以你需要一个 C 编译器(比如 gcc 或者 clang)和 Python 开发版头文件
apt-get install build-essential python-dev
#安装uwsgi
pip install uwsgi

按照官网介绍,写已经Python脚本进行测试,test.py(在任意路径都可以,不过测完要记得删掉)

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

然后输入命令进行测试

uwsgi --http :8000 --wsgi-file test.py

这里是8000端口,因为之前测试django的时候打开的8000端口,这里偷懒就不去配置新的安全组了
那么问题就来了,在启动的时候报错了….=。=

未分类

出现的这个错误,经过测试只会在Python2.7的环境发生,在Python3+就没有发生了,辗转百度和Google,都没有找到这个问题的解决办法且这个问题一般发生在nginx上…
但这个报错问题还是很明显,就是libpcre.so.1这个文件找不到,初步推测为版本问题
首先要咱们搜索一下这个文件,看看本机有没有

未分类

发现本机是有这个文件的,那就好办了,将他链接到相应位置就好

未分类

执行这条语句之后就可以uwsgi就可以正常启动了

在跳过这个坑之后,就可以正式来配置我们的项目了
首先修改自己项目中的wsgi.py文件,添加两行代码

未分类

然后在django项目根目录创建uwsgi.ini文件

uwsgi.ini文件配置

# uwsgi.ini file
[uwsgi]

# Django-related settings

socket = 127.0.0.1:8000            #与nginx通信的地址和端口

# the base directory (full path)
chdir           = /apps/xxxx        #django项目绝对路径

# Django s wsgi file
module          = xxxx.wsgi    #wsgi文件所在的相对于项目的路径

# the virtualenv (full path)
home            =  /root/anaconda3/envs/python27/lib/python2.7/site-packages        #python环境的路径

# process-related settings
# master
master          = true

# maximum number of worker processes
processes       = 4

# ... with appropriate permissions - may be needed
# chmod-socket    = 664
# clear environment on exit
vacuum          = true

plugins=python
#log文件
daemonize=/apps/uwsgi/uwsgi.log
#pid文件
pidfile=/apps/uwsgi/uwsgi.pid

这里配置日志文件和pid文件,方便之后的重启

关于uwsgi的重启问题:

每次项目有代码更新的话,都需要重启uwsgi,如果没有配置pid文件的话,重启需要使用:

#查看uwsgi进程号
ps aux | grep uwsgi
#关闭进程号为0的进程
kill -9 主进程号

未分类

来停止uwsgi,然后才能重启,注意这里的主进程是pid为1的进程,而配置了pid文件的,只需要进行如下方法来重启即可

#重载(一般修改参数,或者修改py文件经常用到)
uwsgi --reload uwsgi.pid
#重启(一般系统环境变化会用到)
uwsgi --stop uwsgi.pid

最后在项目根目录下运行uwsgi命令,载入配置文件

uwsgi --ini uwsgi.ini

然后在后面的日志中要注意环境是否为之前配置,如果不是请激活激活之前创建的Python环境再进行操作

4. 安装配置nginx

最后来安装nginx

sudo apt-get install nginx

修改nginx配置

cd /etc/nginx/sites-enabled    #Ubuntu中nginx配置文件所在路径
vim default

配置文件

server {
        listen 80 default_server;            #监听端口,将来访问的端口
        listen [::]:80 default_server;

        root /var/www/html;

        # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html;


        server_name _;

        location / {
                include uwsgi_params;
                uwsgi_pass 127.0.0.1:8000;    #uwsgi中配置的路径
        }

        location /static {
                alias /apps/xxx/static;       #静态资源路径
        }

        location /resume.ico  {
                alias /apps/xxx/static/resume.ico;    #网页图标路径
        }
}

uwsgi启动后,再启动nginx

基础命令

/etc/init.d/nginx start  #启动
/etc/init.d/nginx stop  #关闭
/etc/init.d/nginx restart  #重启

启动之后,访问外网IP:80,查看是否可以通过nginx访问django

nginx+uwsgi在centos上部署Django应用

背景介绍:

之前做完一个Django项目,打算部署在自己的centos服务器上,可以远程访问,于是命令行上输入

python manage.py runserver 0:8000

就成功运行了,可惜,django自带的web服务器并不稳定,经常无缘无故断掉,于是想到

使用主流的uwsgi+nginx来部署项目,

至于Nginx+uWSGI+Django原理可参考http://www.cnblogs.com/Xjng/p/aa4dd23918359c6414d54e4b972e9081.html

此处就不赘述了,下面介绍下具体部署步骤

1. 安装uwsgi

pip install uwsgi

此时可以尝试使用uwsgi来启动应用,其中wsgi.py在mysite文件夹下

uwsgi --http :8000 --module mysite.wsgi

在浏览其中输入127.0.0.1:8080 能够成功访问,说明你的应用服务器部署成功,已经可以对外提供服务。

2. 安装nginx

yum install nginx

在/etc/nginx/conf.d文件夹下新建nginx启动的配置文件mysite.conf,输入以下信息

server {
  listen 8000;  #启动的nginx进程监听请求的端口
  server_name localhost;   #域名
  location / {
    include /etc/nginx/uwsgi_params;
    uwsgi_pass 127.0.0.1:8001;  #对于动态请求,转发到本机的8001端口,也就是uwsgi监听的端口
  }

  location /static/ {
    alias /home/Maximum/vacancy/static/;    #设定静态文件所在目录
  }
}

3. 同步静态文件到nginx设置的目录下

在django项目setting.py中增加

BASE_DIR = os.path.dirname(__file__)
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR,'..','vacancy','static')
然后在命令行行下执行

python manage.py collectstatic

4. 配置uwsgi

项目根目录下创建uwsgi.ini文件

vi uwsgi.ini
uwsgi.ini内容

[uwsgi]
# Django's wsgi file
module = mysite.wsgi
pythonpath = /usr/local/lib/python3.5/site-packages
socket = 127.0.0.1:8001
pidfile = /home/Maximum/uwsgi.pid    
daemonize = /home/Maximum/uwsgi.log

介绍下uwsgi和nginx相关命令

启动uwsgi:uwsgi --ini uwsgi.ini
停止uwsgi:uwsgi --stop uwsgi.pid
重新加载配置:uwsgi --reload uwsgi.pid
启动nginx:service nginx start
停止nginx:service nginx stop
重启nginx:service nginx restart

接下来启动uwsgi:

uwsgi --ini uwsgi.ini

启动nginx

service nginx start

此时没问题的话就大功告成了,访问173.199.118.8:8000/vacancies即可看到我们运行的项目了

遇到的坑

1、启动nginx时出现以下错误,可知端口已被占用

[gaarai@linode /etc/nginx]$ service nginx restart
 * Restarting nginx nginx
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:443 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)

解决方法:

netstat -ntpl

查看当前运行的端口以及程序,内容类似如下:

[root@vultr mysite]# netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1502/nginx: master
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      461/sshd
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      677/master
tcp        0      0 0.0.0.0:8000            0.0.0.0:*               LISTEN      1502/nginx: master
tcp        0      0 127.0.0.1:8001          0.0.0.0:*               LISTEN      1475/uwsgi
tcp6       0      0 :::3306                 :::*                    LIS

将使用进程端口80,8000,8001的进程PID关闭,uwsgi的进程需要强制关闭

[root@vultr mysite]# kill -9 1475
[root@vultr mysite]# kill 1502

重新启动uwsgi和nginx

[root@vultr mysite]# uwsgi --ini uwsgi.ini
[root@vultr mysite]# service nginx start

2、访问网站出现Internal Server Error错误

查看uwsgi.log日志文件

tail -30 uwsgi.log

日志里出现

unable to load app 0 (mountpoint='') (callable not found or import error)

错误,

尝试执行

uwsgi --http :8000 --module mysite.wsgi

访问173.199.118.8:8000/vacancies运行正常,可知是uwsgi.ini配置文件有误

参考链接Setting up django with uwsgi and nginx

解决办法:

修改uwsgi.ini文件为

[uwsgi]
# Django's wsgi file
module = mysite.wsgi
pythonpath = /usr/local/lib/python3.5/site-packages
socket = 127.0.0.1:8001
pidfile = /home/Maximum/uwsgi.pid    
daemonize = /home/Maximum/uwsgi.log

之前有一些不太懂的设置加了上去,运行错误,去掉之后重启uwsgi和nginx服务即运行正常,

果然自己不太懂的设置还是不能乱加

以上就是

Django中Mysql Redis连接池

MySQL 连接

对Django服务进行压测,DB报错数据库连接数过多,如果设置MySQL的最大连接数为1000,很快连接数就会达到上限,调整到2000,也很快连接数达到上限。

xuetangx DB最大连接数2048

mysql> show variables like 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 2048   |
+-----------------+-------+
1 row in set (0.00 sec)

通过Django文档可以发现Django其实提供了一个连接池的另一种时间方式

Django的默认数据库连接

Django程序接受到请求之后,在第一次访问数据库的时候会创建一个数据库连接,直到请求结束,关闭数据库连接。(Django opens a connection to the database when it first makes a database query. It keeps this connection open and reuses it in subsequent requests.)下次请求也是如此。因此,这种情况下,随着访问的并发数越来越高,就会产生大量的数据库连接。也就是我们在压测时出现的情况。

使用CONN_MAX_AGE减少数据库请求(连接池)

每次请求都会创建新的数据库连接,这对于高并发的应用来说是不能接受的。因此在Django1.6时,提供了持久的数据库连接,通过DATABASE配置CONN_MAX_AGE来控制每个连接的最大存活时间。

The default value is 0, preserving the historical behavior of closing the database connection at the end of each request. To enable persistent connections, set CONN_MAX_AGE to a positive number of seconds. For unlimited persistent connections, set it to None.

这个参数的原理就是在每次创建完数据库连接之后,把连接放到一个Theard.local的实例中。在request请求开始结束的时候,打算关闭连接时会判断是否超过CONN_MAX_AGE设置这个有效期。超过则关闭。每次进行数据库请求的时候其实只是判断local中有没有已存在的连接,有则复用。

基于上述原因,Django中对于CONN_MAX_AGE的使用是有些限制的,使用不当,会适得其反。因为保存的连接是基于线程局部变量的,因此如果你部署方式采用多线程,必须要注意保证你的最大线程数不会多余数据库能支持的最大连接数(一个线程一个连接)。另外,如果使用开发模式运行程序(直接runserver的方式),建议不要设置CONN_MAX_AGE,因为这种情况下,每次请求都会创建一个Thread。同时如果你设置了CONN_MAX_AGE,将会导致你创建大量的不可复用的持久的连接。

CONN_MAX_AGE设置

CONN_MAX_AGE的时间怎么设置主要取决于数据库对空闲连接的管理,比如你的MySQL设置了空闲1分钟就关闭连接,那你的CONN_MAX_AGE就不能大于一分钟,不过DBA已经习惯了程序中的线程池的概念,会在数据库中设置一个较大的值。

Redis 连接

在做一个直播活动时,所有评论数据保存Redis,收到Redis服务报错:max number of clients reached

redis 127.0.0.1:6379> CONFIG GET maxclients
1) "maxclients"
2) "200"

发现设置的这个最大连接数太小了,因为每次request都会创建redis连接,几百个人同时使用就达到最大上线了。

Django-redis可以设置Redis连接池,并设置最大连接数,这样就能保证连接的复用和连接数的控制。

the default connection pool is simple. You can only customize the maximum number of connections in the pool, by setting CONNECTION_POOL_KWARGS in the CACHES setting。

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        ...
        "OPTIONS": {
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
        }
    }
}

END