Django+uwsgi+Nginx部署到雲服務器

前言

當我們在本地運行Django項目

python3 manager runserver

但是,這隻適用於Django的開發模式,只支持單用戶訪問,要想部署到服務器上供大量用戶訪問,綜合網上的許多資料,在此羅列幾種不同的Django部署方案

工具:CentOS7騰訊雲服務器、 Python3.6、 MySQL5.7、 Django2.2.7、 uwsgi2.0.18、 Nginx1.16.1

Django(Git)+uwsgi+Nginx

概念

python web開發中,我們經常使用uwsgi配合nginx部署一個web框架,如Django或flask。同時我們又會說,框架和web服務器之間要符合WSGI協議,想更深入理解WSGI和uwsgi的可以看這裏

Nginx就是一個web服務器,Django或flask就是web框架,只要web服務器和web框架滿足WSGI協議,它們就能相互搭配。所以WSGI只是一個協議,一個約定。而不是python的模塊、框架等具體的功能

uWSGI,則是實現了WSGI協議的一個web服務器。即用來接受客戶端請求,轉發響應的程序。實際上,一個uWSGI的web服務器,再加上Django這樣的web框架,就已經可以實現網站的功能了。那爲什麼還需要Nginx呢?

一個普通的個人網站,訪問量不大的話,當然可以由uWSGI和Django構成。但是一旦訪問量過大,客戶端請求連接就要進行長時間的等待。這個時候就出來了分佈式服務器,我們可以多來幾臺web服務器,都能處理請求。但是誰來分配客戶端的請求連接和web服務器呢?Nginx就是這樣一個管家的存在,由它來分配。這也就是由Nginx實現反向代理,即代理服務器

概述

首先客戶端請求服務資源,
nginx作爲直接對外的服務接口,接收到客戶端發送過來的http請求,會解包、分析,
如果是靜態文件請求就根據nginx配置的靜態文件目錄,返回請求的資源,
如果是動態的請求,nginx就通過配置文件,將請求傳遞給uWSGI;uWSGI 將接收到的包進行處理,並轉發給wsgi,
wsgi根據請求調用django工程的某個文件或函數,處理完後django將返回值交給wsgi,
wsgi將返回值進行打包,轉發給uWSGI,
uWSGI接收後轉發給nginx,nginx最終將返回值返回給客戶端(如瀏覽器)
注:不同的組件之間傳遞信息涉及到數據格式和協議的轉換

作用

  1. 第一級的nginx並不是必須的,uwsgi完全可以完成整個的和瀏覽器交互的流程;
  2. 在nginx上加上安全性或其他的限制,可以達到保護程序的作用;
  3. uWSGI本身是內網接口,開啓多個work和processes可能也不夠用,而nginx可以代理多臺uWSGI完成uWSGI的負載均衡;
  4. django在debug=False下對靜態文件的處理能力不是很好,而用nginx來處理更加高效。

步驟

安裝Python3

在服務器上安裝Python3等依賴

# 進入home目錄
cd ~

# 安裝相關庫
yum -y groupinstall "Development tools"
yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel
yum -y install gcc
yum install -y libffi-devel zlib1g-dev
yum install zlib* -y
 
# 下載python3.6安裝包
wget https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tgz
 
# 創建一個文件夾
mkdir /usr/local/python3
 
# 解壓安裝包
tar -zxvf Python-3.6.8.tgz
 
# 進入解壓後的目錄
cd Python-3.6.8
 
# 配置,使安裝路徑爲/usr/local/python3.6
# 第一個指定安裝的路徑,不指定的話,安裝過程中可能軟件所需要的文件複製到其他不同目錄,刪除軟件很不方便,複製軟件也不方便.
# 第二個可以提高python10%-20%代碼運行速度. 參考:https://blog.csdn.net/whatday/article/details/98053179
# 第三個是爲了安裝pip需要用到ssl,後面報錯會有提到.
./configure --prefix=/usr/local/python3 --enable-optimizations --with-ssl
 
# 編譯,安裝 時間較長 
make && make install
 
# 創建軟連接
ln -s /usr/local/python3/bin/python3 /usr/local/bin/python3
ln -s /usr/local/python3/bin/pip3 /usr/local/bin/pip3
 
# 更新pip
pip3 install --upgrade pip

安裝mysql

參考騰訊雲Centos7 安裝Mysql5.7

分支deploy

本地創建並切換到分支deploy

git checkout -b deploy

注:撤回commit

git reset --soft HEAD^

提交前注意在Django項目,配置setting.py中設置:

DEBUG = False

ALLOWED_HOSTS = ['你的服務器IP或者域名', 'localhost', '127.0.0.1']

然後提交本地Django代碼至github項目的deploy分支

拉取Django項目
git clone https://github.com/xxx/xxx.git

關於在github上 下載源碼 clone 非 master 分支的代碼

拉取後默認是master分支,需切換到deploy分支

git checkout deploy
安裝Django+uwsgi+nginx

這樣在你的服務器上就有了Django項目的代碼,但是我們還沒安裝Django等第三方庫

接着服務器上安裝:

pip3 install django==2.2.7
pip3 install uwsgi

# 通過yum安裝nginx
yum install nginx -y

# 創建軟連接
ln -s /usr/local/python3/bin/uwsgi /usr/bin/uwsgi
# ln -s /usr/local/python3/bin/virtualenv /usr/bin/virtualenv
# ln -s /usr/local/python3/bin/gunicorn /usr/bin/gunicorn
ln -s /usr/local/python3/bin/django-admin.py /usr/bin/django-admin
測試Django

進入項目根目錄

python3 manage.py runserver

我的出現報錯:

django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.7.11.None.

根據報錯安裝mysqlclient

pip3 install mysqlclient

又報錯:

ERROR: Command errored out with exit status 1:
     command: /usr/local/python3/bin/python3.6 -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-p6v1q25n/mysqlclient/setup.py'"'"'; __file__='"'"'/tmp/pip-install-p6v1q25n/mysqlclient/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-install-p6v1q25n/mysqlclient/pip-egg-info
         cwd: /tmp/pip-install-p6v1q25n/mysqlclient/
    Complete output (10 lines):
    /bin/sh: mysql_config: command not found
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-p6v1q25n/mysqlclient/setup.py", line 18, in <module>
        metadata, options = get_config()
      File "/tmp/pip-install-p6v1q25n/mysqlclient/setup_posix.py", line 53, in get_config
        libs = mysql_config("libs_r")
      File "/tmp/pip-install-p6v1q25n/mysqlclient/setup_posix.py", line 28, in mysql_config
        raise EnvironmentError("%s not found" % (mysql_config.path,))
    OSError: mysql_config not found
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.

找了找資料,原來需要安裝mysqlclient所需依賴,略耗時

yum install mysql-devel gcc gcc-devel python-devel

再次安裝mysqlclient

pip3 install mysqlclient

成功安裝,但是再次runserver運行Django 還是報錯:

File "/usr/local/python3/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 36, in <module>
    raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__)
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.7.11.None.

找了找資料,django2.2和pymysql版本不匹配。mysqldb不支持python3 參考django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.2

解決辦法:

找到Python安裝路勁下的Python36-32\Lib\site-packages\django\db\backends\mysql\base.py文件

vi /usr/local/python3/lib/python3.6/site-packages/django/db/backends/mysql/base.py

將文件中的如下代碼註釋即可

if version < (1, 3, 3):
    raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)

接着

python3 manage.py makemigrations

python3 manage.py migrate

python3 manage.py createsuperuser

python3 manage.py runserver

期間登錄超級管理員卻出現CSRF驗證失敗. 請求被中斷.

關閉防火牆試試

systemctl stop firewalld.service
附:
# 一.查看防火牆的狀態
systemctl status  firewalld

# 或者
firewall-cmd --state

# 二.關閉防火牆
systemctl stop firewalld.service

# 禁止防火牆在開機時啓動
systemctl disable firewalld.service

# 三,開啓防火牆
systemctl start firewalld.service

# 防火牆在開機時啓動
systemctl enable firewalld.service

# 重啓防火牆
systemctl restart firewalld.service

然後就可以登錄

測試uwsgi

查看安裝的uwsgi版本

uwsgi --version

編寫測試腳本,可以與Django項目放在同一級路徑下

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

然後運行

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

然後訪問:http://服務器IP:8008/

出現Hello World則成功

測試uwsgi+Django

執行如下命令來檢驗uwsgi是否能與django項目成功結合

uwsgi --http :8008 --chdir /home/LVideo --wsgi-file LVideo.wsgi.py --master --processes 4 --threads 2 --stats 127.0.0.1:9192

常用選項如下所示:

http       :協議類型和端口號
processes  :開啓的進程數量
workers    :開啓的進程數量,等同於processes(官網的說法是spawn the specified number ofworkers / processes)
chdir      :指定運行目錄(chdir to specified directory before apps loading)
wsgi-file  :載入wsgi-file(load .wsgi file)
stats      :在指定的地址上,開啓狀態服務(enable the stats server on the specified address)
threads    :運行線程。由於GIL的存在,我覺得這個真心沒啥用。(run each worker in prethreaded mode with the specified number of threads)
master     :允許主進程存在(enable master process)
daemonize  :使進程在後臺運行,並將日誌打到指定的日誌文件或者udp服務器(daemonize uWSGI)。實際上最常用的,還是把運行記錄輸出到一個本地文件上。
pidfile    :指定pid文件的位置,記錄主進程的pid號。
vacuum     :當服務器退出的時候自動清理環境,刪除unix socket文件和pid文件(try to remove all of the generated file/sockets)

注意:--wsgi-file後面跟的是相對目錄

訪問http://IP:8008成功,出現你的Django項目的頁面

參數太多,可以將其寫入ini文件中

我是在Django項目的同級目錄下創建lvideo_uwsgi.ini文件,寫入如下內容(採用字典格式)

我的/home下的文件,LVideo是clone下來的項目:

[root@VM_0_14_centos home]# ls
LVideo  lvideo_uwsgi.ini  test.py  uwsgi.log  uwsgi.pid

新建lvideo_uwsgi.ini

vi lvideo_uwsgi.ini

這是參考:

# lvideo_uwsgi.ini file
[uwsgi]

# Django-related settings
http = :8008
# 真實服務的端口

# Django項目根目錄 (絕對路徑)
chdir           = /home/LVideo

# wsgi.py文件在項目中的位置
module          = LVideo.wsgi

# process-related settings
# master
master          = true

# 運行的進程數
processes       = 4

# ... with appropriate permissions - may be needed
# chmod-socket    = 664
# clear environment on exit
# 當服務器退出的時候自動清理環境,刪除unix socket文件和pid文件
vacuum          = true

# 使進程在後臺運行,並將日誌打到指定的日誌文件或者udp服務器
daemonize = /home/uwsgi.log

# 指定pid文件的位置,記錄主進程的pid號
pidfile = /home/uwsgi.pid

# 不記錄請求信息的日誌,只記錄錯誤以及uWSGI內部消息到日誌中
disable-logging = true

你可以複製這裏的內容,注意修改chdir、module、daemonize、pidfile:

[uwsgi]

socket          = :8008
chdir           = /home/LVideo
module          = LVideo.wsgi
master          = true
processes       = 4
vacuum          = true
daemonize       = /home/uwsgi.log
pidfile         = /home/uwsgi.pid
disable-logging = true

其中的端口有兩種,分爲:

http   =:8008  這是在測試通過瀏覽器訪問時,可以成功
socket =:8008  這是爲了與nginx配置時需要的

兩個顛倒了就會出錯,所以瀏覽器測試完後需要修改回socket

這樣保存好後,啓動

uwsgi --ini lvideo_uwsgi.ini

若你的ini文件中是http =:8008則可以通過瀏覽器訪問到8008端口,然後注意修改回socket =:8008

因爲我們後面要結合nginx

注:這是配置了daemonize後的uwsgi運行成功的樣子

[root@VM_0_14_centos home]# uwsgi --ini  lvideo_uwsgi.ini 
[uWSGI] getting INI configuration from lvideo_uwsgi.ini
測試Nginx

前面已經通過yum安裝了nginx

查看Nginx版本

nginx -v

然後訪問服務器IP就可以看到CentOS的歡迎界面?我TM也不知道爲什麼不是Nginx的歡迎界面…(好像說是index.html的問題)

看看有沒有進程佔用80端口

lsof -i:80

這裏有

kinsing   11406 root    5u  IPv4 3066592      0t0  TCP VM_0_14_centos:47296->ip255.ip-139-99-50.net:http (ESTABLISHED)
kinsing   11406 root    7u  IPv4 3068905      0t0  TCP VM_0_14_centos:48120->ip255.ip-139-99-50.net:http (ESTABLISHED)
kdevtmpfs 11537 root   15u  IPv4 3021919      0t0  TCP VM_0_14_centos:46146->45.89.230.240:http (ESTABLISHED)
kdevtmpfs 11537 root  175u  IPv4 3068497      0t0  TCP VM_0_14_centos:42542->178.170.189.5:http (SYN_SENT)
kdevtmpfs 11537 root  176u  IPv4 3068779      0t0  TCP VM_0_14_centos:42604->178.170.189.5:http (SYN_SENT)
kdevtmpfs 11537 root  177u  IPv4 3068921      0t0  TCP VM_0_14_centos:42656->178.170.189.5:http (SYN_SENT)

挖礦病毒(我買的騰訊的服務器),等會再處理,說明80端口被佔,那麼我們就配置爲8088端口

輸入nginx -t 看看nginx.conf在哪

[root@VM_0_14_centos ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

然後修改

vi /etc/nginx/nginx.conf

把server部分用下面的替代

server {
    listen       8088;
    server_name  localhost;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;

    charset UTF-8;
    # 這裏存放日誌文件
    access_log  /var/log/nginx/LVideo_access.log;
    error_log   /var/log/nginx/LVideo_error.log;

    client_max_body_size 75M;
    location / {
    	# 你的uwsgi_params文件的路徑
        include /etc/nginx/uwsgi_params;
        # 你的uwsgi端口
        uwsgi_pass 127.0.0.1:8008;
        # 鏈接超時時間
        uwsgi_read_timeout 30;
    }
}

保存

看看訪問8088端口有沒有頁面

若出現502 Bad Gateway nginx/1.16.1

先輸入以下命令看看是否有已存在的uwsgi或者nginx進程

ps -ef | grep uwsgi

ps -ef | grep nginx

有的話可以殺死

killall -9 uwsgi

killall -9 nginx

然後重新運行uwsgi和nginx

uwsgi --ini lvideo_uwsgi.ini

systemctl start nginx.service

然後一定一定可以看到8088端口的頁面,我發四(前前後後調整了10多次)!!!

如果你的項目界面變得非常low,那麼是因爲你還沒配置nginx解析靜態文件,在nginx.conf的 location / {} 前面加上Django項目靜態文件夾的路徑

location /static/ {
	    # 你的static的絕對路徑
        alias /home/LVideo/LVideo/static/;
    }
uwsgi+nginx進程

在啓動uwsgi時,如果指定了pid,可以通過pid停止uwsgi,如果沒指定,直接kill uwsgi的進程id,會導致uwsgi重啓,無法關閉成功

附:

# nginx開機自啓動
systemctl enable nginx.service

# 終止uwsgi方法
# 1、未指定 daemonize:
Ctrl+c(快捷鍵可能有所不同)

# 2、指定daemonize和pidfile:
uwsgi --stop uwsgi.pid

# 3、指定daemonize,但未指定pidfile 通過ps,查看uwsgi相關進程
ps aux|grep uwsgi
# kill pid會發送SIGTERM,只會導致重啓,而不是結束掉。需要發送SIGINT或SIGQUIT,對應着是INT纔可以
killall -s INT /usr/local/bin/uwsgi

# 若出現
-bash: killall: command not found

# 則
# debian、ubuntu系統下:
  apt-get install psmisc

# centos 下:
  yum install psmisc

# 進程查看及殺死:
lsof -i:80

ps -ef | grep nginx

killall -9 nginx
提交代碼

更新服務器Django代碼到github

find / -name id_rsa

沒有ssh鑰匙

在 cd ~ 下 :ssh-keygen -t rsa -C "[email protected]"

一路回車

可以看到:Enter file in which to save the key (/root/.ssh/id_rsa)

cat /root/.ssh/id_rsa.pub

複製內容到github上即可

Django(Git)+uwsgi+Nginx+venv

參考

django項目部署到服務器+虛擬環境
解決nginx+uwsgi部署Django的所有問題
如何把本地的Django項目部署到服務器(親測)
centos6.5下配置django+uwsgi+nginx
centos下配置django、uwsgi和nginx(親測成功)
Python+Django+Nginx+Uwsgi(史上最全步驟)
uWSGI+django+nginx的工作原理流程與部署歷程
Linux vim命令
uwsgi、wsgi和nginx的區別和關係!!

linux如何徹底殺掉uwsgi進程
uWSGI的安裝與配置(官網摘錄)
centos7 nginx安裝/啓動/進程狀態/殺掉進程
nginx報502錯誤,日誌connect() failed (111: Connection refused) while connecting to upstream的解決
Linux 下建立 Git 與 GitHub 的連接並克隆到本地

使用Django + Vue.js快速而優雅地構建前後端分離項目

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章