在 Ubuntu 上使用 Nginx 部署 Flask 應用

fengglying 8年前發布 | 14K 次閱讀 Nginx Flask Web框架

來自: http://python.jobbole.com/84286/

我職業生涯的大部分都在使用微軟的架構,最近我決定走出技術的舒適區,步入開源軟件世界。我現在日常工作的項目是一個RESTful服務,這個服務需要在主流硬件上運行,且能夠按照需要進行水平拓展。為完成這項工作我決定使用Flask和Nginx。Flask是一個輕量級的Python Web框架,Nginx是一個非常穩定的Web服務器,它們在廉價硬件平臺上工作良好。

在這篇文章中我將指導你完成使用Nginx服務器托管Flask應用的安裝、配置過程。我所使用的操作系統是Ubuntu 13.04。

前提條件

在我們開始安裝Nginx及其他所需軟件之前先安裝一些前提軟件。首先,我們需要PIP與virtualenv:

sudo apt-get install python-setuptools
sudo easy_install pip
sudo pip install virtualenv
sudoapt-getinstallpython-setuptools
sudoeasy_installpip
sudopipinstallvirtualenv

使用apt-get安裝Nginx的話,我們需要添加Nginx庫到apt-get source中:

sudo add-apt-repository ppa:nginx/stable
sudoadd-apt-repositoryppa:nginx/stable

注意:如果“add-apt-repository”命令在你的Ubuntu版本中不存在的話,你需要安裝“ software-properties-common ”包,使用命令:sudo apt-get software-properties-common (感謝get_with_it在評論中提到)

升級已有的包,確保系統上有uWSGI所需的編譯器和工具:

sudo apt-get update
sudoapt-getupdate

Nginx

安裝并運行Nginx:

sudo apt-get install nginx
sudo /etc/init.d/nginx start
sudoapt-getinstallnginx
sudo /etc/init.d/nginxstart

Nginx是一個提供靜態文件訪問的web服務,然而,它不能直接執行托管Python應用程序,而uWSGI解決了這個問題。讓我們先安裝uWSGI,稍候再配置Nginx和uWSGI之間的交互。

sudo pip install uwsgi
sudopipinstalluwsgi

里程碑 #1

打開瀏覽器訪問你的服務器,你應該能看到Nginx歡迎頁:

示例應用

我們將托管的應用是經典的“Hello, world!”。這個應用只有一個頁面,已經猜到頁面上將有什么內容了吧。將所有應用相關的文件存放在/var/www/demoapp文件夾中。下面創建這個文件夾并在其中初始化一個虛擬環境:

sudo mkdir /var/www
sudo mkdir /var/www/demoapp
sudomkdir /var/www
sudomkdir /var/www/demoapp

由于我們使用root權限創建了這個文件夾,它目前歸root用戶所有,讓我們更改它的所有權給你登錄的用戶(我的例子中是ubuntu)

sudo chown -R ubuntu:ubuntu /var/www/demoapp/
sudochown -R ubuntu:ubuntu /var/www/demoapp/

創建并激活一個虛擬環境,在其中安裝Flask:

cd /var/www/demoapp
virtualenv venv
. venv/bin/activate
pip install flask
cd /var/www/demoapp
virtualenvvenv
. venv/bin/activate
pipinstallflask

使用下面的代碼創建hello.py文件:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8080)
fromflaskimportFlask
app = Flask(__name__)
 
@app.route("/")
defhello():
    return "Hello World!"
 
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8080)

里程碑 #2

讓我們執行我們剛創建的腳本:

python hello.py
pythonhello.py

現在你可以通過瀏覽器訪問你服務器的8080端口,看,應用生效了:

注意:因為80端口已被Nginx使用,這里我使用8080端口。

現在應用是由Flask內置的web服務托管的,對于開發和調試這確實是個不錯的工具,但不推薦在生產環境中使用。讓我們配置Nginx來挑起這個重擔吧。

配置Nginx

首先刪除掉Nginx的默認配置文件:

sudo rm /etc/nginx/sites-enabled/default
sudorm /etc/nginx/sites-enabled/default

注意:如果你安裝了其他版本的Nginx,默認配置文件可能在/etc/nginx/conf.d文件夾下

創建一個我們應用使用的新配置文件 /var/www/demoapp/demoapp_nginx.conf

server {
    listen      80;
    server_name localhost;
    charset     utf-8;
    client_max_body_size 75M;

    location / { try_files $uri @yourapplication; }
    location @yourapplication {
        include uwsgi_params;
        uwsgi_pass unix:/var/www/demoapp/demoapp_uwsgi.sock;
    }
}
server {
    listen      80;
    server_namelocalhost;
    charset    utf-8;
    client_max_body_size 75M;
 
    location / { try_files $uri @yourapplication; }
    location @yourapplication {
        includeuwsgi_params;
        uwsgi_passunix:/var/www/demoapp/demoapp_uwsgi.sock;
    }
}

將剛建立的配置文件使用符號鏈接到Nginx配置文件文件夾中,重啟Nginx:

sudo ln -s /var/www/demoapp/demoapp_nginx.conf /etc/nginx/conf.d/
sudo /etc/init.d/nginx restart
sudoln -s /var/www/demoapp/demoapp_nginx.conf /etc/nginx/conf.d/
sudo /etc/init.d/nginxrestart

里程碑 #3

訪問服務器的公共ip地址,你會看到一個錯誤:

別擔心,這個錯誤是正常的,它代表Nginx已經使用了我們新創建的配置文件,但在鏈接到我們的Python應用網關uWSGI時遇到了問題。到uWSGI的鏈接在Nginx配置文件的第10行定義:

uwsgi_pass unix:/var/www/demoapp/demoapp_uwsgi.sock;
uwsgi_passunix:/var/www/demoapp/demoapp_uwsgi.sock;

這代表Nginx和uWSGI之間的鏈接是通過一個socket文件,這個文件位于 /var/www/demoapp/demoapp_uwsgi.sock 。因為我們還沒有配置uWSGI,所以這個文件還不存在,因此Nginx返回“bad gateway”錯誤,讓我們馬上修正它吧。

配置uWSGI

創建一個新的uWSGI配置文件 /var/www/demoapp/demoapp_uwsgi.ini

[uwsgi]
#application's base folder
base = /var/www/demoapp

#python module to import
app = hello
module = %(app)

home = %(base)/venv
pythonpath = %(base)

#socket file's location
socket = /var/www/demoapp/%n.sock

#permissions for the socket file
chmod-socket    = 666

#the variable that holds a flask application inside the module imported at line #6
callable = app

#location of log files
logto = /var/log/uwsgi/%n.log
[uwsgi]
#application's base folder
base = /var/www/demoapp
 
#python module to import
app = hello
module = %(app)
 
home = %(base)/venv
pythonpath = %(base)
 
#socket file's location
socket = /var/www/demoapp/%n.sock
 
#permissions for the socket file
chmod-socket    = 666
 
#the variable that holds a flask application inside the module imported at line #6
callable = app
 
#location of log files
logto = /var/log/uwsgi/%n.log

創建一個新文件夾存放uWSGI日志,更改文件夾的所有權:

sudo mkdir -p /var/log/uwsgi
sudo chown -R ubuntu:ubuntu /var/log/uwsgi
sudomkdir -p /var/log/uwsgi
sudochown -R ubuntu:ubuntu /var/log/uwsgi

里程碑 #4

執行uWSGI,用新創建的配置文件作為參數:

uwsgi --ini /var/www/demoapp/demoapp_uwsgi.ini
uwsgi --ini /var/www/demoapp/demoapp_uwsgi.ini

接下來訪問你的服務器,現在Nginx可以連接到uWSGI進程了:

我們現在基本完成了,唯一剩下的事情是配置uWSGI在后臺運行,這是uWSGI Emperor的職責。

uWSGI Emperor

uWSGI Emperor (很拉風的名字,是不?) 負責讀取配置文件并且生成uWSGI進程來執行它們。創建一個初始配置來運行emperor - /etc/init/uwsgi.conf

description "uWSGI"
start on runlevel [2345]
stop on runlevel [06]
respawn

env UWSGI=/usr/local/bin/uwsgi
env LOGTO=/var/log/uwsgi/emperor.log

exec $UWSGI --master --emperor /etc/uwsgi/vassals --die-on-term --uid www-data --gid www-data --logto $LOGTO
description "uWSGI"
startonrunlevel [2345]
stoponrunlevel [06]
respawn
 
envUWSGI=/usr/local/bin/uwsgi
envLOGTO=/var/log/uwsgi/emperor.log
 
exec $UWSGI --master --emperor /etc/uwsgi/vassals --die-on-term --uidwww-data --gidwww-data --logto $LOGTO

最后一行運行uWSGI守護進程并讓它到 /etc/uwsgi/vassals 文件夾查找配置文件。創建這個文件夾,在其中建立一個到鏈到我們剛創建配置文件的符號鏈接。

sudo mkdir /etc/uwsgi
sudomkdir /etc/uwsgi

同時,最后一行說明用來運行守護進程的用戶是www-data。為簡單起見,將這個用戶設置成應用和日志文件夾的所有者。

sudo chown -R www-data:www-data /var/www/demoapp/
sudo chown -R www-data:www-data /var/log/uwsgi/
sudochown -R www-data:www-data /var/www/demoapp/
sudochown -R www-data:www-data /var/log/uwsgi/

注意:我們先前安裝的Nginx版本使用“www-data”這個用戶來運行Nginx,其他Nginx版本的可能使用“Nginx ”這個替代用戶

由于Nginx和uWSGI都由同一個用戶運行,我們可以在uWSGI配置中添加一個安全提升項。打開uWSGI配置文件,將chmod-socket值由 666 更改為 644

...
#permissions for the socket file
chmod-socket    = 644
...
#permissions for the socket file
chmod-socket    = 644

現在我們可以運行uWSGI了:

sudo start uwsgi
sudostartuwsgi

最后,Nginx和uWSGI被配置成啟動后立即對外提供我們的應用服務。

問題解決

如果出現錯誤的話,第一個檢查的地方是日志文件。Nginx默認將錯誤信息寫到 /var/log/nginx/errors.log 文件。

我們已經配置了uWSGI emperor將日志寫到 /var/log/uwsgi/emperor.log 。這個文件夾還包含著每個配置應用的單獨日志。我們的例子是 - /var/log/uwsgi/demoapp_uwsgi.log

靜態文件

如果你的應用提供靜態文件的話,將下面的規則添加到 demoapp_nginx.conf 文件:

location /static {
    root /var/www/demoapp/;
}
location /static {
    root /var/www/demoapp/;
}

上面配置的結果就是所有在 /var/www/demoapp/static 文件夾中的文件將由 提供 Nginx對外服務 (謝謝Bastianh指出)

托管多個應用

如果你想在一臺服務器上托管多個Flask應用,為每個應用創建一個單獨的文件夾,像我們前面所做的一樣,創建Nginx及uWSGI配置文件到應用文件夾的符號鏈接。

使用Distribute部署應用

使用 distribute 部署Flask應用的話,首先,按照 Flask文檔 里的步驟將應用轉化成package,然后復制distribute通用安裝包到服務器上,使用虛擬環境中的Python來安裝它。如下:

python setup.py install
pythonsetup.pyinstall

最后且同樣重要的是,uwsgi配置里應用屬性的值要設置成包含Flask應用的包的名稱。

</div>

 本文由用戶 fengglying 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!