部署Django REST Framework服務(Nginx + uWSGI + Django)

初衷

在探索了DRF之后(兩篇:Django REST Framework Quickstart 項目解讀 - 簡書Django REST Framework 實現業務 api 并自動文檔化 - 簡書 ) ,是時候上線到一個正式的服務上了,也為了后面更好地實現一些想法。

準備服務器

一開始想到的還是阿里云主機,之前也用過一段時間,但是說實話,價格貴了點。因為現在只是實現一些自己的小想法,所以選擇了性價比稍微高一些的國外vps。根據大家的推薦,選擇了vultr的5刀版本,已經足夠使用了,支持支付寶付款,所以特別方便。

image.png

但是這個過程還是有些問題,比如說節點的IP可能會被墻,解決的方法是,不斷地試著換實例,一般能換到訪問正常的節點。但是這種墻法還是比較暴力的,使用了tcp截斷,你會發現能ping通,但是不能建立tcp連接。

VPS啟動ok之后,建立一個新用戶,避免總是使用root賬號去登錄或者去操作,并在新用戶上加入sshkey,方便今后ssh連接。之后就可以綁定域名了,使用vps的另一個好處是,不需要備案。

安裝nginx

直接安裝便可,我看版本也不低。

apt-get install nginx

主配置文件:/etc/nginx/nginx.conf

啟動nginx服務:

sudo service nginx start

默認情況下,使用域名測試訪問nginx是否啟動正常便可。

安裝python3+virtualenv環境

因為我選擇了ubuntu18.04的系統,好像默認就預裝了python3.6,所以這個可以跳過了。

安裝virtualenv:

sudo apt-get install python3-pip
pip3 install virtualenv

高版本的ubuntu可能會把virtualenv安裝到$HOME/.local/bin/下面,所以需要把路徑添加到PATH里。

建立django運行的虛擬環境并安裝django等

virtualenv -p /usr/bin/python3 env3
pip install djangorestframework django pymysql coreapi pygments markdown
git clone https://github.com/roubo/rouboApi.git

安裝mysql

sudo apt-get install mysql-server
## 查看默認用戶名密碼
sudo cat /etc/mysql/debian.cnf 
## 登錄
mysql -u xxxx -p yyyy

修改密碼:

mysql> use mysql;
Database changed

mysql> update user set plugin='mysql_native_password' where user='root';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set authentication_string=password('xxx') where user='root';
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 1

mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

建立業務相關的數據庫

create database rouboinfo default charset utf8 collate utf8_general_ci;

django項目數據庫初始化

python manage.py makemigrations
python manage.py migrate

測試Django端服務

啟動django調試服務

python manage.py runserver

測試接口,本地訪問ok(django服務本身不需要對外網提供訪問服務,最終通過nginx分發)

?  ~ curl -i 'http://127.0.0.1:8000/rouboapi/v1/report/'
HTTP/1.1 400 Bad Request
Date: Thu, 06 Sep 2018 03:42:23 GMT
Server: WSGIServer/0.2 CPython/3.6.5
Content-Type: application/json
Vary: Accept
Allow: GET, HEAD, OPTIONS
X-Frame-Options: SAMEORIGIN
Content-Length: 124

{"report_type":["This field is required."],"device_id":["This field is required."],"ip_address":["This field is required."]}%

橋接nginx和django

現在nginx和django的服務都已經ok,接下來就是怎么打通兩者,我們之前提到過uWSGI。這里我們來了解下WSGI協議的事情。

WSGI協議

WSGI(Web Server GateWay Interface),這個是一套協議,用于連接web server 和 web application。他的出現也是人們對Web的server和application解耦的需求。舉個例子,比如我們要完成兩個api接口,我們可以很作地選擇兩個web application框架,比如Django和Flask,一個api分別使用一種框架,而對客戶端來說,可以完全無感。WSGI協議在這里就起到了橋接作用,可以實現多Server對單application,或者當server對多application。

uWSGI應用

uWSGI是一個應用,他可做為兩種角色:

  • 當在 Nginx + uWSGI + Django 場景下,他是中間件。
  • 當在 uWSGI + Django 的場景下, 他是Web Server。

當為中間件角色時,需要用到其uwsgi協議,Nginx一般通過該協議與uWSGI連接。這里的uwsgi協議的作用,我們可以簡單地理解為,如何高效地傳遞request和response便好。而uWSGI中間件的作用,我們也可以簡單地理解為,作為一個網關屏蔽各web application之間的協議、開發語言等差異,并且高效地管理著各種并發、負載均衡、日志等。

那為什么要選擇 Nginx + uWSGI + Django 這種方式呢? 其實是一個物盡其用的理由。nginx有如下優點:

1、安全,客戶端對Web服務器的訪問需要先經過反向代理服務器。這樣可以防止外部程序對Web服務器的直接攻擊。
2、負載均衡,反向代理服務器可以根據Web服務器的負載情況,動態地把HTTP請求交給不同的Web服務器來處理,前提是要有多個Web服務器。
3、提升Web服務器的IO性能。一個HTTP請求的數據,從客戶端傳輸給服務器,是需要時間的,例如N秒,如果直接傳給Web服務器,Web服務器就需要讓一個進程阻塞N秒,來接收IO,這樣會降低Web服務器的性能。如果使用反向代理服務器,先讓反向代理服務器接收完整個HTTP請求,再把請求發給Web服務器,就能提升Web服務器的性能。還有一些靜態文件的請求,可以直接交給反向代理來處理,不需要經過Web服務器。

安裝和配置uWSGI和Nginx

注意我還是將應用安裝在虛擬環境中。

首先在非虛擬環境中安裝全局依賴的包:

sudo apt-get install python3.6-dev build-essential

在虛擬環境中安裝uWSGI

pip install uwsgi

測試uWSGI + django是否運行正常,在項目路徑下運行并測試8080端口是否正常:

uwsgi --http :8080 --module rouboinfo.wsgi

如果這一切正常,那就可以開始配置nginx接入uWSGI了。

增加nginx配置,rouboapi.conf:

# the upstream component nginx needs to connect to
upstream django {
    server unix:///data/django/rouboApi/rouboapi.scok; # for a file socket
    #server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on
    listen      80;
    # the domain name it will serve for
    server_name app.airoubo.com; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    # Django media
    #location /media  {
    #    alias /path/to/your/mysite/media;  # your Django project's media files - amend as required
    #}

    #location /static {
    #    alias /path/to/your/mysite/static; # your Django project's static files - amend as required
    #}

    # Finally, send all non-media requests to the Django server.
    location /roubo {
        uwsgi_pass  django;
        include     /etc/nginx/uwsgi_params; # the uwsgi_params file you installed
    }
}

使用配置文件運行uWSGI:

# mysite_uwsgi.ini file
[uwsgi]

# Django-related settings
# the base directory (full path)
chdir           = /data/django/rouboApi
# Django's wsgi file
module          = rouboinfo.wsgi
# the virtualenv (full path)
home            = /data/django/env3

# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 10
# the socket (use the full path to be safe
socket          = /data/django/rouboApi/rouboapi.scok
# ... with appropriate permissions - may be needed
chmod-socket    = 666
# clear environment on exit
vacuum          = true
# 在虛擬環境下執行
uwsgi --ini rouboapi.ini

至此,我們發現接口訪問已經正常,nginx <-> uWSGI <-> django 的通路已經ok了。但是我們來看下Django REST Framework 的文檔頁面的效果:


image.png

發現所有樣式都丟失了。。這是因為我們的nginx配置里并沒有將靜態文件暴露給客戶端:

    #location /static {
    #    alias /path/to/your/mysite/static; # your Django project's static files - amend as required
    #}

Django的靜態文件收集和Nginx的靜態文件配置

上面說的文檔頁面的樣式丟失問題,我們可以看下nginx的error log:

2018/09/06 07:41:27 [error] 14754#14754: *23 open() "/usr/share/nginx/html/static/rest_framework/js/default.js" failed (2: No such file or directory), client: 116.231.148.176, server: app.airoubo.com, request: "GET /static/rest_framework/js/default.js HTTP/1.1", host: "app.airoubo.com", referrer: "http://app.airoubo.com/roubo/rouboapi/v1/report/"

也就是rest下的js文件是404。

收集Django的靜態文件到指定目錄

Settings.py中加入收集路徑:

STATIC_ROOT = os.path.join(BASE_DIR, "static/")

在項目下執行:

python manage.py collectstatic

執行后在項目目錄下可以看到static文件夾:

static
|-- admin
|   |-- css
|   |-- fonts
|   |-- img
|   `-- js
`-- rest_framework
    |-- css
    |-- docs
    |-- fonts
    |-- img
    `-- js

配置nginx,放開靜態文件,修改nginx配置文件中的static如下:

location /static {
        alias /data/django/rouboApi/static; 
}

重啟nginx,查看效果,完工:

image.png

完成

后端部署完成,后面可以愉快地添加新接口新服務了。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,698評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,202評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,742評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,580評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,297評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,688評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,693評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,875評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,438評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,183評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,384評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,931評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,612評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,022評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,297評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,093評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,330評論 2 377

推薦閱讀更多精彩內容