Docker基础知识 (11) - 使用 Docker 部署 Nginx + Gunicorn + Flask 项目
Gunicorn 是一个 Unix 上被广泛使用的高性能的 Python WSGI UNIX HTTP Server。它和大多数的 Web 框架兼容,并具有实现简单,轻量级,高性能等特点。
Gunicorn 是一个移植自 Ruby 的 Unicorn 项目的 pre-fork worker 模型,即支持 eventlet 也支持greenlet。Gunicorn 启动项目之后一定会有一个主进程 Master 和一个或者多个工作进程。工作进程的数量可以指定,工作进程是实际处理请求的进程,主进程维护服务器的运行。
Gunicorn 默认使用 gevent 同步阻塞的网络模型(-k sync),对于大并发的访问可能表现不够好,但是可以使用 gevent 来增加并发量。
Gunicorn VS uWSGI
(1) 两个都是实现了 WSGI协议 的Web服务器,并且都是基于 Perfork 模型。
(2) uWSGI 是用 C 语言编写的,Gunicorn 是用 Python 语言编写的,相对于 uWSGI,Gunicorn 相对简单,启动也十分方便。
Gunicorn GitHub: https://github.com/benoitc/gunicorn
Flask 是一个轻量级的可定制框架,使用 Python 语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。它可以很好地结合 MVC 模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或 Web 服务的实现。
Flask GitHub: https://github.com/pallets/flask
1. 部署 Gunicorn + Flask
1) 部署环境
IP 地址(本地测试环境):192.168.0.10
操作系统:Linux CentOS 7.9
Docker 版本: 20.10.7
gunicorn 目录:/home/docker/gunicorn # 在 Docker 所在主机上,手动创建各级目录,下同
2) 创建 Flask 项目
$ cd /home/docker/gunicorn
$ mkdir flaskapp
$ cd flaskapp
$ vim app.py
from flask import Flask app = Flask(__name__) @app.route('/') def home(): return 'Gunicorn/Flask - Hello World!'
3) 创建 gunicorn.conf.py 文件
$ cd /home/docker/gunicorn/flaskapp
$ vim gunicorn.conf.py
bind="0.0.0.0:8002"
workers=5
worker_class="gevent"
4) 创建 Dockerfile
$ cd /home/docker/gunicorn/flaskapp
$ vim Dockerfile
FROM python:3.8
WORKDIR /home/docker/gunicorn/flaskapp
# COPY 指令和 ADD 指令功能和使用方式类似,COPY 指令不会做自动解压文件
#COPY . /home/docker/gunicorn/flaskapp
RUN pip install -i https://mirrors.aliyun.com/pypi/simple gunicorn gevent
RUN pip install -i https://mirrors.aliyun.com/pypi/simple flask==2.0.0
EXPOSE 8002
CMD ["gunicorn", "-c", "/home/docker/gunicorn/flaskapp/gunicorn.conf.py", "app:app"]
注:也可以使用镜像网站 https://pypi.tuna.tsinghua.edu.cn/simple。
本文后面运行容器时,把 /home/docker/gunicorn/flaskapp 挂载到容器内的 /home/docker/gunicorn/flaskapp 目录,所以不使用 COPY 命令。
如果使用 Django 项目代替 Flask 项目,假设 Django 项目名称为 demo,修改 Dockerfile 文件如下:
FROM python:3.8
WORKDIR /home/docker/gunicorn/demo
# COPY 指令和 ADD 指令功能和使用方式类似,COPY 指令不会做自动解压文件
#COPY . /home/docker/gunicorn/demo
RUN pip install -i https://mirrors.aliyun.com/pypi/simple gunicorn gevent
RUN pip install -i https://mirrors.aliyun.com/pypi/simple django==3.0.1
EXPOSE 8002
CMD ["gunicorn", "-c", "/home/docker/gunicorn/demo/gunicorn.conf.py", "demo.wsgi:application"]
5) 创建 python_gunicorn 镜像,并运行容器
$ cd /home/docker/gunicorn/flaskapp
# 创建镜像
$ docker build -t python_gunicorn:3.8-20.1.0 .
Sending build context to Docker daemon 4.096kB Step 1/6 : FROM python:3.8 ---> a08150c12a68 Step 2/6 : WORKDIR /home/docker/gunicorn/flaskapp ---> Running in b814e286f851 Removing intermediate container b814e286f851 ---> 4c603e0cf191 Step 3/6 : RUN pip install -i https://mirrors.aliyun.com/pypi/simple gunicorn gevent ---> Running in 5dd99993625d Looking in indexes: https://mirrors.aliyun.com/pypi/simple Collecting gunicorn Downloading https://mirrors.aliyun.com/pypi/packages/e4/dd/5b190393e6066286773a67dfcc2f9492058e9b57c4867a95f1ba5caf0a83/gunicorn-20.1.0-py3-none-any.whl (79 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 79.5/79.5 KB 2.5 MB/s eta 0:00:00 Collecting gevent Downloading https://mirrors.aliyun.com/pypi/packages/68/13/95b3272019d69984ba044c6783de5efea76b0d92c97d96bfe832ec7dc6fa/gevent-21.12.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (6.5 MB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.5/6.5 MB 1.4 MB/s eta 0:00:00 Requirement already satisfied: setuptools>=3.0 in /usr/local/lib/python3.8/site-packages (from gunicorn) (57.5.0) Collecting zope.interface Downloading https://mirrors.aliyun.com/pypi/packages/e9/56/945a20c9efe2a5f68cc176b525131830c4392992ceccef91902d823de7ef/zope.interface-5.4.0-cp38-cp38-manylinux2010_x86_64.whl (259 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 259.2/259.2 KB 1.1 MB/s eta 0:00:00 Collecting greenlet<2.0,>=1.1.0 Downloading https://mirrors.aliyun.com/pypi/packages/5c/93/654613aeeda6fc8f65227d6d2b9f0c469f324ec12cb1511430e77da4875b/greenlet-1.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (157 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 157.1/157.1 KB 2.1 MB/s eta 0:00:00 Collecting zope.event Downloading https://mirrors.aliyun.com/pypi/packages/9e/85/b45408c64f3b888976f1d5b37eed8d746b8d5729a66a49ec846fda27d371/zope.event-4.5.0-py2.py3-none-any.whl (6.8 kB) Installing collected packages: zope.interface, zope.event, gunicorn, greenlet, gevent Successfully installed gevent-21.12.0 greenlet-1.1.3 gunicorn-20.1.0 zope.event-4.5.0 zope.interface-5.4.0 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv WARNING: You are using pip version 22.0.4; however, version 22.2.2 is available. You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command. Removing intermediate container 5dd99993625d ---> bab804b908e5 Step 4/6 : RUN pip install -i https://mirrors.aliyun.com/pypi/simple flask==2.0.0 ---> Running in a1d03ee7e1c1 Looking in indexes: https://mirrors.aliyun.com/pypi/simple Collecting flask==2.0.0 Downloading https://mirrors.aliyun.com/pypi/packages/bf/73/9180d22a40da68382e9cb6edb66a74bf09cb72ac825c130dce9c5a44198d/Flask-2.0.0-py3-none-any.whl (93 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 93.2/93.2 KB 2.0 MB/s eta 0:00:00 Collecting Jinja2>=3.0 Downloading https://mirrors.aliyun.com/pypi/packages/bc/c3/f068337a370801f372f2f8f6bad74a5c140f6fda3d9de154052708dd3c65/Jinja2-3.1.2-py3-none-any.whl (133 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 133.1/133.1 KB 1.7 MB/s eta 0:00:00 Collecting click>=7.1.2 Downloading https://mirrors.aliyun.com/pypi/packages/c2/f1/df59e28c642d583f7dacffb1e0965d0e00b218e0186d7858ac5233dce840/click-8.1.3-py3-none-any.whl (96 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 96.6/96.6 KB 1.3 MB/s eta 0:00:00 Collecting itsdangerous>=2.0 Downloading https://mirrors.aliyun.com/pypi/packages/68/5f/447e04e828f47465eeab35b5d408b7ebaaaee207f48b7136c5a7267a30ae/itsdangerous-2.1.2-py3-none-any.whl (15 kB) Collecting Werkzeug>=2.0 Downloading https://mirrors.aliyun.com/pypi/packages/c8/27/be6ddbcf60115305205de79c29004a0c6bc53cec814f733467b1bb89386d/Werkzeug-2.2.2-py3-none-any.whl (232 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 232.7/232.7 KB 1.8 MB/s eta 0:00:00 Collecting MarkupSafe>=2.0 Downloading https://mirrors.aliyun.com/pypi/packages/fd/f4/524d2e8f5a3727cf309c2b7df7c732038375322df1376c9e9ef3aa92fcaf/MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (25 kB) Installing collected packages: MarkupSafe, itsdangerous, click, Werkzeug, Jinja2, flask Successfully installed Jinja2-3.1.2 MarkupSafe-2.1.1 Werkzeug-2.2.2 click-8.1.3 flask-2.0.0 itsdangerous-2.1.2 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv WARNING: You are using pip version 22.0.4; however, version 22.2.2 is available. You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command. Removing intermediate container a1d03ee7e1c1 ---> 477efff863c6 Step 5/6 : EXPOSE 8002 ---> Running in da9c964a1cf3 Removing intermediate container da9c964a1cf3 ---> 7b656d9d23b5 Step 6/6 : CMD ["gunicorn", "-c", "/home/docker/gunicorn/flaskapp/gunicorn.conf.py", "app:app"] ---> Running in a697ed437326 Removing intermediate container a697ed437326 ---> d91f75cfb6ec Successfully built d91f75cfb6ec Successfully tagged python_gunicorn:3.8-20.1.0
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
python_gunicorn 3.8-20.1.0 bb447fd877d1 About a minute ago 961MB
python 3.8 a08150c12a68 2 weeks ago 912MB
# 运行容器
$ docker run --name python_gunicorn-3.8 -p 8002:8002\
-v /home/docker/gunicorn/flaskapp:/home/docker/gunicorn/flaskapp\
--privileged=true\
-d python_gunicorn:3.8-20.1.0
$ docker exec -it python_gunicorn-3.8 /bin/bash # 进入容器
root@af34e34693e1:/home/docker/gunicorn/flaskapp# ls
Dockerfile __pycache__ app.py gunicorn.conf.py
root@af34e34693e1:/home/docker/gunicorn/flaskapp# exit
浏览器访问 http://192.168.0.10:8002,动态页面显示结果如下:
Gunicorn/Flask - Hello World!
2. 部署 Nginx + Gunicorn + Flask
1) 部署环境
IP 地址(本地测试环境):192.168.0.10
操作系统:Linux CentOS 7.9
Docker 版本: 20.10.7
2) 拉取 nginx 镜像
$ docker pull nginx # 相当于 docker pull nginx:latest
$ docker images # 查看镜像列表
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 2b7d6430f78d 10 days ago 142MB
...
注:可以访问 Dockers Hub(https://hub.docker.com/_/nginx?tab=tags)查询 Nginx 镜像。
3) 配置 nginx
由于 Gunicorn 和 Flask 处理静态文件的能力较弱,所以本文把 nginx 配置为动态文件的代理服务器,nginx 自己处理静态文件。
(1) 创建 nginx.conf 文件
在 Docker 所在主机上,创建 /home/docker/nginx/conf.d 目录,在该目录下创建 nginx.conf 文件。
server {
listen 80 default_server;
server_name localhost;
location / {
proxy_pass http://python_gunicorn-3.8:8002;
}
# nginx 自己处理 /static 对应的静态文件
root /usr/share/nginx/html;
location /static {
alias /usr/share/nginx/html;
}
}
参数说明:
(1) server.location.proxy_pass: http://python_gunicorn-3.8:8002 表示 “容器名称:端口”,也可以写成 “http://ip:端口”,获取 ip 的方法,运行如下命令:
$ docker inspect --format='{{.NetworkSettings.IPAddress}}' python_gunicorn-3.8
172.17.0.2
(2) server.root: /usr/share/nginx/html 是 nginx 容器内的路径。静态文件 (HTML/CSS/JS/Images 等文件)对应的映射目录是 /usr/share/nginx/html;
location /static: nginx 自己处理 /static 对应的静态文件
(2) 创建 hello.html 文件
$ cd /home/docker/nginx/html
$ vim hello.html
<h3>Nginx/Gunicorn/Flask - hello.html</h3>
注:这种模式下,静态文件由 nginx 处理,nginx 容器内的静态文件目录是 /usr/share/nginx/html,运行 nginx 容器会把 Docker 所在主机上的 /home/docker/nginx/html 挂载到 /usr/share/nginx/html。
(3) 运行 nginx 容器
$ docker run --name nginx-gunicorn-3.8 -p 8889:80\
-v /home/docker/nginx/html:/usr/share/nginx/html\
-v /home/docker/nginx/conf.d:/etc/nginx/conf.d\
--privileged=true\
--link python_gunicorn-3.8\
-d nginx
参数说明:
--name nginx-gunicorn-3.8:将容器命名为 nginx-gunicorn-3.8。
-p 8889:80:端口进行映射,将本地 8889 端口映射到容器内部的 80 端口。
-v:将本地文件夹与容器文件夹挂载。
--privileged=true:使用该参数,容器内的 root 拥有真正的 root 权限。否则,容器内的 root 只是外部的一个普通用户权限。
-d:设置容器在后台一直运行。
nginx: 这里表示 nginx:latest,镜像:tag。
$ docker ps # 查看运行的容器列表
浏览器访问 http://192.168.0.10:8889/,动态页面显示如下:
Gunicorn/Flask - Hello World!
浏览器访问 http://192.168.0.10:8889/static/hello.html,静态页面显示如下:
Nginx/Gunicorn/Flask - hello.html
浙公网安备 33010602011771号