(轉載誤入)python上手實踐 -- docker+nginx+gunicorn+flask項目部署

最近在研究這個,時間不夠,沒辦法只能轉載了,僅做自己學習,誤入

 

flask屬於輕量級python的web框架,其流行程度可以與django媲美。因爲是輕量型,所以對於開發一些中小型項目就非常方便。不過flask自帶的server速度較慢,測試環境還可以,真正實際使用起來還是很多問題。同時在部署時會移植到linux系統中,穩定性更好。

1.使用虛擬環境創建flask項目

在使用flask來開發項目時,爲了保證項目移植的順平性(如在windows中開發的項目移植到linux中),通常會採用env虛擬環境方式,將pip安裝的一系列第三方庫放在虛擬環境env目錄下。移動整個項目工程也就會將虛擬環境遷移走。

(1)建立虛擬環境env,並激活使用

首先新建一個flask工程目錄,並使用python -m venv env命令創建虛擬環境目錄:

mkdir Flask_Proj
cd Flask_Proj
python -m venv env   #創建虛擬環境目錄env

上述命令執行完成後,就會在Flask_Proj目錄下新建一個env目錄,並有如下內容:

[hadoop@big01 env]$ ll
total 4
drwxrwxr-x. 2 hadoop hadoop 202 May 17 21:03 bin
drwxrwxr-x. 2 hadoop hadoop   6 May 17 20:53 include
drwxrwxr-x. 3 hadoop hadoop  23 May 17 20:53 lib
lrwxrwxrwx. 1 hadoop hadoop   3 May 17 20:53 lib64 -> lib
-rw-rw-r--. 1 hadoop hadoop  69 May 17 20:53 pyvenv.cfg

然後使用source命令激活bin目錄下的activate,就可以激活虛擬環境使用了:

source env/bin/activate

反過來如果想退出虛擬環境,使用deactivate即可。

(2)有了這個env虛擬環境後,在當前工程目錄下pip install flask,開啓安裝flask庫。如果默認pypi官方鏈接速度較慢,可以使用:

pip install -i https://mirrors.aliyun.com/pypi/simple flask

到底是國內鏡像,速度不是一般的快。

安裝完成後,可以去看一下這個庫不是放在python默認安裝目錄裏,而是放在剛創建的虛擬環境目錄env裏的lib文件夾下,路徑爲:env/lib/python3.7/site-packages。

flask安裝成功後,可以在工程目錄下新建一個main.py文件,在其中輸入如下內容:

#main.py
from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return 'jianhua_helloworld2020'

if __name__ == '__main__':
    app.run(port=2021,host='0.0.0.0')  #host設置爲0.0.0.0,可以允許外部遠程訪問

然後使用python直接運行這個文件,就可以開啓一個測試的web服務:

[hadoop@big01 asmarket]$ python main.py
 * Serving Flask app "main" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:2021/ (Press CTRL+C to quit)

此時可以在外部瀏覽器上訪問這個地址,端口號爲2021:

2. gunicorn部署flask項目

上述在flask工程項目中創建env虛擬環境,是爲了保證許多依賴的第三方庫版本的一致。如上在啓動了flask自帶的server後,可以實現外部訪問。但這種方式僅適用於測試,無法用於實際部署,因此一般推薦使用gunicorn來搭建flask服務器。

Gunicorn (獨角獸)是一個高效的Python WSGI Server,通常用它來運行 wsgi application(由我們自己編寫遵循WSGI application的編寫規範) 或者 wsgi framework(如Django,Paster),地位相當於Java中的Tomcat。

(1)安裝gunicorn

gunicorn是一個第三方庫,可以直接使用pip來安裝:

pip install -i https://mirrors.aliyun.com/pypi/simple gunicorn

(2)使用gunicorn命令

基本使用方式:

gunicorn --workers=3 main:app 

--workers=3表示三個進程,main:app,其中main爲之前flask工程中的main.py,意味這將main.py對象實例化爲app。

允許上述命令後,就會出現如下提示:

(env) [hadoop@big01 asmarket]$ gunicorn --workers=4 te:app
[2020-05-17 22:21:04 +0800] [9123] [INFO] Starting gunicorn 20.0.4
[2020-05-17 22:21:04 +0800] [9123] [INFO] Listening at: http://127.0.0.1:8000 (9123)
[2020-05-17 22:21:04 +0800] [9123] [INFO] Using worker: sync
[2020-05-17 22:21:04 +0800] [9126] [INFO] Booting worker with pid: 9126
[2020-05-17 22:21:04 +0800] [9127] [INFO] Booting worker with pid: 9127
[2020-05-17 22:21:05 +0800] [9128] [INFO] Booting worker with pid: 9128
[2020-05-17 22:21:05 +0800] [9129] [INFO] Booting worker with pid: 9129

可以看到上述監聽地址爲:127.0.0.0,端口爲8000。工作模式爲sync,即同步工程模式。這兩種參數都可以進行修改,其中監聽地址和端口號可以在上述命令後添加 -b ip:port方式實現:

gunicorn --workers=3 main:app -b 0.0.0.0:2021

在shell命令窗口:

(env) [hadoop@big01 asmarket]$ gunicorn --workers=4 te:app -b 0.0.0.0:2021
[2020-05-17 22:26:29 +0800] [9162] [INFO] Starting gunicorn 20.0.4
[2020-05-17 22:26:29 +0800] [9162] [INFO] Listening at: http://0.0.0.0:2021 (9162)
[2020-05-17 22:26:29 +0800] [9162] [INFO] Using worker: sync
[2020-05-17 22:26:29 +0800] [9165] [INFO] Booting worker with pid: 9165
[2020-05-17 22:26:29 +0800] [9166] [INFO] Booting worker with pid: 9166
[2020-05-17 22:26:29 +0800] [9167] [INFO] Booting worker with pid: 9167
[2020-05-17 22:26:29 +0800] [9168] [INFO] Booting worker with pid: 9168

此時同樣可以在外部瀏覽器中訪問,獲得的效果與直接使用flask來搭建server服務一致。

對於工作模式,默認是sync,即同步模式。這種模式就是說在調用的時候,必須等待調用返回結果後,決定後續的行爲。而異步則是在調用這個job的時候,不用等待其執行結果,還可以執行其他job。

舉個例子:

打電話問酒店晚上有沒有房間,如果是同步通信機制,酒店前臺會禮貌的說:“請您稍等,我查一下",等她查到結果了就告訴你結果,這個過程中你的電話是一直通着的,在等她的結果,決定住她們家還是去別的酒店。如果是異步通信機制,酒店前臺會禮貌的說:”我先查一下,一會給您回過去。“然後她把電話掛了。你馬上就可以拿手機看看周邊是否有便利的餐館。等她查到了,她會主動給你打電話。而此時餐館也查好了,可以開啓美好的旅行了。

如果要更換爲異步模式,可以使用gevent。此時還需要pip來安裝gevent。

gunicorn --workers=3 main:app -b 0.0.0.0:2021 -k 'gevent'

(3)使用參數配置文件設定

使用上述腳本命令還是不方便的,gunicorn可以使用-c參數,就是使用配置文件。將一些參數設定放在該配置文件裏:

import os
bind='0.0.0.0:5001'   #綁定監聽ip和端口號
workers=3               #同時執行的進程數,推薦爲當前CPU個數*2+1
backlog=2048            #等待服務客戶的數量,最大爲2048,即最大掛起的連接數
worker_class="gevent" #sync, gevent,meinheld   #工作模式選擇,默認爲sync,這裏設定爲gevent異步
max_requests=1000       #默認的最大客戶端併發數量
daemon=True           # 是否後臺運行
reload=True            # 當代碼有修改時,自動重啓workers。適用於開發環境。
pidfile='./gunicore.pid'    #設置pid文件的文件名
loglevel='debug'     # debug error warning error critical
accesslog='log/gunicorn.log'  #設置訪問日誌
errorlog='log/gunicorn.err.log' #設置問題記錄日誌

將上述內容存放在config.py文件中,然後在命令行輸入:

gunicorn -c config.py main:app

如下爲本次實踐時配置的config.py參數:

import  os
from  gevent import monkey
monkey.patch_all()
import multiprocessing
debug = False
bind = "0.0.0.0:5001"
pidfile = "gunicorn.pid"
accesslog="/home/hadoop/asmarket/logs/gunicorn.log"
workers = multiprocessing.cpu_count()*2 + 1
worker_class = "gevent"
daemon=True

然後開啓運行,此時gunicorn設置爲後臺看守進程,先直接從外部瀏覽器訪問,然後查看log文件,內容如下:

[hadoop@big01 logs]$ more gunicorn.log 
192.168.58.1 - - [17/May/2020:23:30:44 +0800] "GET / HTTP/1.1" 200 23 "-" "Mozi
lla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
68.0.3440.106 Safari/537.36"
192.168.58.1 - - [17/May/2020:23:30:46 +0800] "GET / HTTP/1.1" 200 23 "-" "Mozi
lla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
68.0.3440.106 Safari/537.36"
192.168.58.1 - - [17/May/2020:23:30:47 +0800] "GET / HTTP/1.1" 200 23 "-" "Mozi
lla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
68.0.3440.106 Safari/537.36"

至此基本的gunicorn+flask異步服務部署就實現了。

3. gunicorn+nginx配置

有了gunicorn和gevent後,gunicorn可以實現多進程http服務,不過其性能還是相對nginx這種專業的web服務要差一些,主要體現在對高併發的處理、安全問題、靜態資源文件的處理等。因此一般情況會在gunicorn之上再配置一層nginx服務。其基本架構示意如下(圖來源於百度):

(1)docker部署nginx

由於nginx採用安裝方式還相對比較麻煩,可以直接使用docker來部署。不過當然首先在root賬戶下安裝docker服務:

#yum安裝docker
yum install docker
#啓動docker進程服務
systemctl start docker
systemctl enable docker  

有了docker後,使用docker的search和pull服務就可以將nginx拉取到本機上:

[root@big01 ~]# docker pull nginx
Using default tag: latest
Trying to pull repository docker.io/library/nginx ... 
latest: Pulling from docker.io/library/nginx
afb6ec6fdc1c: Pull complete 
b90c53a0b692: Pull complete 
11fa52a0fdc0: Pull complete 
Digest: sha256:30dfa439718a17baafefadf16c5e7c9d0a1cde97b4fd84f63b69e13513be7097
Status: Downloaded newer image for docker.io/nginx:latest

然後使用docker 查看鏡像:

[root@big01 ~]# docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
docker.io/nginx         latest              9beeba249f3e        2 days ago          127 MB
docker.io/hello-world   latest              bf756fb1ae65        4 months ago        13.3 kB

接下來可以運行nginx容器:

[root@big01 ~]# docker run --name mynginx -p 8080:80 -d nginx
79b2f668784f866869f41ab08468784cf5f694fb451486250f37eaaa11808411

此時可以從外部瀏覽器訪問獲得默認的nginx響應頁面:

下面對nginx訪問頁面做一個映射,因爲如果要進入docker內部訪問的話還是很不方便的,因此一般情況將docker鏡像作爲一個服務,而將實際的資源進行一個映射。在本地機器上放置資源,映射到容器內部,nginx訪問內部文件路徑時就映射到訪問外部本地資源上了,這樣便於資源分配以及web文件的管理。這裏就是增加一個docker的-v參數,格式爲本地資源:容器資源。

先進入docker內部,查看nginx的配置文件:

[root@big01 nginx]# docker exec -it 16528ae739c4 /bin/bash
root@16528ae739c4:/# cd /etc/nginx/conf.d/
root@16528ae739c4:/etc/nginx/conf.d# more default.conf 
server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;

默認訪問的路徑爲/usr/share/nginx/html下的html文件,這個可以後續修改。我們可以先測試一下,將這個路徑映射到本地機器上。這樣需要重新run一個鏡像:

[root@big01 nginx]# docker run --name mynginxt -v /usr/share/nginx/:/usr/share/nginx/html -p 8021:80 -d nginx
16528ae739c40d28a68be67b10aac42343b97b5fa468565127eaf051ea25886c

上述命令中:-v /usr/share/nginx/:/usr/share/nginx/html,就是將本地的/usr/share/nginx目錄映射到容器內部的/usr/share/nginx/html目錄中,如果我們在本地的nginx目錄下新建一個index.html網頁,那訪問的時候就是訪問這個新建的index.html網頁。如下新建一個簡單網頁並保存爲index.html。

<html>
<head>
  <meta charset="utf-8">
</head>
<body>
<h1>我的第一個標題</h1>
<p>我的第一個段落。</p>
</body>
</html>

接下來就可以在外部瀏覽器訪問,注意端口現在爲8021。

(2)nginx+gunicorn部署

上述gunicorn部署時,ip爲0.0.0.0,端口號爲5001。在使用nginx代理這個服務時,修改nginx相應的配置文件即可。不過因爲是docker部署,因此還需使用docker來操作。此時也可以將配置文件映射到外部宿主機上。

首先啓動gunicorn+flask項目服務:

[hadoop@big01 asmarket]$ gunicorn -c config.py main:app

然後在/usr/share/nginx目錄下新建一個nginx.conf文件,在其中輸入如下內容:

server {
    listen 80;
    server_name asmarket.com; # 這是HOST機器的外部域名,用地址也行

    location / {
        proxy_pass http://0.0.0.0:5001; # 這裏是指向 gunicorn host 的服務地址
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  }

將其映射到nginx容器裏的default.conf配置文件:

[root@big01 nginx]# docker run --name mynginx -v /usr/share/nginx/nginx.conf:/etc/nginx/conf.d/default.conf -d nginx
39026ba7d80eac3d59d00ead25d7275e5f2b125dde3a9e3379dffb5c10ef9662

這樣在啓動nginx時直接使用的就是剛纔新建立的nginx.conf配置文件。

此時nginx已經啓動了:

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                   PORTS                  NAMES
39026ba7d80e        nginx               "nginx -g 'daemon ..."   7 minutes ago       Up 7 minutes             80/tcp                 mynginx

然後就可以運行flask項目了。

如何驗證確實是代理了gunicornweb服務,可以直接使用nginx原有的默認80端口訪問,如果出現錯誤,說明nginx已經代理了web服務,否則就是沒成功。

(3)supervisor進程守護

nginx一般不會莫名其妙被關閉,但gunicorn是一個進程,完成有有可能因爲一些原因被關閉或者阻塞,爲了保證gunicorn進程,需要使用看護進程插件。這裏使用supervisor來解決這個問題。

supervisor專門用戶linux端進程管理,首先使用pip安裝一下這個插件:

[root@big01 ~]# pip install supervisor

安裝成功後,可以創建一個配置文件:

# 設置默認配置
$ echo_supervisord_conf > /etc/supervisord.conf
$ vi /etc/supervisord.conf

這個配置文件放在/etc/目錄下,名爲supervisor.conf。接下來就可以修改其配置了:

[program:myapp]
command=/usr/local/bin/gunicorn -c config.py main:app               
directory=/home/hadoop/asmarket
autostart=true                ; start at supervisord start (default: true)
startsecs=1                   ; # of secs prog must stay up to be running (def. 1)
startretries=3                ; max # of serial start failures when starting (default 3)
exitcodes=0                   ; 'expected' exit codes used with autorestart (default 0)
stdout_logfile=/home/hadoop/asmarket/logs/main.logs
stdout_logfile_maxbytes=50MB   ; max # logfile bytes b4 rotation (default 50MB)
user=root

修改完成後,直接使用supervisord來執行:

supervisord -c supervisor.conf

這樣myapp的進程就啓動了。可以使用supervisorctl status命令來查看當前進程狀態:

supervisorctl status
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章