用 Anaconda 开启一个新的环境
创建一个新的 conda 环境,并取名为 flask
1 conda create --name flask python=3
激活 flask
环境
开启一个简单的 Flask 服务
用 pip 安装 Flask
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from flask import Flask, request, jsonify app = Flask(__name__) app.config['JSON_AS_ASCII' ] = False @app.route("/hello" , methods=["GET" ] ) def hello_world (): name = request.args.get("name" , "" ) return jsonify({ "err_code" : 0 , "ret" : f"Hello, {name} " })if __name__ == "__main__" : app.run()
运行程序,得到如下输出结果:
1 2 3 4 5 * Serving Flask app 'main' * Debug mode: off WARNING : This is a development server . Do not use it in a production deployment. Use a production WSGI server instead . * Running on http://127.0 .0 .1 :5000 Press CTRL+C to quit
然后浏览器打开:
1 http:// 127.0 .0.1 :5000 /hello?name=AI探险家
就会从浏览器中得到如下结果:
1 { "err_code" : 0 , "ret" : "Hello, AI探险家" }
从前面开启服务的输出结果可以看出,我们的 Flask 应用目前是一个开发服务。 要正式部署的话,建议使用 WSGI。那我们就接受建议,使用 uWSGI
搭配 nginx
来部署服务搭配。
安装 uWSGI
首先安装 uWSGI 相关的依赖环境。下面是 Ubuntu 系统下的安装命令
1 apt-get install build-essential python-dev
其他操作系统可以参考官方安装教程:Installing uWSGI
接下来是安装 uwsgi
。理论上可以直接用 pip
安装。
奇怪的是,我这边在 Anaconda 环境中用 pip
安装 uwsgi
会报错。用 conda
命令来安装则是正常的:
1 conda install -c conda-forge uwsgi
配置 uWSGI
在 main.py
同个目录创建一个 uwsgi.ini
文件:
1 2 3 4 5 6 7 8 9 10 11 [uwsgi] module = main:appuid = www-datagid = www-datamaster = true processes = 5 socket = /tmp/uwsgi.socketchmod-sock = 664 vacuum = true
在这份配置文件中,调用的模块是 main.py
的 app
。然后使用 www-data
(WEB 服务的标准用户) 作为 uwsgi
进程的 uid/gid
。 通过 processes
指定 5 个进程。另外,我们给 uwsgi
创建了一个 socket 文件 /tmp/uwsgi.socket
,并赋予 664 的执行权限。 作为对比,也可以直接给 socket 设置端口号,例如:、
1 2 3 4 [uwsgi] ...socket = :3032 ...
另外,当我们退出进程时,希望 /tmp/uwsgi.socket
文件能够被自动删除,因此可以设置 vacuum = true
来实现这个功能。
运行 uwsgi
得到如下输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 [uWSGI] getting INI configuration from uwsgi.ini *** Starting uWSGI 2.0 .21 (64 bit) on [Tue Apr 18 21 :13 :37 2023 ] *** compiled with version : 11.2 .0 on 28 March 2023 07 :32 :14 os: Linux-5.15 .90 .1 -microsoft-standard-WSL2 #1 SMP Fri Jan 27 02 :56 :13 UTC 2023 nodename: Airme machine: x86_64 clock source: unix pcre jit disabled detected number of CPU cores: 20 current working directory: /home/aizpy/Workspace/FlaskTest detected binary path : /home/aizpy/miniconda3/envs/flask/bin/uwsgi your processes number limit is 63631 your memory page size is 4096 bytes detected max file descriptor number: 1024 lock engine: pthread robust mutexes thunder lock : disabled (you can enable it with uwsgi socket 0 bound to UNIX address /tmp/uwsgi.socket fd 3 Python version : 3.11 .2 (main, Mar 27 2023 , 23 :42 :44 ) [GCC 11.2 .0 ] *** Python threads support is disabled. You can enable it with Python main interpreter initialized at 0xa01a98 your server socket listen backlog is limited to 100 connections your mercy for graceful operations on workers is 60 seconds mapped 437520 bytes (427 KB) for 5 cores *** Operational MODE: preforking *** WSGI app 0 (mountpoint='' ) ready in 0 seconds on interpreter 0xa01a98 pid: 13221 (default app) *** uWSGI is running in multiple interpreter mode *** spawned uWSGI master process (pid: 13221 ) spawned uWSGI worker 1 (pid: 13222 , cores: 1 ) spawned uWSGI worker 2 (pid: 13223 , cores: 1 ) spawned uWSGI worker 3 (pid: 13224 , cores: 1 ) spawned uWSGI worker 4 (pid: 13225 , cores: 1 ) spawned uWSGI worker 5 (pid: 13226 , cores: 1 )
确实创建了 5 个进程。当输入Ctrl-C
来退出进程时,可以看到如下输出:
1 2 3 4 5 6 7 8 ^CSIGINT/SIGTERM received...killing workers... worker 1 buried after 1 seconds worker 2 buried after 1 seconds worker 3 buried after 1 seconds worker 4 buried after 1 seconds worker 5 buried after 1 seconds goodbye to uWSGI. VACUUM: unix socket /tmp/uwsgi.socket removed.
此时,5 个进程全部退出了,并且 /tmp/uwsgi.socket
文件也被删除了。
生成依赖环境
1 pip freeze > requirements.txt
需要注意的是,如果你是通过 conda 安装的 uwsgi,那么执行这个命令后,uWSGI 这一条会变成类似这样的结果:
1 uWSGI @ file:// /croot/u wsgi_1679988297904/work
这是一个绝对路径,无法部署到其他机器上。此时可以根据之前 conda 的安装结果,来指定 uwsgi 的版本号。例如:
最终的 requirements.txt
长这样:
1 2 Flask = = 2.2 .3 uWSGI = = 2.0 .21
这里删掉了中间的依赖项,因为安装这两个库就会自动安装其他的。
配置 nginx
创建一份 nginx.conf
文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 user www-data;worker_processes auto;pid /run/nginx.pid;events { worker_connections 1024 ; use epoll ; multi_accept on ; }http { access_log /dev/stdout; error_log /dev/stdout; sendfile on ; tcp_nopush on ; tcp_nodelay on ; keepalive_timeout 65 ; types_hash_max_size 2048 ; include /etc/nginx/mime.types; default_type application/octet-stream; index index.html index.htm; server { listen 80 default_server; listen [::]:80 default_server; server_name localhost; root /var/www/html; location / { include uwsgi_params; uwsgi_pass unix:/tmp/uwsgi.socket; } } }
创建执行脚本
创建一个启动脚本 start.sh
1 2 3 # !/usr/bin/env bash service nginx start uwsgi --ini uwsgi.ini
编写 Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 FROM ubuntu:22.04 MAINTAINER aizpy "aizpy@outlook.com" EXPOSE 80 COPY . /srv/app WORKDIR /srv/app RUN apt-get clean && apt-get -y update RUN apt-get install -y nginx python3-dev build-essential pip RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple COPY nginx.conf /etc/nginx RUN chmod +x ./start.sh CMD ["./start.sh" ]
通过 Dockerfile 创建镜像
1 docker build . -t my_flask_app
生成容器并运行
1 docker run --name flask_app -p 80:80 my_flask_app
参考