The original article is reprinted from liu Yue’s Technology blog v3u.cn/a_id_164

The book goes back to the previous one: In Win10, using flack-celery asynchronous push Websocket messages (sock. IO), we will use “Celery asynchronous push Websocket messages” Why Docker? The reason is simple, this container technology can put the entire project into a single container, just maintain a simple configuration file to tell the computer what to put into the container each deployment, even automate the process, the deployment process is simple and convenient.

The simple understanding is that the mirror image of Docker is similar to the fairy ball in the hands of the little wisp in Pokemon. Our project is similar to those pokemon. When we finish developing, we can use DockerFile to package the project and make a mirror image (the elves are sucked into the fairy ball). Deployment can be understood as the elf was released to fight (by running container packaging good mirror), whereas the Docker warehouse improves the convenience of mirror, can let us anytime and anywhere as long as the network can use their own mirror (equivalent to a little wisdom don’t have to carry the elves ball, but through the network at any time to download the elves of the ball).

Meanwhile, Docker’s powerful cross-platform feature allows us to deploy projects in any system, including Windows, which is often criticized. It is worth mentioning that the process of deploying projects in Win10 is also applicable to Centos, Mac OS, Ubuntu and other systems, showing its compatibility.

For Win10, how to play with DockerToolBox and replace domestic image sources (various god pit), please refer to this article.

First, a brief look at the project structure:

Manage.py is the entry file for the project. Here we use Sockert. IO to make Flask support Websocket

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=The '*',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':'hello, 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)
Copy the code

The Gunicorn server serves as a container for wsGi apps and is compatible with various Web frameworks (Flask, Django, etc.) thanks to gEvent and other technologies, Using Gunicorn can significantly improve wsGi app performance without changing much of the WSGi app code. So how do you improve performance? To put it simply, the default network model of Gunicorn is SELECT. When we replace worker with gevent, it will be changed to epoll monitoring model. For select, poll and epoll, please refer to this article: Tornado: True Asynchrony and False Asynchrony. I won’t repeat it here.

Install the appropriate libraries

pip install gunicorn gevent --user
Copy the code

Edit gunicorn.conf.py in the project directory

workers = 3    # processes
worker_class = "gevent"   Asynchronous mode
bind = "0.0.0.0:5000"
Copy the code

Since Gunicorn does not support Windows environments, you only need to write the configuration, not run it.

Edit the requirements. TXT file in the project directory, which contains all the libraries our project depends on

Flask ==1.0.2 flask- Cors flask- Socketio flask- SQLAlchemy Pymysql gunicorn gevent Redis ==3.3.11Copy the code

Then create a Dockerfile file in the project directory. This file can be interpreted as a script to package the image. What do you need the image to do

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"]
Copy the code

In /Project/myflask, copy the dependency table and install the corresponding dependencies. During the installation process, we specify the local source to improve the packaging speed. Finally, we use Gunicorn to run the Project. It is worth mentioning that ENV LANG C.UTF-8 is to declare the encoding in Docker internal environment, to prevent Chinese garble problems.

Finally, we can happily package the entire project and execute it in the project root directory

docker build -t 'myflask' .
Copy the code

At this time see Docker by reading Dockerfile file to download the required base image and dependent library, here must specify the download source of Docker, otherwise the speed will be very slow, packaged image file about 1g.

After downloading, you can see that myFlask is already sitting in the mirror library, running

docker images
Copy the code

Command to view

We can then use this image to run Flask projects through containers, running commands

docker run -it --rm -p 5000:5000 myflask
Copy the code

The command here is to map docker’s internal port 5000 to the host’s port 5000 by port mapping. The following parameter is the image name. We’ve seen Flask run in Win10 using Gunicorn in a way that would have been unthinkable without Docker technology.

On Windows, you need to access the Docker container through an assigned IP address, not localhost.

There was no problem at all.

Conclusion: Here our Docker+Flask + Gunicorn is deployed, upload the image to the Dockerhub repository, and we can deploy our project in just 1 minute, anytime, anywhere, on any system, as long as we are connected to the Internet, as long as we want. This is the greatest gift of Docker technology to developers. Finally, I enclose the project address :gitee.com/QiHanXiBei/…

The original article is reprinted from liu Yue’s Technology blog v3u.cn/a_id_164