使用Nginx+Uwsgi部署Python Flask項目
第一次用Flask做Web(也是第一次用Python做Web),在部署的時候遇到了不少問題,現在將過程就下來,供在這方面也有疑惑的人參考.(PS:使用Apache+mod_wsgi部署模式的可以參考另一個博主的這篇文章:http://blog.elnmp.com/post/python/apache-mod_wsgi-flask-pipenvxiang-mu-bu-shu)
項目及服務器環境:
Python版本:3.6.5 Flask版本:1.0.2 服務器版本:CentOS 7.4 Nginx與Uwsgi版本皆為目前最新
部署開始
Web項目
虛擬環境
為了防止Python包的版本之間起沖突,我們需要使用虛擬環境將各個項目隔離開來,一般對於這種情況網上的教程都會選擇用原生的virtualenv,但是這裏推薦一個超好用的第三方工具,據說也是Python官方推薦的虛擬環境管理工具,名字叫pipenv,使用方法自行百度,安裝方法如下:
pip install pipenv
安裝完成後,進入Flask項目根目錄,使用pipenv創建虛擬環境,值得一提的是,pipenv不一定要用正規的install命令來創建環境,使用進入虛擬環境shell的命令也一樣可以,pipenv會自動在虛擬環境列表中匹配當前項目的虛擬環境,如果找不到則會自動幫你新創建一個,具體如下:
[[email protected] Fisher] pipenv shell Creating a virtualenv for this project… Using /usr/local/bin/python3.6 (3.6.5) to create virtualenv… Spawning environment shell (/bin/bash). Use ‘exit‘ to leave. . /home/shenghun/.local/share/virtualenvs/Fisher-kuuv-2eR/bin/activate [[email protected] Fisher] ./home/shenghun/.local/share/virtualenvs/Fisher-kuuv-2eR/bin/activate (Fisher-kuuv-2eR) [[email protected]]
之後,由於虛擬環境間相互獨立.因此需要重新安裝一下包否則Python找不到包會造成程序崩潰,另外,由於pipenv生成的包統一會放在一個地方,和原生的virtualenv直接放在項目根目錄不一樣,所以註意記錄下虛擬環境的地址,之後在配置Uwsgi和Nginx的時候用的上,地址為".home/shenghun/.local/share/virtualenvs/Fisher-kuuv-2eR",問我在哪看?你猜啊(~ ̄▽ ̄)~
Uwsgi
Uwsgi是一個Web服務器,具體信息就不再贅述了,自己找度娘,要使用Uwsgi,首先需要安裝Python中的Uwsgi包,最好在全局環境和虛擬環境中都裝上(起碼我是這樣的,如果不都裝上會發生什麽我也不知道),但需要註意的一點是,Uwsgi需要一些其他環境的支持,因此在安裝Uwsgi前要把先行條件準備好:
yum -y install gcc gcc-c++ zlib zlib-devel openssl openssl-devel pcre pcre-devel GeoIP gd libXpm libxslt sqlite-devel
完成之後,再使用pip install uwsgi(虛擬環境中使用pipenv install)安裝Uwsgi.
裝完Uwsgi,我們還要在項目根目錄下創建一個Uwsgi配置文件,實際上Uwsgi可以用命令使其帶參數啟動,但有了配置文件就不用每次寫一大串命令了,為了方便,我直接把文件命名為uwsgi.ini, 大致配置如下:
[uwsgi] # Http access port. # If this option comes into effect, we can visit our web site on http://[our IP]:[Port] # http=:5001 # Uwsgi‘s ip and port when it is loaded by Nginx socket = 127.0.0.1:5001 # Point to the main directory of the Web Site chdir = / home / Servers_Nginx / Fisher / # Setting up a virtual environment virtualenv = / root /.local / share / virtualenvs / Fisher - e_ddg0zZ # Python startup file wsgi - file = fisher.py # The application variable of Python Flask Core Oject callable = app # The maximum numbers of Processes processes = 1 # The maximum numbers of Threads threads = 2
其他的配置沒什麽好說的,英語稍微有點水平的都能看懂寫的什麽,重點在http和socket上,這兩個配置是不能同時存在的(起碼在我印象中),http是用來使外網能直接訪問Uwsgi的,而socket是用來和Nginx通信的,Nginx獲取到外網的請求後,就通過這個地址轉發給Uwsgi處理,socket的用法在下面Nginx的配置文件中會看到.
配置好了之後,可以用uwsgi uwsgi.ini命令查看是否成功配置,如果沒問題,則會有以下啟動信息(只截取一部分,事實上有老大一串):
[uWSGI] getting INI configuration from uwsgi.ini *** Starting uWSGI 2.0.17 (64bit) on [Tue Jul 3 22:42:15 2018] *** compiled with version: 4.8.5 20150623 (Red Hat 4.8.5-16) on 02 July 2018 14:12:13 os: Linux-3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 nodename: shenghun machine: x86_64 clock source: unix pcre jit disabled detected number of CPU cores: 1 current working directory: /home/Servers_Nginx/Fisher detected binary path: /usr/bin/uwsgi uWSGI running as root, you can use --uid/--gid/--chroot options Ctrl+C結束運行,開始Nginx的安裝與配置 Nginx Nginx是什麽
雖然只有Uwsgi也可以直接部署項目,但是為了安全,需要Nginx來進行請求代理,眾所周知類似於學校之類的內部計算機通過信息中心服務器訪問外網的行為稱為正向代理,所有的訪問請求都由中央服務器代理,此時正常情況下外網是不知道你的計算機的地址的;而Nginx的作用就是實現反向代理,正向代理代理的是內部計算機,而反向代理代理的是內部服務器,正是有Nginx存在,Uwsgi的真正接口才不會暴露在網絡上,服務器的安全才有了一定的保障(當然,惡意攻擊另說),此外,Nginx還自帶防DDoS攻擊機制.可以說日常使用是非常省心了.
Nginx安裝
關於Nginx的安裝,有很多種方法,這裏選擇了yum源安裝(其他linux發行版也有類似的安裝方法).
yum源配置
首先在/etc/yum.repo.d/文件夾下添加yum源,名字就叫做Nginx.repo吧(為了方便懶得起名)
[[email protected] yum.repos.d] vim Nginx.repo
輸入以上命令進入文件編輯,完成相關配置,對於yum源的配置官方文檔是這麽說的:
其中baseurl中的OS需要改成自己的系統名,OSRELEASE需要改成系統的發型版本號.完成之後配置文件如下:
[Nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/7/$basearch/ gpgcheck=0 enabled=1
配置完成後還沒完,需要使用一下命令重新加載yum源:
[[email protected] yum.repos.d] yum clear all
[[email protected] yum.repos.d] yum makecache
出現以下信息即為成功:
其他系統添加源方法可以到http://nginx.org/en/linux_packages.html中查看,我就不一一贅述了.
yum源安裝
之後就很簡單了,直接yum install nginx就行,如果不想提示是否繼續可以再加上-y參數像這樣:
[[email protected] /] yum -y install nginx
回車以後會自動安裝nginx,稍等一會,等屏幕出現successful install nginx就可以了,由於我這裏已經安裝成功了,所以是這樣的:
另外說一下,我這裏選擇yum除了安裝方便外,還有一個很重要的因素,那就是yum安裝可以自動將Nginx加入系統服務,不用再傻傻地到安裝目錄下適用./nginx或者一大串路徑啟動了,直接用systemctl(CentOS 6使用service)的start,stop,restart就可以完成啟動,停止,重載,甚至可以用systemctl status nginx就可以直接看到nginx啟動狀態,非常方便:
Nginx配置
Nginx安裝完成後,接下來就需要配置虛擬主機用以部署項目了,進入nginx配置文件目錄,如果不知道在哪的可以使用一下方法找到:
[[email protected] /] whereis nginx
第一個路徑是啟動快捷鍵,第二個Nginx依賴的一下庫,第四個是nginx項目目錄,第五個看名字就知道應該是文檔之類的,所以配置文件目錄是/etc/nginx沒跑了.
查看文件夾目錄:
編輯主配置文件
主配置文件就是nginx.conf,使用vim進入編輯:
新文件的worker_processes的值是1,這裏最好改成auto,這樣nginx可以根據需要自動匹配工作進程數,其他的就不用動了,關於虛擬主機的配置在最後一行有,意思就是每次啟動nginx的時候自動載入/etc/nginx/conf.d/下的全部.conf文件,至於這些.conf文件是什麽,等下就知道了.
新建虛擬主機
進入conf.d文件夾後查看文件夾目錄發現,這裏只有一個default.conf,使用vim查看一下:
原來這就是虛擬主機的配置文件,默認監聽的是80端口,如果80端口已經有進程占用了會啟動失敗,遇到啟動失敗的情況可以試著更改一下監聽端口,此時啟動Nginx就已經可以訪問到歡迎頁面了,這裏我們改成6000端口試試:
[[email protected] conf.d] systemctl restart nginx
在瀏覽器中使用http://IP地址:端口號查看一下
成功啟動!
接下來就是正式的虛擬機配置了,在conf.d文件夾下新建一個.conf文件,名字就用項目名吧(方便些),使用vim進入,配置如下:
upstream flask{ server 127.0.0.1:5001; } # Virtual host, with this option, we can visit our web site on server_name. # If the server_name is an ip address and we has configured a DNS, # we can also use the corresponding domain name. server { listen 5000; # domain name or ip address server_name www.shenghuntianlang.xin; charset utf-8; # the web site resources path location / { include uwsgi_params; # The inner address whilch point to Uwsgi. all the requests will resend to Uwsgo to resolve. # If we has configured the upstream options, we can fill in the upstream name instead. uwsgi_pass flask; # If the following options are already exists in ‘Uwsgi.ini‘.these options can be ignored. # Configure Uwsgi‘s running environment path. # uwsgi_param UWSGI_PYHOME /root/.local/share/virtualenvs/Fisher-e_ddg0zZ; # Configure the main directory of web site # uwsgi_param UWSGI_CHDIR /home/Servers_Nginx/Fisher; # Configure the Flask Core Object # uwsgi_param UWSGI_SCRIPT fisher:app; } }
每個選項的作用都寫在註釋中了,不過還是稍微解釋一下吧,首先upstream是用來做負載均衡的Nginx在接收到請求後,會將請求轉發到其中的服務器上,這裏的每一個server就是一個服務器,另外,127.0.0.1:5001是不是有點熟悉?是滴,就是上面配置的Uwsgi的socket,Nginx通過socket連接Uwsgi把請求發送到Uwsgi服務器,Uwsgi處理後把響應反饋給Nginx再由Nginx轉發給客戶端,使用upstream時只需要將設置的upstream名(這裏是flask)填入server中的location中的uwsgi_pass就可以了,另外也可以不配置upstream,直接把Uwsgi的socket填入uwsgi_pass也行得通,
其次是server的location,其中的include是加載uwsgi_params文件(本身在Nginx配置目錄/etc/nginx下就有一個,可以看上面的截圖),這個文件是用來確定Uwsgi的運行信息的,由於Nginx配置目錄下有現成的,所以就不用管了,直接指向那個文件即可(如果有需要需要置頂到特定文件則需要填入絕對地址),還有就是下面全部註釋掉的配置信息,這些是用來額外配置Uwsgi的啟動配置的,如果Uwsgi的.ini文件裏面有相關配置(虛擬環境啊核心APP對象啊什麽的)就不需要了,因此這裏只給了兩個配置,uwsg_params文件和Uwsgi的socket.
到此虛擬環境就配置成功了,另外配置完Nginx之後可以使用nginx -t測試配置文件,如果成功就萬事大吉,有錯誤的話會有相關信息彈出,之後使用systemctl restart nginx重啟Nginx,就可以用配置的server_name加端口訪問Nginx了.
雜記
※查看端口號監聽狀態與關閉監聽進程
查看端口號
[[email protected] /] netstat -ntlp | grep 5000
tcp 0 0 0.0.0.0:5000 0.0.0.0:* LISTEN 10316/nginx: master
通過pid關閉監聽進程
[[email protected] /] kill -9 pid
使用場景:端口被占用,服務起不來
註:其中pid是監聽進程的名字的‘/‘前面的那個數字
※查看服務名相關運行信息並關閉
查看服務名相關運行信息
[[email protected] /] ps -ef | grep nginx root 10316 1 0 10:37 ? 00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 10317 10316 0 10:37 ? 00:00:00 nginx: worker process root 10589 8661 0 11:22 pts/6 00:00:00 grep --color=auto nginx
關閉此服務
[[email protected] /] pkill -9 nginx
使用場景:同名服務已存在,需要重新啟動新服務
註:此方式是關閉此服務名下的所有進程,如果需要精準關閉,可以使用通過pid方式,此外,就算關閉所有進程,仍然會有一個名為‘grep --color=auto nginx‘的進程存在(Uwsgi以及其他一些服務也是),屬於正常情況,不比特別在意
※Nginx和Uwsgi無法同時啟動
解決方法:Nginx的監聽端口不要和Uwsgi的端口一樣,不然會起沖突導致其中一個起不來.
※自定義執行命令
編輯用戶目錄下的.bashrc可以自定義執行命令:
[[email protected] ~] vim .bashrc
編輯完成後保存退出,並使.bashrc生效:
[[email protected] ~] source .bashrc
此後就可以使用新命令了,另外可以用alias臨時定義執行命令,只不過是暫時的,退出終端之後就沒了.
※※切換程序前後臺並在退出終端(xshell之類的工具同理)後繼續執行
切換前後臺
執行一個命令:
[[email protected] Fisher] uwsgi uwsgi.ini
此時Uwsgi會在前臺執行,在當前終端中無法進行其他操作,
切換到後臺,先Ctrl+Z掛起程序
然後使用:
[[email protected] Fisher] bg
此時程序在後臺執行,終端解鎖,可以進行其他操作,使用fg可以將後臺的程序調到前臺
其他用法可以自行找度娘
此外,即使程序在後臺運行,一旦退出終端,程序進程仍舊會被系統kill掉,可以使用tmux工具:
創建新會話:
[[email protected] ~] tmux new -s 會話名(自定)
之後會進入新回話,底部會有綠色提示
在這裏面運行程序程序執行後,使用Ctrl+b | d(先輸入Ctrl+b,再輸入單個d)退出當前會話,此時會回到前面的終端環境
使用Ctrl+b | s可以查看所有會話
進入先前會話
[[email protected] ~] tmux attach -t uwsgi-fisher
使用Nginx+Uwsgi部署Python Flask項目