前言
當(dāng)我們?cè)诒镜剡\(yùn)行Django項(xiàng)目
python3 manager runserver
但是户魏,這只適用于Django的開發(fā)模式,只支持單用戶訪問(wèn),要想部署到服務(wù)器上供大量用戶訪問(wèn)葛躏,綜合網(wǎng)上的許多資料澈段,在此羅列幾種不同的Django部署方案
工具:CentOS7騰訊云服務(wù)器、 Python3.6舰攒、 MySQL5.7败富、 Django2.2.7、 uwsgi2.0.18摩窃、 Nginx1.16.1
Django(Git)+uwsgi+Nginx
概念
在python web
開發(fā)中兽叮,我們經(jīng)常使用uwsgi配合nginx部署一個(gè)web框架,如Django或flask猾愿。同時(shí)我們又會(huì)說(shuō)充择,框架和web服務(wù)器之間要符合WSGI協(xié)議,想更深入理解WSGI和uwsgi的可以看這里
Nginx就是一個(gè)web服務(wù)器匪蟀,Django或flask就是web框架椎麦,只要web服務(wù)器和web框架滿足WSGI協(xié)議,它們就能相互搭配材彪。所以WSGI只是一個(gè)協(xié)議观挎,一個(gè)約定。而不是python的模塊段化、框架等具體的功能
uWSGI嘁捷,則是實(shí)現(xiàn)了WSGI協(xié)議的一個(gè)web服務(wù)器。即用來(lái)接受客戶端請(qǐng)求显熏,轉(zhuǎn)發(fā)響應(yīng)的程序雄嚣。實(shí)際上,一個(gè)uWSGI的web服務(wù)器喘蟆,再加上Django這樣的web框架缓升,就已經(jīng)可以實(shí)現(xiàn)網(wǎng)站的功能了。那為什么還需要Nginx呢蕴轨?
一個(gè)普通的個(gè)人網(wǎng)站港谊,訪問(wèn)量不大的話,當(dāng)然可以由uWSGI和Django構(gòu)成橙弱。但是一旦訪問(wèn)量過(guò)大歧寺,客戶端請(qǐng)求連接就要進(jìn)行長(zhǎng)時(shí)間的等待。這個(gè)時(shí)候就出來(lái)了分布式服務(wù)器棘脐,我們可以多來(lái)幾臺(tái)web服務(wù)器斜筐,都能處理請(qǐng)求。但是誰(shuí)來(lái)分配客戶端的請(qǐng)求連接和web服務(wù)器呢蛀缝?Nginx就是這樣一個(gè)管家的存在顷链,由它來(lái)分配。這也就是由Nginx實(shí)現(xiàn)反向代理内斯,即代理服務(wù)器
概述
首先客戶端請(qǐng)求服務(wù)資源蕴潦,
nginx作為直接對(duì)外的服務(wù)接口像啼,接收到客戶端發(fā)送過(guò)來(lái)的http請(qǐng)求,會(huì)解包潭苞、分析忽冻,
如果是靜態(tài)文件請(qǐng)求就根據(jù)nginx配置的靜態(tài)文件目錄,返回請(qǐng)求的資源此疹,
如果是動(dòng)態(tài)的請(qǐng)求僧诚,nginx就通過(guò)配置文件,將請(qǐng)求傳遞給uWSGI蝗碎;uWSGI 將接收到的包進(jìn)行處理湖笨,并轉(zhuǎn)發(fā)給wsgi,
wsgi根據(jù)請(qǐng)求調(diào)用django工程的某個(gè)文件或函數(shù)蹦骑,處理完后django將返回值交給wsgi慈省,
wsgi將返回值進(jìn)行打包,轉(zhuǎn)發(fā)給uWSGI眠菇,
uWSGI接收后轉(zhuǎn)發(fā)給nginx边败,nginx最終將返回值返回給客戶端(如瀏覽器)
注:不同的組件之間傳遞信息涉及到數(shù)據(jù)格式和協(xié)議的轉(zhuǎn)換
作用
- 第一級(jí)的nginx并不是必須的,uwsgi完全可以完成整個(gè)的和瀏覽器交互的流程捎废;
- 在nginx上加上安全性或其他的限制笑窜,可以達(dá)到保護(hù)程序的作用;
- uWSGI本身是內(nèi)網(wǎng)接口登疗,開啟多個(gè)work和processes可能也不夠用排截,而nginx可以代理多臺(tái)uWSGI完成uWSGI的負(fù)載均衡;
- django在debug=False下對(duì)靜態(tài)文件的處理能力不是很好辐益,而用nginx來(lái)處理更加高效断傲。
步驟
安裝Python3
在服務(wù)器上安裝Python3等依賴
# 進(jìn)入home目錄
cd ~
# 安裝相關(guān)庫(kù)
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
# 創(chuàng)建一個(gè)文件夾
mkdir /usr/local/python3
# 解壓安裝包
tar -zxvf Python-3.6.8.tgz
# 進(jìn)入解壓后的目錄
cd Python-3.6.8
# 配置,使安裝路徑為/usr/local/python3.6
# 第一個(gè)指定安裝的路徑,不指定的話,安裝過(guò)程中可能軟件所需要的文件復(fù)制到其他不同目錄,刪除軟件很不方便,復(fù)制軟件也不方便.
# 第二個(gè)可以提高python10%-20%代碼運(yùn)行速度. 參考:https://blog.csdn.net/whatday/article/details/98053179
# 第三個(gè)是為了安裝pip需要用到ssl,后面報(bào)錯(cuò)會(huì)有提到.
./configure --prefix=/usr/local/python3 --enable-optimizations --with-ssl
# 編譯荷腊,安裝 時(shí)間較長(zhǎng)
make && make install
# 創(chuàng)建軟連接
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
分支deploy
本地創(chuàng)建并切換到分支deploy
git checkout -b deploy
注:撤回commit
git reset --soft HEAD^
提交前注意在Django項(xiàng)目艳悔,配置setting.py中設(shè)置:
DEBUG = False
ALLOWED_HOSTS = ['你的服務(wù)器IP或者域名', 'localhost', '127.0.0.1']
然后提交本地Django代碼至github項(xiàng)目的deploy分支
拉取Django項(xiàng)目
git clone https://github.com/xxx/xxx.git
關(guān)于在github上 下載源碼 clone 非 master 分支的代碼
拉取后默認(rèn)是master分支急凰,需切換到deploy分支
git checkout deploy
安裝Django+uwsgi+nginx
這樣在你的服務(wù)器上就有了Django項(xiàng)目的代碼女仰,但是我們還沒(méi)安裝Django等第三方庫(kù)
接著服務(wù)器上安裝:
pip3 install django==2.2.7
pip3 install uwsgi
# 通過(guò)yum安裝nginx
yum install nginx -y
# 創(chuàng)建軟連接
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
測(cè)試Django
進(jìn)入項(xiàng)目根目錄
python3 manage.py runserver
我的出現(xiàn)報(bào)錯(cuò):
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.7.11.None.
根據(jù)報(bào)錯(cuò)安裝mysqlclient
pip3 install mysqlclient
又報(bào)錯(cuò):
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.
找了找資料,原來(lái)需要安裝mysqlclient所需依賴抡锈,略耗時(shí)
yum install mysql-devel gcc gcc-devel python-devel
再次安裝mysqlclient
pip3 install mysqlclient
成功安裝疾忍,但是再次runserver運(yùn)行Django 還是報(bào)錯(cuò):
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
期間登錄超級(jí)管理員卻出現(xiàn)CSRF驗(yàn)證失敗. 請(qǐng)求被中斷.
關(guān)閉防火墻試試
systemctl stop firewalld.service
附:
# 一.查看防火墻的狀態(tài)
systemctl status firewalld
# 或者
firewall-cmd --state
# 二.關(guān)閉防火墻
systemctl stop firewalld.service
# 禁止防火墻在開機(jī)時(shí)啟動(dòng)
systemctl disable firewalld.service
# 三一罩,開啟防火墻
systemctl start firewalld.service
# 防火墻在開機(jī)時(shí)啟動(dòng)
systemctl enable firewalld.service
# 重啟防火墻
systemctl restart firewalld.service
然后就可以登錄
測(cè)試uwsgi
查看安裝的uwsgi版本
uwsgi --version
編寫測(cè)試腳本,可以與Django項(xiàng)目放在同一級(jí)路徑下
vim test.py
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b"Hello World"]
然后運(yùn)行
uwsgi --http :8008 --wsgi-file test.py
然后訪問(wèn):http://服務(wù)器IP:8008/
出現(xiàn)Hello World
則成功
測(cè)試uwsgi+Django
執(zhí)行如下命令來(lái)檢驗(yàn)uwsgi是否能與django項(xiàng)目成功結(jié)合
uwsgi --http :8008 --chdir /home/LVideo --wsgi-file LVideo.wsgi.py --master --processes 4 --threads 2 --stats 127.0.0.1:9192
常用選項(xiàng)如下所示:
http :協(xié)議類型和端口號(hào)
processes :開啟的進(jìn)程數(shù)量
workers :開啟的進(jìn)程數(shù)量撇簿,等同于processes(官網(wǎng)的說(shuō)法是spawn the specified number ofworkers / processes)
chdir :指定運(yùn)行目錄(chdir to specified directory before apps loading)
wsgi-file :載入wsgi-file(load .wsgi file)
stats :在指定的地址上聂渊,開啟狀態(tài)服務(wù)(enable the stats server on the specified address)
threads :運(yùn)行線程差购。由于GIL的存在,我覺(jué)得這個(gè)真心沒(méi)啥用汉嗽。(run each worker in prethreaded mode with the specified number of threads)
master :允許主進(jìn)程存在(enable master process)
daemonize :使進(jìn)程在后臺(tái)運(yùn)行欲逃,并將日志打到指定的日志文件或者udp服務(wù)器(daemonize uWSGI)。實(shí)際上最常用的饼暑,還是把運(yùn)行記錄輸出到一個(gè)本地文件上稳析。
pidfile :指定pid文件的位置,記錄主進(jìn)程的pid號(hào)弓叛。
vacuum :當(dāng)服務(wù)器退出的時(shí)候自動(dòng)清理環(huán)境彰居,刪除unix socket文件和pid文件(try to remove all of the generated file/sockets)
注意:--wsgi-file后面跟的是相對(duì)目錄
訪問(wèn)http://IP:8008成功,出現(xiàn)你的Django項(xiàng)目的頁(yè)面
參數(shù)太多撰筷,可以將其寫入ini文件中
我是在Django項(xiàng)目的同級(jí)目錄下創(chuàng)建lvideo_uwsgi.ini文件陈惰,寫入如下內(nèi)容(采用字典格式)
我的/home
下的文件,LVideo是clone下來(lái)的項(xiàng)目:
[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
# 真實(shí)服務(wù)的端口
# Django項(xiàng)目根目錄 (絕對(duì)路徑)
chdir = /home/LVideo
# wsgi.py文件在項(xiàng)目中的位置
module = LVideo.wsgi
# process-related settings
# master
master = true
# 運(yùn)行的進(jìn)程數(shù)
processes = 4
# ... with appropriate permissions - may be needed
# chmod-socket = 664
# clear environment on exit
# 當(dāng)服務(wù)器退出的時(shí)候自動(dòng)清理環(huán)境毕籽,刪除unix socket文件和pid文件
vacuum = true
# 使進(jìn)程在后臺(tái)運(yùn)行奴潘,并將日志打到指定的日志文件或者udp服務(wù)器
daemonize = /home/uwsgi.log
# 指定pid文件的位置,記錄主進(jìn)程的pid號(hào)
pidfile = /home/uwsgi.pid
# 不記錄請(qǐng)求信息的日志,只記錄錯(cuò)誤以及uWSGI內(nèi)部消息到日志中
disable-logging = true
你可以復(fù)制這里的內(nèi)容影钉,注意修改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 這是在測(cè)試通過(guò)瀏覽器訪問(wèn)時(shí),可以成功
socket =:8008 這是為了與nginx配置時(shí)需要的
兩個(gè)顛倒了就會(huì)出錯(cuò)廉赔,所以瀏覽器測(cè)試完后需要修改回socket
這樣保存好后肉微,啟動(dòng)
uwsgi --ini lvideo_uwsgi.ini
若你的ini文件中是http =:8008
則可以通過(guò)瀏覽器訪問(wèn)到8008端口,然后注意修改回socket =:8008
因?yàn)槲覀兒竺嬉Y(jié)合nginx
注:這是配置了daemonize后的uwsgi運(yùn)行成功的樣子
[root@VM_0_14_centos home]# uwsgi --ini lvideo_uwsgi.ini
[uWSGI] getting INI configuration from lvideo_uwsgi.ini
測(cè)試Nginx
前面已經(jīng)通過(guò)yum安裝了nginx
查看Nginx版本
nginx -v
然后訪問(wèn)服務(wù)器IP就可以看到CentOS的歡迎界面蜡塌?我TM也不知道為什么不是Nginx的歡迎界面...(好像說(shuō)是index.html的問(wèn)題)
看看有沒(méi)有進(jìn)程占用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)
挖礦病毒(我買的騰訊的服務(wù)器)碉纳,等會(huì)再處理,說(shuō)明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;
# 鏈接超時(shí)時(shí)間
uwsgi_read_timeout 30;
}
}
保存
看看訪問(wèn)8088端口有沒(méi)有頁(yè)面
若出現(xiàn)502 Bad Gateway nginx/1.16.1
先輸入以下命令看看是否有已存在的uwsgi或者nginx進(jìn)程
ps -ef | grep uwsgi
ps -ef | grep nginx
有的話可以殺死
killall -9 uwsgi
killall -9 nginx
然后重新運(yùn)行uwsgi和nginx
uwsgi --ini lvideo_uwsgi.ini
systemctl start nginx.service
然后一定一定可以看到8088端口的頁(yè)面劳曹,我發(fā)四(前前后后調(diào)整了10多次)!@拍Α铁孵!
如果你的項(xiàng)目界面變得非常low,那么是因?yàn)槟氵€沒(méi)配置nginx解析靜態(tài)文件房资,在nginx.conf的 location / {} 前面加上Django項(xiàng)目靜態(tài)文件夾的路徑
location /static/ {
# 你的static的絕對(duì)路徑
alias /home/LVideo/LVideo/static/;
}
uwsgi+nginx進(jìn)程
在啟動(dòng)uwsgi時(shí)蜕劝,如果指定了pid,可以通過(guò)pid停止uwsgi,如果沒(méi)指定岖沛,直接kill uwsgi的進(jìn)程id暑始,會(huì)導(dǎo)致uwsgi重啟,無(wú)法關(guān)閉成功
附:
# nginx開機(jī)自啟動(dòng)
systemctl enable nginx.service
# 終止uwsgi方法
# 1婴削、未指定 daemonize:
Ctrl+c(快捷鍵可能有所不同)
# 2蒋荚、指定daemonize和pidfile:
uwsgi --stop uwsgi.pid
# 3、指定daemonize馆蠕,但未指定pidfile 通過(guò)ps期升,查看uwsgi相關(guān)進(jìn)程
ps aux|grep uwsgi
# kill pid會(huì)發(fā)送SIGTERM,只會(huì)導(dǎo)致重啟互躬,而不是結(jié)束掉播赁。需要發(fā)送SIGINT或SIGQUIT,對(duì)應(yīng)著是INT才可以
killall -s INT /usr/local/bin/uwsgi
# 若出現(xiàn)
-bash: killall: command not found
# 則
# debian吼渡、ubuntu系統(tǒng)下:
apt-get install psmisc
# centos 下:
yum install psmisc
# 進(jìn)程查看及殺死:
lsof -i:80
ps -ef | grep nginx
killall -9 nginx
提交代碼
更新服務(wù)器Django代碼到github
find / -name id_rsa
沒(méi)有ssh鑰匙
在 cd ~ 下 :ssh-keygen -t rsa -C "xxx@xx.com"
一路回車
可以看到:Enter file in which to save the key (/root/.ssh/id_rsa)
cat /root/.ssh/id_rsa.pub
復(fù)制內(nèi)容到github上即可
Django(Git)+uwsgi+Nginx+venv
參考
一
django項(xiàng)目部署到服務(wù)器+虛擬環(huán)境
解決nginx+uwsgi部署Django的所有問(wèn)題
如何把本地的Django項(xiàng)目部署到服務(wù)器(親測(cè))
centos6.5下配置django+uwsgi+nginx
centos下配置django容为、uwsgi和nginx(親測(cè)成功)
Python+Django+Nginx+Uwsgi(史上最全步驟)
uWSGI+django+nginx的工作原理流程與部署歷程
Linux vim命令
uwsgi、wsgi和nginx的區(qū)別和關(guān)系!!
二
linux如何徹底殺掉uwsgi進(jìn)程
uWSGI的安裝與配置(官網(wǎng)摘錄)
centos7 nginx安裝/啟動(dòng)/進(jìn)程狀態(tài)/殺掉進(jìn)程
nginx報(bào)502錯(cuò)誤寺酪,日志connect() failed (111: Connection refused) while connecting to upstream的解決
Linux 下建立 Git 與 GitHub 的連接并克隆到本地