前言
當我們在本地運行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最終將返回值返回給客戶端(如瀏覽器)
注:不同的組件之間傳遞信息涉及到數據格式和協議的轉換
作用
- 第一級的nginx並不是必須的,uwsgi完全可以完成整個的和瀏覽器交互的流程;
- 在nginx上加上安全性或其他的限制,可以達到保護程序的作用;
- uWSGI本身是內網接口,開啓多個work和processes可能也不夠用,而nginx可以代理多臺uWSGI完成uWSGI的負載均衡;
- 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
分支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 的連接並克隆到本地