Ubuntu配置環境3:Nginx+Gunicorn+Supervisor

首先,本文的mysite是指自己的站點名稱。

安裝nginx

 apt-get install nginx

關閉nginx默認的log

vi /etc/nginx/nginx.conf
找到以下access_log和error_log,修改為null。
access_log /dev/null;
error_log /dev/null;

接下來配置站點配置,進入nginx站點配置目錄,并新建配置文件

cd /etc/nginx/sites-available/
vi mysite

寫入一下對應站點配置文本,并保存

server {  
        listen   80;  
        server_name www.mysite.com mysite.com;
        #修改最大上傳為10M,默認為2M,超出大小出現413 Request Entity Too Large錯誤
        client_max_body_size 10M;
         #一定要記得在網站目錄下創建logs文件夾,不然會報錯,不需要可注釋掉
        #access_log /var/www/mysite/logs/access.log;
        #error_log /var/www/mysite/logs/access.log;
        

        #默認請求,nginx反向代理(動態頁面轉發至gunicorn)
        location / {  
            #將訪客IP加入headers中,否則獲取到的將是127.0.0.1
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;  
            proxy_redirect off;  
            #如果請求的文件不存在,則將路由轉發到gunicorn的8000端口
            if (!-f $request_filename) {  
                proxy_pass http://127.0.0.1:8000;  
                break;  
            }  
        }

        #靜態文件請求轉發給目錄
        location ^~ /static/ {
                root /var/www/mysite/app;
        }
    }

上面的內容中proxy_pass http://127.0.0.1:8000; 是表示動態頁面轉發到本機8000端口,這個端口就是gunicorn開放的服務。
這樣靜態頁面nginx就直接返回給訪客,動態頁面則轉發給gunicorn處理。

這里插一句:由于使用nginx反向代理到gunicorn,那么在flask中獲取IP就需要

//X-Forward-For參數為nginx反向代理轉發到gunicorn時設置的參數
ip = request.headers.get('X-Forward-For') or request.remote_addr

啟用站點配置文件

cd /etc/nginx/sites-enabled
#添加引用鏈接
ln -s /etc/nginx/sites-available/mysite ./mysite
#查看引用是否成功
ls -l
Paste_Image.png

檢測配置文件是否有錯誤

sudo nginx -t

重啟nginx

service nginx restart

開啟防火墻端口

如果系統中沒有安裝ufw,則可以跳過,沒有安裝的話表現為命令不識別。
安裝了ufw的話,如果相關端口沒有開放,配置好nginx后會出現自己可以訪問(wget網址試試),外網卻無法訪問

#查看開放的端口
ufw status
#添加80端口
ufw allow 80
Paste_Image.png

安裝Gunicorn

進入配置好的virtualenvs虛擬目錄,激活網站虛擬環境

cd /var/virtualenvs
source mysite_venv/bin/activate

安裝Gunicorn

pip install gunicorn
#進入網站根目錄
cd /var/www/mysite
#創建配置文件
vi gunicorn.conf

輸入配置文本并保存:

# 進程為5
workers = 5

# 監聽本地8000端口,之后這個端口來的就是看這個網站的。
bind = '127.0.0.1:8000'

#如果要搭配gevent使用,請加上取消注釋
#worker_class="gevent" #sync, gevent,meinheld

注意:如果需要使用gevent模式,請先pip install gevent,然后在gunicorn.conf配置文件中加上worker_class="gevent",其他都和往常一樣。

gunicorn啟動測試

cd /var/www/mysite
gunicorn -c gunicorn.conf myapp:app

啟動后提示:


Paste_Image.png

到這里gunicorn已經安裝并配置好了,如果要正常用gunicorn啟動網站項目,需要項目中有對應的啟動文件,現在可以先跳過這一步,直接跳到安裝Supervisor。

當我們安裝并配置好 gunicorn 之后,需要用 gunicorn 啟動 flask,注意網站項目中 manage.py里面的 app.run(),這句代碼是作為 flask 自帶的server服務的啟動 入口,由于flask自帶的server很性能很差,這里我們服務器上使用 gunicorn,manage.py和myapp.py一樣,都是作為啟動入口文件,供server調用運行。在項目的manage.py文件中,gunicom不會執行代碼中的.run(),是需要加上一段代碼對接gunicom。

在網站項目中需要一個gunicorn的啟動入口的文件,如果沒有就自己新建一個文件,名字無所謂,我取的是myapp.py,
內容為

import os
from app import create_app,db

app = create_app(os.getenv('mysite_CONFIG') or 'default')

#使用Gunicorn需要這兩行代碼對接
from werkzeug.contrib.fixers import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app)

這個文件和manage.py一樣,也是一個啟動文件,不同的是,myapp.py專門作為gunicorn啟動使用,manage.py是用作flask自帶的web-server啟動,同時manage.py里面還有一些管理代碼,一樣可以使用python manage.py shell或python manage.py db init等命令來管理數據庫。

運行Gunicorn,
--config gunicorn.conf是根據配置文件來運行
manage為自己的run文件

gunicorn -c gunicorn.conf myapp:app

安裝Supervisor

我們的網站現在雖然能訪問了,但是假如你重啟服務器,網站的動態文件就會打不開,因為gunicorn不會開機自己啟動,需要一個小保姆開機后自動給他啟動,這里我們就使用supervisor。

Supervisor是一款服務器管理工具,用于監控和守護進程。阿里云會偶爾宕機,宕機后會切換物理服務,造成服務器重啟。故而官網也強調過,程序最好有自動重啟、重連機制。所以我們需要Supervisor當保姆,照顧我們的后臺進程。

 apt-get install supervisor

注意:supervisor需要系統默認是python2.7才能兼容支持,否則會安裝失敗,使用python -V查看系統默認py版本

向supervisor添加gunicorn的啟動項

cd /etc/supervisor/conf.d
vi mysite.conf

粘貼一下文本并保存

# 進程的名字,取一個以后自己一眼知道是什么的名字。(這行字不能刪,第一行需要一行注釋,刪了就有問題)
[program:mysite]
# 定義Gunicorn啟動命令,我們手動在ssh啟動Gunicorn需要cd到網站目錄然后輸入 gunicorn -c gunicorn.conf myapp:app,所以這里所有路徑都要寫成絕對路徑,這樣系統才能找到這些路徑
command=/var/virtualenvs/mysite_venv/bin/gunicorn myapp:app -c /var/www/mysite/gunicorn.conf
# 網站目錄
directory=/var/www/mysite
# 進程所屬用戶
user=root
# 自動重啟設置。
autostart=true
autorestart=true
# 日志存放位置(可能造成print中文UnicodeEncodeError)
#stdout_logfile=/var/www/mysite/logs/gunicorn_supervisor.log
# 設置環境變量。這里這行的意思是:設置環境變量MODE的值為UAT。請根據自己的需要配置,如沒有需要這行可以刪除。
#environment = MODE="UAT"

[supervisord]

保存后就進入supervisorctl控制臺

supervisorctl

進入控制臺

reread
update
start mysite

啟動完成后,以后每次開機supervisor都會幫我們自動按照配置文件啟動gunicorn服務。

Paste_Image.png

如果發生錯誤請退出控制臺,嘗試重啟服務

service supervisor restart

現在重啟服務器后,如果網站能正常訪問了,說明gunicorn自動啟動了,這也表示我們的supervisor配置成功了。

以后如果更新了網站項目文件,讓gunicorn重新加載新的項目文件也只需要使用supervisor管理gunicorn進程就好了。
重新載入配置文件并停止所有進程并按新的配置啟動:supervisorctl reload

以下是所有supervisorctl 的命令

supervisorctl status: 查看當前運行的進程列表
supervisorctl stop xxx: 停止某一個進程(xxx),xxx為[program:theprogramname]里配置的值。
supervisorctl start xxx: 啟動某個進程
supervisorctl restart xxx: 重啟某個進程
supervisorctl stop groupworker: 重啟所有屬于名為groupworker這個分組的進程(start,restart同理)
supervisorctl stop all,停止全部進程,注:start、restart、stop都不會載入最新的配置文件。
supervisorctl reload,載入最新的配置文件,停止原有進程并按新的配置啟動、管理所有進程。
supervisorctl update,根據最新的配置文件,啟動新配置或有改動的進程,配置沒有改動的進程不會受影響而重啟。
注意:顯示用stop停止掉的進程,用reload或者update都不會自動重啟。

supervisor使用中遇到的一些錯誤

============錯誤A
參考https://www.v2ex.com/t/210122

如果提示unix:///var/run/supervisor.sock no such file
error: <class 'socket.error'>, [Errno 2] No such file or directory: file: /usr/lib/python2.7/socket.py line: 224
這表明supervisord服務端沒有成功啟動,多半是/etc/supervisor/conf.d下面自己的配置文件出問題

cd /etc/supervisor/conf.d
supervisord -c mysite.conf
Paste_Image.png

這里就告訴我配置文件17行出了問題

修改好配置文件后,

#重新生成supervisor.sock文件,啟動監聽服務
supervisord -c supervisord.conf
#重新加載自定義配置文件
supervisorctl reload

============錯誤B
如果配置文件有錯誤,會提示你提示

Paste_Image.png

如果有錯誤則exit退出控制臺,vi mysite.conf修改錯誤后再繼續進入控制臺,并reread重新讀取配置文件。
如果都正確了,則在supervisorctl的控制臺中輸入命令,啟動supervisor任務。
(注意:如果要supervisor啟動任務,則會啟動gunicorn,自己先使用gunicorn命令試試能否正常啟動網站項目)。

#進入網站目錄
cd /var/www/mysite
#測試能否正常啟動網站項目
gunicorn -c gunicorn.conf myapp:app

如果能正常啟動就ctrl+c結束,然后繼續進入supervisorctl啟動任務。

supervisorctl

==============錯誤C

這樣就錯誤:

[program:taokeapi]
# 定義Gunicorn啟動命令,我們手動在ssh啟動Gunicorn需要cd到網站目錄然后輸入 gunicorn -c gunicorn.conf myapp:app,所以>這里所有路徑都要寫成絕對路徑,這樣系統才能找到這些路徑
command=/var/virtualenvs/taokeapi_venv/bin/gunicorn myapp:app -c /var/www/taokeapi/gunicorn.conf
# 網站目錄
directory=/var/www/taokeapi
# 進程所屬用戶
user=root
# 自動重啟設置。
autostart=true
autorestart=true

[supervisord]

這樣就正確:

# 進程的名字,取一個以后自己一眼知道是什么的名字。
[program:taokeapi]
# 定義Gunicorn啟動命令,我們手動在ssh啟動Gunicorn需要cd到網站目錄然后輸入 gunicorn -c gunicorn.conf myapp:app,所以>這里所有路徑都要寫成絕對路徑,這樣系統才能找到這些路徑
command=/var/virtualenvs/taokeapi_venv/bin/gunicorn myapp:app -c /var/www/taokeapi/gunicorn.conf
# 網站目錄
directory=/var/www/taokeapi
# 進程所屬用戶
user=root
# 自動重啟設置。
autostart=true
autorestart=true

[supervisord]

差別僅僅是第一行多了一行注釋。。。
不知道是BUG還是什么,總之第一行需要注釋,去掉就會出問題。。。

======錯誤D

Paste_Image.png

使用supervisor啟動gunicorn,執行print就出錯。
而直接啟動gunicorn則沒問題。
可見錯誤在supervisor上面。。

經過多次排查,發現,
vi /etc/supervisor/conf.d/taokeapi.conf配置文件中多了一行,

stdout_logfile=/var/www/mysite/logs/gunicorn_supervisor.log

由于supervisor是基于python2,當運行python3的項目時,print就會被寫入這個日志文件,python2在有些系統中輸出中文就會出現UnicodeEncodeError錯誤。
解決辦法:
配置文件中去掉這行輸出日志目錄,完整配置如下:

# 進程的名字,取一個以后自己一眼知道是什么的名字。
[program:taokeapi]
# 定義Gunicorn啟動命令,我們手動在ssh啟動Gunicorn需要cd到網站目錄然后輸入 gunicorn -c gunicorn.conf myapp:app,所以>這里所有路徑都要寫成絕對路徑,這樣系統才能找到這些路徑
command=/var/virtualenvs/taokeapi_venv/bin/gunicorn myapp:app -c /var/www/taokeapi/gunicorn.conf
# 網站目錄
directory=/var/www/taokeapi
# 進程所屬用戶
user=root
# 自動重啟設置。
autostart=true
autorestart=true

[supervisord]

然后重新加載配置文件

supervisord -c taokeapi.conf

supervisorctl
>reread
>update
>reload

這樣就發現沒問題了

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

推薦閱讀更多精彩內容