Centos部署Python3+Django+uWSGI+Nginx
背景:最近打算自己寫一個小網站,介面不多,就打算用Django來寫了,正好提升一下自己的python的程式碼水平。這篇部落格主要是用來記錄從本地執行到部署伺服器這過程遇到的一些小問題。
提示:
如果是阿里雲的伺服器,我們要去阿里雲的後臺管理業去配置安全規則,開放我們即將要使用的那些埠的許可權,他很多的埠都是預設不開放的。
Djano簡單介紹
我使用的IDE是PyCharm,操作簡單,可直接建立Django專案,然後python版本選擇3.x。
簡單的說兩句Django。這個框架個人感覺上手容易,畢竟框架做了比較好的分層,不同檔案的只能劃分也是很明確的,當然裡面涉及一些配置引數什麼的,這個大家可以去網上找Django的教程,先看看入門。
在目錄結構中我們可以看到一個venv的檔案,這個算是給我們建立的一個虛擬環境,為應用提供了隔離的Python執行環境,解決了不同應用間多版本的衝突問題。這個大家可以自己去查一下加深理解。
在本地敲程式碼的時候,使用到某些庫的時候我們會使用 pip install xxxxx 來安裝。使用了venv這種虛擬環境,所有的包預設安裝在本專案下,新的專案使用的話需要再安裝。
前期的本地工作就沒什麼了,從網上找到教程一點一點的學習就可以了。當然了,我們要準備部署到伺服器的時候,首先得保證本地能成功的執行,本地都跑不了,那配置到伺服器上肯定也不會,別的不說,程式碼首先別有問題。
必要依賴包的安裝
之前呢,搞過幾次java,當時記得是把專案打成war包,然後上傳,有點笨。把Django專案壓縮一下再上傳應該也是可以的。但是何必呢,我們直接把程式碼傳到github(或者自己存程式碼的地方)上面,然後在登上伺服器,直接git clone多好~ 有的時候太緊張,或者把事情想的太難了。
我們在本地pip install的那些包,到了伺服器那邊還是要再重新install的。
在伺服器端,clone下專案來之後,cd到當前專案,我們可以把之前安裝的包再一個一個的重新pip install,但是太多了我們也不一定記得清楚有哪些,所以我們現在本地生成一個記錄引用的包的檔案。
依賴檔案生成 (本地操作) pip freeze > requirements.txt 依賴檔案安裝 (伺服器端操作) pip install -r requirement.txt
我們建立專案時候用的python的版本要跟伺服器上面的版本相同,我的伺服器系統是centos7,記得好像是自帶的是python2.x,然後我專案使用的python3.x, 所以我要在伺服器上裝python3.x, 具體的安裝操作,大家自己搜尋一下。
安裝完高版本的python之後,執行pip,可能會出現一些問題,我忘記當時的報錯了,好像是pip的版本問題,因為Django的版本,所以需要安裝pip3, 這地方安裝有些囉嗦,大家不要著急,慢慢的裝,遇到報什麼錯就去相應的搜尋一下。
有時候會提醒你升級pip,然你使用這個 pip install --upgrade pip
命令,個人建議不要亂試,我就是使用這個升級之後,pip和pip3都找不到了。
如果pip install顯示 ‘沒有那個檔案或目錄’ 的時候,可以嘗試一下下面這個命令 python -m pip install xxx
。
如果沒什麼別的報錯了的話我們繼續執行 pip install -r requirement.txt
來安裝我們需要的包。
下面我遇到了讓我糾結了一天的一個錯誤。

其實主要的問題就是 在安裝mysqlclient的過程中 mysql_config not found
我這還特地上Stack Overflow上問了問,也沒人回到我。我在網上搜索了關於這個問題的錯誤,嘗試了所有能嘗試的方法都沒能解決。
我搜索了一下,我的檔案裡壓根就沒有mysql_config這個檔案,太氣了。
其中有幾個比較靠譜的方法,是讓安裝 yum install mysql-devel
這個東西,我也跟著做運行了這個命令,不過安裝出問題了,從終端上的提示來看,是有衝突,是與資料庫有衝突,很抱歉我忘記截圖了,但是我從網上的一片文章中也找到了一樣的問題,大家參看一下。
--> Running transaction check ---> Package mysql-devel.x86_64 0:5.1.69-1.el6_4 will be installed --> Processing Dependency: mysql = 5.1.69-1.el6_4 for package: mysql-devel-5.1.69-1.el6_4.x86_64 --> Running transaction check ---> Package mysql.x86_64 0:5.1.69-1.el6_4 will be installed --> Processing Conflict: MySQL-client-5.5.30-1.el6.x86_64 conflicts mysql --> Processing Conflict: MySQL-server-5.5.30-1.el6.x86_64 conflicts mysql --> Processing Conflict: mysql-5.1.69-1.el6_4.x86_64 conflicts MySQL --> Finished Dependency Resolution Error: mysql conflicts with MySQL-devel-5.5.30-1.el6.x86_64 You could try using --skip-broken to work around the problem You could try running: rpm -Va --nofiles --nodigest
可以看得出來有幾個Conflict, 最可氣的是底下他還教你通過 --skip-broken
來避開這些衝突,我照做了,結果依然不管用,問題就出在這個衝突上。
好吧,你不是說跟MySQL衝突嗎,我就把MySQL解除安裝了再說(我很早之前學習MySQL的時候就安裝了)。
具體的MySQL移除過程我就不多說了,只提下面兩個點:
使用 rpm -qa|grep mysql
檢視mysql的安裝情況
rpm -e 檔名 --nodeps
來移除
如果有不管用的地方大家看一下下面這兩篇文章,說的還不錯,借鑑一下。
http://834945712.iteye.com/blog/1979042
https://blog.csdn.net/lsa000/article/details/77374351然後就是重新安裝MySQL,步驟可借鑑下面這篇文章
https://www.jianshu.com/p/d679db1ab27f 反正我的專案在重新安裝了MySQL之後就好了,mysql_config檔案也有了,再一次執行 pip install -r requirement.txt
,然後所有的包都順利的安裝完成。
最後執行python manager.py runserver,就可以看到我們的專案跑起來了 ~
但是呢,這樣執行使用Django自帶的WSGI Server執行的,是有效能缺陷的,併發承受能力不行 ~ 要不然為什麼我們還要使用uWSGI+Nginx呢
具體差距看一下這篇對比文章
django自帶wsgi server vs 部署uwsgi+nginx後的效能對比uWSGI
首先在使用之前,我們得先大致瞭解他們到底是什麼東西,為什麼要使用。
瞭解uWSGI
uWSGI旨在為部署分散式叢集的網路應用開發一套完整的解決方案。主要面向web及其標準服務。由於其可擴充套件性,能夠被無限制的擴充套件用來支援更多平臺和語言。uWSGI是一個web伺服器,實現了WSGI協議,uwsgi協議,http協議等。
uWSGI又很多優點,具體對uWSGI的講解看這個
https://www.jianshu.com/p/679dee0a4193具體uWSGI的安裝我就不詳細的說了,網上教程很多,我想說的是配置檔案的問題,因為我搜了很多關於uWSGI的文章,可能是由於我們每個人的專案的結構不同,或者別的願意,所以總感覺這個配置檔案很難寫。
網上大多數的教程在教我們使用uWSGI的時候會讓我們新建一個test.py的檔案,然後 uwsgi --http :8000 --wsgi-file test.py
, 檢測是否能正常執行。
執行成功的話就說明uWSGI這個橋樑是起作用的~
下面這個說明我很喜歡
the web client <-> uWSGI <-> Python
但是我們使用uWSGI是為了服務於Django專案的,所以說我壓根就沒嘗試上面這一步,而是直接嘗試通過uwsgi命令來執行django專案。
這裡會有一點小分歧,因為我從網上搜到的很多教程是說運行了一個.wsgi的檔案,但是我整個專案中就沒有發現這麼一個檔案,只有一個wsgi.py的檔案,所以我就是用了下面這個命令來執行整個專案
uwsgi --http :8000 --wsgi-file wsgi.py
注意後面wsgi.py的路徑問題.
結果還不錯,專案跑得起來了。
配置uwsgi
我其實並不是真的明白為什麼要配置這個.ini檔案,聽別人說是這樣的:
如果你喜歡用命令列的方式(如shell)敲命令,那可以省去任何配置。
但是,絕大多數人,還是不願意記那麼長的命令,反覆敲的。所以uwsgi裡,就給大家提供了多種配置,省去你啟動時候,需要敲一長串命令的過程。
配置的方式很多,我選擇使用ini的方式,也是因為網上教程多。
我們在根目錄下面建一個.ini的檔案,由於最初跟著網上的教程學,所以起了個test.ini的名字。
下面是這個檔案裡面的內容,首先我得成人有很多我是不知道什麼意思的,而且網上教程中的配置會有各種各樣的引數,這個以後我再慢慢研究。
http = :8000 chdir = /root/myblog/ module = blog.wsgi:application processes = 4 threads = 2 master = true enable-threads = true daemonize = /root/searchmarket/marketSearch/uwsgi.log buffer-size = 21573
稍微解釋一下,不一定多,可作參考。
chdir是當前專案的路徑
module算是wsgi.py這個檔案的路徑嗎 ?好像是的,但是為什麼要寫成這樣子呢 ?
(在我的專案中,myblog目錄下有一個blog資料夾,wsgi.py就在這個blog資料夾中~是在搞不懂為啥要寫成blog.wsgi而且後面還加上個 :application)
daemonize是放log日誌的地方,自己建立好檔案,路徑貼上。
差不多了...
然後執行 uwsgi --ini test.ini
這個命令就行了 ~
執行完之後,從終端裡我看不出來倒是成功了沒有,我用postman請求了一下試了試,失敗的話我就從那個.log檔案中看日誌,然後處理問題。
成功的話,那就是uWSGI部分成功了。
注:也許會碰到端口占用的問題
我的埠使用的8000 然後執行這個命令 lsof -i:8000
, 然後你會看到PID, 然後 kill xxx
,就行了。
我發現了一個快速的方法
killall -9 uwsgi
Nginx
啟動Nginx
我使用的是yum安裝,簡單易操作。
yum -y install nginx
就OK了
然後nginx啟動頁非常簡單,直接 nginx
就好了。
在啟動nginx時候碰到一個小問題,我幹了什麼導致的我也不太清楚,反正就是報了這麼個錯:
Job for nginx.service failed because the control process exited with error code
就是沒啟動的了,我忽然想起來之前看的一篇部落格,在啟動之前他檢測了80埠的狀態,我就隱隱感覺是80埠已經被佔用的緣故。
然後我運行了這個命令 netstat -ntpl
來檢視當前活躍的連結
netstat -ntpl 檢視一下80埠是否被佔用
Active Internet connections (only servers) Proto Recv-Q Send-Q Local AddressForeign AddressStatePID/Program name tcp00 0.0.0.0:33060.0.0.0:*LISTEN14267/mysqld tcp00 127.0.0.1:63790.0.0.0:*LISTEN709/redis-server 12 tcp00 0.0.0.0:800.0.0.0:*LISTEN4225/nginx: master tcp00 0.0.0.0:220.0.0.0:*LISTEN1184/sshd tcp00 0.0.0.0:80000.0.0.0:*LISTEN4212/uwsgi
發現nginx已經被我啟動過一次了,我也記不清楚了,反正現在啟動nginx沒有什麼提示。(網上一些文章顯示有一個OK的提示)。
然後可以 kill 4225
, 在 nginx
,就好了 ~
用瀏覽器開啟 xxx.xxx.xxx.xx:80 (xx代表我們伺服器的ip),就可以看到nginx啟動成功的標識了。
配置Nginx
yum線上安裝會將nginx的安裝檔案放在系統的不同位置,可以通過命令 rpm -ql nginx
來檢視安裝路徑
[root@sunxb ~]# rpm -ql nginx /etc/logrotate.d/nginx /etc/nginx /etc/nginx/conf.d /etc/nginx/conf.d/default.conf /etc/nginx/fastcgi_params /etc/nginx/koi-utf /etc/nginx/koi-win /etc/nginx/mime.types /etc/nginx/modules /etc/nginx/nginx.conf /etc/nginx/scgi_params /etc/nginx/uwsgi_params /etc/nginx/win-utf /etc/sysconfig/nginx /etc/sysconfig/nginx-debug /usr/lib/systemd/system/nginx-debug.service /usr/lib/systemd/system/nginx.service /usr/lib64/nginx /usr/lib64/nginx/modules /usr/libexec/initscripts/legacy-actions/nginx /usr/libexec/initscripts/legacy-actions/nginx/check-reload /usr/libexec/initscripts/legacy-actions/nginx/upgrade /usr/sbin/nginx /usr/sbin/nginx-debug /usr/share/doc/nginx-1.14.0 /usr/share/doc/nginx-1.14.0/COPYRIGHT /usr/share/man/man8/nginx.8.gz /usr/share/nginx /usr/share/nginx/html /usr/share/nginx/html/50x.html /usr/share/nginx/html/index.html /var/cache/nginx /var/log/nginx
配置config檔案
vim /etc/nginx/conf.d/default.conf
然後把location / {} 裡面改為如下
location / { includeuwsgi_params; uwsgi_pass127.0.0.1:8000; uwsgi_param UWSGI_SCRIPT blog.wsgi; uwsgi_param UWSGI_CHDIR /root/myblog; indexindex.html index.htm; client_max_body_size 35m; }
uwsgi_pass 必須和uwsgi中的設定一致
UWSGI_CHDIR和UWSGI_SCRIPT 其實也跟uwsgi中差不多,一個專案路徑,一個wsgi檔案的路徑。
儲存之後,Nginx的配置就完成了。最後我們得稍微修改一下uwsgi中的一條配置。
之前在test.ini檔案中是 http = :8000
我們要改為 socket = :8000
。
重新執行uwsgi,重啟nginx。
結束。