Python系列之-Nginx+uWSGI+virtualenv多項目部署

配置virtualenv及Python環境

一、新建獨立運行環境,命名爲venvjavascript

[root@vultr ~]# mkdir projects # 測試的項目總目錄
[root@vultr ~]# pip3 install virtualenv
[root@vultr ~]# cd projects
[root@vultr projects]# virtualenv venv --python=python3 --no-site-packages

--python:指定Python版本
--no-site-packages:不復制系統已安裝Python包
複製代碼

二、激活虛擬環境php

[root@vultr projects]# source venv/bin/activate
複製代碼

執行後命令提示符前面會出現一個venv,變成(venv)[root@vultr opt]#,退出虛擬環境執行deactivate便可。css

三、安裝項目依賴:pip3 install, 在虛擬環境中安裝的包,不會對系統環境形成影響。html

Django項目配置

一、上傳Django項目: Hello項目java

目錄結構:
Hello/
    apps/
    Hello/
    manage.py
複製代碼

二、配置項目的數據庫信息:vi Hello/Hello/settings.pypython

若是是遠程服務器,須要修改setting.py文件中的ALLOWED_HOSTS:
ALLOWED_HOSTS = ['*']
複製代碼

三、數據遷移mysql

(venv)[root@vultr Hello]# python3 manage.py makemigrations
(venv)[root@vultr Hello]# python3 manage.py migrate
複製代碼

執行python3 manage.py makemigrations的一些錯誤處理:
由於版本問題,可能會提示如下兩個問題 參考文檔:blog.csdn.net/weixin_3312… 問題一:linux

django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.
複製代碼

即便在__init__.py文件裏添加了以下語句,依然會提示這個錯誤,這裏有兩種辦法,一種是使用低版本的Django,一種是修改一些文件,這裏採用第二種。以下:nginx

#__init__.py
import pymysql
pymysql.install_as_MySQLdb()
複製代碼
[root@vultr ~]# vi /opt/MiniProgram/Notes/venv/lib/python3.6/site-packages/django/db/backends/mysql/base.py # 路徑可能不一樣,看提示信息

將如下語句註釋:
if version < (1, 3, 3):
     raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
複製代碼

繼續執行python3 manage.py makemigrations還有一個錯誤:c++

AttributeError: ‘str’ object has no attribute ‘decode’
複製代碼

這裏,修改修改operations.py,一樣在錯誤信息前有這個文件的路徑

[root@vltur ~]# vi /opt/MiniProgram/Notes/venv/lib/python3.6/site-packages/django/db/backends/mysql/operations.py

將如下內容
query = getattr(cursor, '_executed', None)
if query is not None:
    query = query.decode(errors='replace')
return query

將query.decode修改成query.encode
query = query.encode(errors='replace')
複製代碼

四、收集靜態文件:vi Hello/Hello/settings.py

STATIC_ROOT = os.path.join(BASE_DIR, "static")
複製代碼

:wq保存後,執行

(venv)[root@vultr Hello]# python3 manage.py collectstatic --noinput
複製代碼

五、用runserver啓動項目,看是否正常運行

(venv)[root@vultr Hello]# python3 manage.py runserver 0.0.0.0:8088
複製代碼

uWSGI配置

deactivate退出虛擬環境
一、安裝uWSGI

[root@vultr Hello]# pip3 install uWSGI
複製代碼

二、命令行運行測試
項目目錄Hello下,執行如下命令:

[root@vultr Hello]# uwsgi --http ip:端口 --home /root/env/ --file Hello/wsgi.py --static-map=/static=static

--home:指定虛擬環境的目錄
wsgi.py:Django建立項目時生成的文件
複製代碼

若是訪問URL正常,說明Python虛擬環境和uWSGI沒有問題.
說明: 使用阿里雲服務器ECS,這裏執行不經過,ip使用公網IP和私網IP都提示bind(): Cannot assign requested address [core/socket.c line 769]。

三、使用ini配置文件來啓動uWSGI
我習慣性建立projects目錄,目錄結構以下:

/root/projects/
            script/     --> 存放uWSGI相關的文件,例如uwsgi.ini, uwsgi.pid...
            Hello/  --> 項目目錄
                    apps/  --> 應用程序目錄
                    Hello/  --> settings.py等文件所在目錄
                    static/
            env/  --> 虛擬環境目錄
複製代碼
[root@vultr projects]# vi script/uwsgi.ini

[uwsgi]
# 項目目錄
chdir=/root/projects/Hello/
# 虛擬環境目錄
home=/root/projects/venv/
# 啓動uwsgi的用戶名和用戶組
uid=root
gid=root
# 指定項目的application
module=Hello.wsgi:application
# 指定sock的文件路徑
socket=/root/projects/script/uwsgi.sock
# 啓用主進程
master=true
# 進程個數
workers=5
pidfile=/root/projects/script/uwsgi.pid
# 自動移除unix Socket和pid文件當服務中止的時候
vacuum=true
# 序列化接受的內容,若是可能的話
thunder-lock=true
# 啓用線程
enable-threads=true
# 設置自中斷時間
harakiri=30
# 設置緩衝
post-buffering=4096
# 設置日誌目錄
daemonize=/root/projects/script/uwsgi.log
複製代碼

四、後臺啓動中止uWSGI的命令

[root@vultr projects]# uwsgi --ini script/uwsgi.ini # 啓動
[root@vultr projects]# uwsgi --stop script/uwsgi.pid # 中止
複製代碼

五、可能出現的問題 問題一:

no /etc/mime.types file found  # 缺乏文件
複製代碼

解決:

[root@vltur ~]# wget http://mirror.centos.org/centos/6/os/x86_64/Packages/mailcap-2.1.31-2.el6.noarch.rpm
[root@vltur ~]# rpm -ivh mailcap-2.1.31-2.el6.noarch.rpm
複製代碼

問題二:

no internal routing support, rebuild with pcre support
複製代碼

解決:

[root@vltur ~]# pip3 uninstall uwsgi
[root@vltur ~]# yum install -y pcre pcre-devel
[root@vltur ~]# pip3 install uwsgi -I --no-cache-dir 
複製代碼

-I 強制從新安裝,不使用緩存裏的, 不加-I --no-cache-dir的話,從新安裝仍是提示這個。

問題三:

bind(): Cannot assign requested address [core/socket.c line 769]
複製代碼

參考文檔:blog.csdn.net/JT31520/art… 這是用阿里雲可能會出現的問題,翻譯爲沒法分配請求的地址。但我不在uwsgi.ini指定ip和端口,我是在Nginx指定的,因此這個錯誤對我後面搭配Nginx不影響,只是單獨測試uWSGI時有問題。

Nginx配置

一、源碼安裝

  1. 裝相關的庫
[root@vultr ~]# yum -y install make zlib zlib-devel gcc-c++ libtool openssl openssl-devel
複製代碼
  1. 安裝PCRE
[root@vultr ~]# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.43.tar.gz
[root@vultr ~]# tar -zxvf pcre-8.43.tar.gz
[root@vultr ~]# cd pcre-8.43
[root@vultr ~]# ./configure --prefix=/usr/local/pcre
[root@vultr ~]# make && make install
[root@vultr ~]# /usr/local/pcre/bin/pcre-config --version # 查看是否安裝成功
8.43  # 出現8.43說明已經安裝成功
複製代碼
  1. 下載並解壓Nginx安裝包
[root@vultr ~]# wget http://nginx.org/download/nginx-1.16.0.tar.gz
[root@vultr ~]# tar -zxvf nginx-1.16.0.tar.gz
[root@vultr ~]# cd nginx-1.16.0
[root@vultr ~]# ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-pcre=/root/pcre-8.43
[root@vultr ~]# make && make install
[root@vultr ~]# /usr/local/nginx/sbin/nginx -v # 查看Nginx版本,若是顯示了版本說明安裝正常
複製代碼

注意:--with-pcre=/root/pcre-8.43須要改爲本身下載解壓的pcre源碼目錄。

三、/usr/local/nginx/conf/nginx.conf下添加,是在http{}裏

[root@vultr projects]# vi /usr/local/nginx/conf/nginx.conf 

server {
    listen 84;  # 端口
    server_name 10.129.205.183 ;  # 域名
    access_log  /usr/local/nginx/logs/access.log  main;
    charset  utf-8;
    gzip on;
    gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php application/json text/json image/jpeg image/gif image/png application/octet-stream;
    
    error_page  404           /404.html;
    error_page   500 502 503 504  /50x.html;
    # 指定項目路徑uwsgi
    location / {
        include uwsgi_params; # 加載nginx和uwsgi的通訊協議模塊
        uwsgi_connect_timeout 30; # 超時時間
        uwsgi_pass unix:/root/projects/script/uwsgi.sock;
    }
    # 指定靜態文件路徑
    location /static/ {
    alias  /root/projects/Hello/static/;
    index  index.html index.htm;
    }
}
複製代碼

啓動Nginx可能有的問題, 指的是**access_log /usr/local/nginx/logs/access.log main;**有錯:

nginx: [emerg] unknown log format "proxy_log" in /usr/local/macports/etc/nginx/nginx.conf:147
複製代碼

解決,在HTTP配置的部分,去掉log_format的註釋,以下:

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';
...後面省略
複製代碼

三、經常使用命令

[root@vultr ~]# /usr/local/nginx/sbin/nginx -s reload # 從新載入配置文件
[root@vultr ~]# /usr/local/nginx/sbin/nginx -s reopen # 重啓Nginx
[root@vultr ~]# /usr/local/nginx/sbin/nginx # 啓動Nginx
[root@vultr ~]# /usr/local/nginx/sbin/nginx -s stop # 關閉Nginx
複製代碼

也能夠將路徑添加到$PATH裏。

四、啓動與中止Nginx

  1. 檢查uWSGI是否啓動了
[root@vultr projects]# ps -ef | grep uwsgi
root      2299     1  0 06:22 ?        00:00:00 uwsgi --ini script/uwsgi.ini
root      2301  2299  0 06:22 ?        00:00:00 uwsgi --ini script/uwsgi.ini
root      2302  2299  0 06:22 ?        00:00:00 uwsgi --ini script/uwsgi.ini
root      2303  2299  0 06:22 ?        00:00:00 uwsgi --ini script/uwsgi.ini
root      2304  2299  0 06:22 ?        00:00:00 uwsgi --ini script/uwsgi.ini
root      2305  2299  0 06:22 ?        00:00:00 uwsgi --ini script/uwsgi.ini
root      2306  2299  0 06:22 ?        00:00:00 uwsgi --ini script/uwsgi.ini
root      2361  2016  0 06:32 pts/1    00:00:00 grep uwsgi
複製代碼
  1. 啓動Nginx
[root@vultr projects]# /usr/local/nginx/sbin/nginx 
複製代碼
  1. 訪問URL,見證奇蹟的時刻到了,而後...

ok,報錯了,莫慌。度娘查了502是服務器錯誤,然而前面測試了Django+uWSGI沒問題,因此最有多是在Nginx出錯了。

來,咱們查看一下Nginx的錯誤日誌文件,日誌文件在哪呢???
若是是源碼編譯安裝,那錯誤日誌在/usr/local/nginx/logs/error.log,若是是yum安裝,經過如下方式查找。

[root@vultr projects]# find / -name nginx.conf
/etc/nginx/nginx.conf
[root@vultr projects]# vi /etc/nginx/nginx.conf
複製代碼

error_log參數就是錯誤日誌文件了,讓咱們再打開error.log文件,找到最後一條記錄:

2019/05/12 06:41:43 [crit] 1514#1514: *2 connect() to unix:/root/projects/script/uwsgi.sock failed (13: Permission denied) while connecting to upstream, ...(後面省略)

複製代碼

failed (13: Permission denied) while connecting to upstream能夠看出是鏈接uwsgi.sock沒有權限???緣由是我貪圖方便,直接把項目文件以及uWSGI文件放在了/root/目錄下!!!

好,修改路徑,先中止Nginx和uWSGI,再修改路徑/root/projects/更改成/opt/projects/:

[root@vultr projects]# uwsgi --stop script/uwsgi.pid 
[root@vultr projects]# /usr/local/nginx/sbin/nginx -s stop
中止 nginx:                                               [肯定]
[root@vultr projects]# cd ..
[root@vultr ~]# mv projects /opt/
[root@vultr ~]# cd /opt/projects/
複製代碼

而後將script/uwsgi.ini和/usr/local/nginx/conf/redis.conf中關於路徑的都修改過來,修改好後,再次啓動uWSGI和Nginx:

[root@vultr projects]# uwsgi --ini script/uwsgi.ini 
[uWSGI] getting INI configuration from script/uwsgi.ini
[root@vultr projects]# /usr/local/nginx/sbin/nginx
正在啓動 nginx:                                           [肯定]
複製代碼

再次訪問URL, 訪問正常。

多項目部署

利用virtualenv能夠在服務器上配置多個Python運行環境,所以根據Nginx、uWSGI、virtualenv能夠實現一個服務器上運行多個項目,且互不干擾。

首先咱們先來了解一下Nginx+uWSGI通訊原理。

請求首先交給Nginx,若是是靜態內容Nginx就直接處理了,若是是動態內容就將請求交給uWSGI服務器,Nginx和uWSGI之間是經過Socket來通訊的,通訊協議就是/etc/nginx/conf.d/Hello.conf裏配置的uwsgi_params文件。

那麼,如今咱們來梳理一下,Nginx是怎麼知道uWSGI在哪裏?經過什麼和uWSGI作Socket通訊,回看/etc/nginx/conf.d/Hello.conf文件:

原來是根據uwsgi_pass指定了Nginx與uWSGI通訊的Socket文件路徑,看到這,就知道好辦了,一個項目配置一個uwsgi.ini文件和nginx.conf裏的一個server,那既然須要部署多個項目,那就是多個uwsgi.ini和nginx.conf裏的多個server。

好的,咱們開始測試:
一、配置虛擬環境以及測試用runserver運行Django項目是否正常。 個人目錄結構是:

opt/
    projects/
        Hello/   --> 第一個Django項目
        venv/     --> 第一個Django項目的虛擬環境
        World/   --> 第二個Django項目
        venv_1/   --> 第二個Django項目的虛擬環境
        script/  --> uwsig.ini等文件存放
複製代碼

二、配置World項目的uwsgi_w.ini文件

[root@vultr projects]# vi script/uwsgi_w.ini

[uwsgi]
# 項目目錄
chdir=/opt/projects/World/
# 虛擬環境目錄
home=/opt/projects/venv_1/
# 啓動uwsgi的用戶名和用戶組
uid=root
gid=root
# 指定項目的application
module=World.wsgi:application
# 指定sock的文件路徑
socket=/opt/projects/script/uwsgi_w.sock
# 啓用主進程
master=true
# 進程個數
workers=5
pidfile=/opt/projects/script/uwsgi_w.pid
# 自動移除unix Socket和pid文件當服務中止的時候
vacuum=true
# 序列化接受的內容,若是可能的話
thunder-lock=true
# 啓用線程
enable-threads=true
# 設置自中斷時間
harakiri=30
# 設置緩衝
post-buffering=4096
# 設置日誌目錄
daemonize=/opt/projects/script/uwsgi_w.log
複製代碼

三、配置Nginx

[root@vultr projects]# vi /usr/local/nginx/conf/nginx.conf

server {
    listen 84;  # 端口,請注意端口
    server_name 10.129.205.183 ;  # 域名
    access_log  /usr/local/nginx/logs/access.log  main;
    charset  utf-8;
    gzip on;
    gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php application/json text/json image/jpeg image/gif image/png application/octet-stream;

    error_page  404           /404.html;
    error_page   500 502 503 504  /50x.html;
    # 指定項目路徑uwsgi
    location / {
        include uwsgi_params; # 加載nginx和uwsgi的通訊協議模塊
        uwsgi_connect_timeout 30; # 超時時間
        uwsgi_pass unix:/opt/projects/script/uwsgi.sock;
    }
    # 指定靜態文件路徑
    location /static/ {
    alias  /opt/projects/Hello/static/;
    index  index.html index.htm;
    }
}

server {
    listen 86;  # 端口,請注意端口
    server_name 10.129.205.183 ;  # 域名
    access_log  /usr/local/nginx/logs/access.log  main;
    charset  utf-8;
    gzip on;
    gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php application/json text/json image/jpeg image/gif image/png application/octet-stream;

    error_page  404           /404.html;
    error_page   500 502 503 504  /50x.html;
    # 指定項目路徑uwsgi
    location / {
        include uwsgi_params; # 加載nginx和uwsgi的通訊協議模塊
        uwsgi_connect_timeout 30; # 超時時間
        uwsgi_pass unix:/opt/projects/script/uwsgi_w.sock;
    }
    # 指定靜態文件路徑
    location /static/ {
    alias  /opt/projects/World/static/;
    index  index.html index.htm;
    }
}
複製代碼

四、啓動uWSGI和Nginx,訪問兩個端口的URL。 ok,訪問正常。

一些問題:
問題一:

error] 959#0: *116 open() "/usr/local/nginx/html/favicon.ico" failed (2: No such file or directory), client: 111.68.59.75, server: 127.0.0.1, request: "GET /favicon.ico HTTP/1.1" 
複製代碼

參考文檔:blog.csdn.net/ygm_linux/a… 解決, 關閉favicon.ico不存在時記錄日誌, 在server{}中添加:

location /favicon.ico {
    log_not_found off;
    access_log off;
}
複製代碼

添加ssl證書

阿里雲有免費的我的用ssl證書,能夠去申請一個,把我的網站提高爲HTTPS,具體怎麼申請請Google吧。
一、購買ssl證書,並下載pem和key文件,將.pem和.key放置到/usr/local/nginx/cert下
二、修改nginx.conf配置文件,在HTTP{}裏添加以下配置

server {
    listen 443 ssl;
    server_name localhost;
    ssl_certificate   /usr/local/nginx/cert/2353008_www.incisor.cn.pem;
    ssl_certificate_key  /usr/local/nginx/cert/2353008_www.incisor.cn.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    location / {
     root html;
     index index.html index.htm;
    }
}
複製代碼

443是HTTPS的默認端口,個人博客就在這個端口。若是其餘端口須要添加ssl證書,就按照這個樣式添加,這些都是ssl相關配置,好比:

server {
    listen 84 ssl;
    ......省略
    ssl_certificate   /usr/local/nginx/cert/2353008_www.incisor.cn.pem;
    ssl_certificate_key  /usr/local/nginx/cert/2353008_www.incisor.cn.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ......省略
}
複製代碼
相關文章
相關標籤/搜索