原文轉載自「劉悅的技術博客」v3u.cn/a_id_164python
書接上回,以前一篇:Win10環境下使用Flask配合Celery異步推送實時/定時消息(Socket.io)/2020年最新攻略,闡述瞭如何使用Celery異步推送Websocket消息,如今咱們利用Docker將這個完整項目部署起來,爲何用Docker呢?緣由很簡單,這種容器技術能夠將整個項目用單個容器裝起來,僅僅只須要維護一個簡單的配置文件就告訴電腦每次部署要把什麼東西裝進容器,甚至把這個過程自動化,部署流程就會變得簡單、方便。mysql
簡單理解就是Docker的鏡像就相似《精靈寶可夢》中小智手裏的精靈球,咱們的項目就相似那些寵物小精靈,當咱們開發完畢就能夠利用DockerFile對項目進行打包製做成鏡像(小精靈被吸入精靈球),部署時就能夠理解爲小精靈被釋放出來進行戰鬥(經過打包好的鏡像運行容器),而Docker的倉庫則提升了鏡像的便捷性,可讓咱們隨時隨地只要聯網就可使用本身的鏡像(至關於小智不用隨身攜帶精靈球,而是經過網絡隨時下載須要的精靈球)。git
同時Docker其強大的跨平臺特性,可讓咱們在任何系統下部署項目,包括常常使人詬病的Windows,值得一提的是本次在Win10下部署項目的流程一樣適用於Centos、Mac os、Ubuntu等系統,其兼容性可見一斑。redis
關於Win10如何折騰和配置Docker,請參照這篇文章:win10系統下把玩折騰DockerToolBox以及更換國內鏡像源(各類神坑)sql
首先簡單看一下項目結構:docker
manage.py是項目的入口文件,這裏咱們利用Sockert.io讓Flask支持Websocketdjango
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import pymysql
from flask import request,jsonify
from flask_cors import CORS
from flask_socketio import SocketIO,send,emit,join_room, leave_room
import urllib.parse
import user_view
from celery import Celery
from datetime import timedelta
pymysql.install_as_MySQLdb()
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:root@localhost:3306/md"
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['BROKER_URL'] = 'redis://localhost:6379'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379'
app.config['CELERY_ACCEPT_CONTENT'] = ['json', 'pickle']
app.config['REDIS_URL'] = 'redis://localhost:6379'
app.config['JSON_AS_ASCII'] = False
CORS(app,cors_allowed_origins="*")
app.register_blueprint(user_view.user)
db = SQLAlchemy(app)
socketio = SocketIO(app,cors_allowed_origins='*',async_mode="threading",message_queue=app.config['CELERY_RESULT_BACKEND'])
celery = Celery(app.name)
celery.conf.update(app.config)
celery.conf.CELERYBEAT_SCHEDULE = {
"test":{
"task":"get_cron",
"schedule":timedelta(seconds=10)
}
}
@celery.task(name="get_cron")
def get_cron():
get_sendback.delay()
@celery.task()
def get_sendback():
socketio.emit('sendback','message',broadcast=True)
@app.route('/task')
def start_background_task():
get_sendback.delay()
return '開始'
@app.route('/',methods=['GET','POST',"PUT","DELETE"])
def hello_world():
#res = db.session.execute("insert into user (`username`) values ('123') ")
# res = db.session.execute(" select id,username from user ").fetchall()
# data = request.args.get("id")
# #data = request.form.get("id")
# print(data)
# print(res)
# #return 'Hello Flask'
# return jsonify({'result': [dict(row) for row in res]})
return jsonify({'message':'你好,Docker'})
@socketio.on('join')
def on_join(data):
username = 'user1'
room = 'room1'
join_room(room)
send(username + ' has entered the room.', room=room)
@socketio.on('message')
def handle_message(message):
message = urllib.parse.unquote(message)
print(message)
send(message,broadcast=True)
@socketio.on('connect', namespace='/chat')
def test_connect():
emit('my response', {'data': 'Connected'})
@socketio.on('disconnect', namespace='/chat')
def test_disconnect():
print('Client disconnected')
@app.route("/sendback",methods=['GET'])
def sendback():
socketio.emit('sendback','message')
return 'ok'
if __name__ == '__main__':
socketio.run(app,debug=True,host="0.0.0.0",port=5000)
複製代碼
接下來使用Gunicorn+gevent來運行Flask項目,Gunicorn服務器做爲wsgi app的容器,可以與各類Web框架兼容(flask,django等),得益於gevent等技術,使用Gunicorn可以在基本不改變wsgi app代碼的前提下,大幅度提升wsgi app的性能。那到底怎麼提高性能?說簡單點,Gunicorn 默認的網絡模型是 select ,當咱們把worker 替換成 gevent 後,則改成 epoll 監聽模型,關於select、poll、epoll請參照這篇文章:關於Tornado:真實的異步和虛假的異步,這裏再也不贅述。json
安裝相應的庫flask
pip install gunicorn gevent --user
複製代碼
編輯項目目錄下的gunicorn.conf.pybash
workers = 3 # 進程數
worker_class = "gevent" # 異步模式
bind = "0.0.0.0:5000"
複製代碼
因爲Gunicorn並不支持Windows環境,因此只須要寫好配置,不須要運行。
編輯項目目錄下的requirements.txt文件,這裏面都是咱們項目所依賴的庫
flask==1.0.2
flask-cors
flask-socketio
flask-sqlalchemy
pymysql
celery
gunicorn
gevent
redis==3.3.11
複製代碼
隨後在項目目錄下建立一個 Dockerfile 文件,這個文件能夠理解爲打包鏡像的腳本,你須要這個鏡像作什麼,就把任務寫到腳本中,Docker經過執行這個腳原本打包鏡像
FROM python:3.6
WORKDIR /Project/myflask
COPY requirements.txt ./
RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
COPY . .
ENV LANG C.UTF-8
CMD ["gunicorn", "manage:app", "-c", "./gunicorn.conf.py"]
複製代碼
能夠看到,咱們項目的鏡像首先基於python3.6這個基礎鏡像,而後聲明項目目錄在/Project/myflask中,拷貝依賴表,以後安裝相應的依賴,這裏在安裝過程當中咱們指定了國內的源用來提升打包速度,最後利用gunicorn運行項目,值得一提的是,ENV LANG C.UTF-8是爲了聲明Docker內部環境中的編碼,防止中文亂碼問題。
最後咱們就能夠愉快的打包整個項目了,在項目根目錄下執行
docker build -t 'myflask' .
複製代碼
此時看到Docker經過讀取Dockerfile文件來下載所需的基礎鏡像和依賴庫,這裏必定要指定Docker的下載源,不然速度會很是緩慢,打包好的鏡像文件大概有1g左右。
下載結束以後,能夠看到myflask這個鏡像已經靜靜躺在鏡像庫中了,運行
docker images
複製代碼
命令來查看
而後咱們就能夠利用這個鏡像來經過容器跑Flask項目了,運行命令
docker run -it --rm -p 5000:5000 myflask
複製代碼
這裏的命令是經過端口映射把docker內部的端口5000映射到宿主機的5000端口上,後面的參數是鏡像名稱。咱們看到,在Win10下,已經難以想象的經過Gunicorn把Flask跑起來了,這在以前沒有Docker技術以前是不可想象的。
經過網址訪問一下,這裏注意一點,就是Windows系統下,訪問Docker容器須要經過分配的ip來訪問,而不是咱們經常使用的localhost。
徹底沒有任何問題。
結語:到這裏咱們的 Docker+Flask + Gunicorn就部署完畢了,將這個鏡像上傳Dockerhub倉庫,在任什麼時候間、任何地點、任何系統上,只要連着網、只要咱們想,就均可以在短短1分鐘以內部署好咱們的項目,這就是Docker技術對開發人員最好的饋贈。最後奉上項目地址:gitee.com/QiHanXiBei/…
原文轉載自「劉悅的技術博客」 v3u.cn/a_id_164