部署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

完成

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

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容