Flask + Docker 容器化部署Python应用

文章目录

      • 1. 基础介绍
        • 1.1 Flask
        • 1.2 Gunicorn
        • 1.3 Docker
      • 2. 基于 Flask 创建 Python 应用
      • 3. 基于 Gunicorn 部署 Flask 项目
      • 4. 基于 Docker 封装 Flask 应用
        • 4.1 requirements.txt
        • 4.2 Dockerfile
        • 4.3 构建Docker镜像
      • 5. 运行 Docker 镜像
        • 5.1 调试模式运行
        • 5.2 生产模式运行

1. 基础介绍

本文将使用Flask开发一个简单的Python web应用程序,并为“容器化”做好准备。然后创建一个Docker映像,并将其部署到测试和生产环境中。

1.1 Flask

python最流行的两个框架之一(django、flask),轻量级是最大的特点

1.2 Gunicorn

Gunicorn:只熟悉熟悉用 java 或者 PHP 做开发的可能对 python 的部署一开始不太理解,Flask应用是一个符合WSGI规范的Python应用,不能独立运行(类似app.run的方式仅适合开发模式),需要依赖其他的组件提供服务器功能。

gunicorn 默认使用同步阻塞的网络模型(-k sync),对于大并发的访问可能表现不够好,我们很方便地顺手套一个gevent来增加并发量

1.3 Docker

Docker是目前主流IT公司广泛接受和使用的,用于构建、管理和保护它们应用程序的工具。

容器,例如Docker允许开发人员在单个操作系统上隔离和运行多个应用程序,而不是为服务器上的每个应用程序专用一个虚拟机。使用容器更轻量级,可以降低成本、更好地使用资源和发挥更高的性能。

2. 基于 Flask 创建 Python 应用

Flask是Python的一个轻量级Web应用框架,简单易用,可以很快速地创建web应用。我们用它来创建此demo应用。

我们创建一个名为FlaskDemo的简单的web应用:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():  
	return """
	

Python Flask in Docker!

A sample web-app for running Flask inside Docker.

"""
if __name__ == "__main__": app.run(debug=True, host='0.0.0.0')

通过命令行 python app.py 运行这个应用:

python app.py

然后在浏览器中访问http://localhost:5000/,可以看到Dockerzing Python app using Flask这样的页面。
但是这样简单运行的话,只要按一下 ctrl + c 终止运行,或者关掉终端,网站就连接不了了,我们要寻求更长久的真正的部署。

Flask + Docker 容器化部署Python应用_第1张图片

3. 基于 Gunicorn 部署 Flask 项目

运行以下命令即可安装这两个利器

pip install gunicorn gevent

在根目录下新建文件 /gunicorn/config.py

workers = 5    # 定义同时开启的处理请求的进程数量,根据网站流量适当调整
worker_class = "gevent"   # 采用gevent库,支持异步处理请求,提高吞吐量
bind = "0.0.0.0:5000"

可以使用gunicorn命令来测试是否可以正确运行,命令如下,打开网址127.0.0.1:5000,将会打开我们的网站。

gunicorn app:app -c gunicorn/config.py

一旦报错,则根据错误提示修复即可。

注:基于 Gunicorn + Gevent 部署flask项目,可以参考之前的一篇文章:基于gunicorn部署flask项目

4. 基于 Docker 封装 Flask 应用

首先: 请确保机器上已安装Docker,如果没有可以参考文章:Ubuntu安装及使用Docker

要在Docker上运行应用程序,首先必须构建一个容器,而且必须包含使用的所有依赖项——在我们的例子中只有Flask。因此,新建一个包含所有依赖包的 requirements.txt 文件,然后创建一个Dockerfile,该文件用来描述构建映像过程。

4.1 requirements.txt

首先我们需要为该应用创建一个 requirements.txt 文件,以便容器里面 python 环境的安装。
requirements.txt

# 可以给出具体版本
gunicorn==20.1.0
flask==1.0.2
pandas==0.23.0
numpy==1.14.3
# gevent...

requirements.txt 是做 python 项目常写的一个文件,有了这个文件,在安装 python 应用依赖的三方包时,可以直接用如下命令执行:

pip install -r requirements.txt

当然我们这里先不用执行。

接下来,需要将应用程序运行所需的所有Python文件都放在顶层文件夹apps中。
注: 建议将主入口程序命名为 app.py,将脚本中创建的Flask对象命名为 app 是一种通常的做法,这样也可以简化部署 (对应于部署命令 gunicorn -c gunicorn/config.py app:app 中的 app:app )。

FlaskApp  
    └── apps
        └── < .py files>
        └── < .py files>
    └── gunicorn
        └── config.py
    ├── app.py
    ├── Dockerfile
    ├── requirements.txt
    

4.2 Dockerfile

然后我们还要创建一个 Dockerfile 文件,以便 Docker 镜像的构建。
Dockerfile

FROM ubuntu:18.04
WORKDIR /

COPY ./requirements.txt /requirements.txt

RUN apt-get update -y && \  
    apt-get install -y python3-pip python3-dev

COPY ./requirements.txt /requirements.txt

RUN pip3 install -r requirements.txt
# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

COPY . /
## 使用gunicorn
CMD ["gunicorn", "app:app", "-c", "./gunicorn/config.py"]

## 若不使用gunicorn, 可将 CMD ["gunicorn"...] 替换成下面2行命令
# ENTRYPOINT [ "python3" ]
# CMD [ "app.py" ]  # 不使用gunicorn, 直接python运行app.py

Dockerfile的基本指令有十三个,上面用到了部分;

  • FROM - 所有Dockerfile的第一个指令都必须是 FROM ,用于指定一个构建镜像的基础源镜像,如果本地没有就会从公共库中拉取,没有指定镜像的标签会使用默认的latest标签,如果需要在一个Dockerfile中构建多个镜像,可以使用多次。
  • MAINTAINER - 描述镜像的创建者,名称和邮箱。
  • RUN - RUN命令是一个常用的命令,执行完成之后会成为一个新的镜像,通常用于运行安装任务从而向映像中添加额外的内容。在这里,我们需更新包,安装 python3 和 pip 。在第二个 RUN 命令中使用 pip 来安装 requirements.txt 文件中的所有包。
  • COPY - 复制本机文件或目录,添加到指定的容器目录, 本例中将 requirements.txt 复制到镜像中。
  • WORKDIR - 为RUN、CMD、ENTRYPOINT指令配置工作目录。可以使用多个WORKDIR指令,后续参数如果是相对路径,则会基于之前命令指定的路径。
  • ENTRYPOINT - 在启动容器的时候提供一个默认的命令项。
  • RUN - CMD [ “app.py” ] 运行 app.py 。

注: 关于Dockerfile的相关说明可以参考博客: Dockerfile文件详解

4.3 构建Docker镜像

现在 Dockerfile 已经准备好了,而且也了解了Docker的构建过程,接下来为我们的应用程序创建Docker映像.
(1) 在Dockerfile的同级目录打开终端, 输入以下命令来创建名为 testflask的映像 :

sudo docker build -t 'testflask' .

需要注意的是这个过程需要一点时间,因为它有几百兆。

注: 构建过程中可能会出现一些报错, 导致 requirements.txt 中的库无法成功安装

  • 提示 pip 版本过低, 建议升级其版本
    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-wu79sfu4/pandas/
You are using pip version 8.1.1, however version 21.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
The command '/bin/sh -c pip3 install -r requirements.txt' returned a non-zero code: 1

解决方案: 升级 pip 版本

pip install --upgrade pip
  • RUN pip3 install -r requirements.txt 过程中出现的其他不明原名的错误
Step 6/9 : RUN pip3 install -r requirements.txt
 ---> Running in 01c9caacab4d
Collecting gunicorn==20.1.0 (from -r requirements.txt (line 1))
Exception:
Traceback (most recent call last):
  File "/usr/share/python-wheels/urllib3-1.13.1-py2.py3-none-any.whl/urllib3/connection.py", line 140, in _new_conn
    (self.host, self.port), self.timeout, **extra_kw)
  File "/usr/share/python-wheels/urllib3-1.13.1-py2.py3-none-any.whl/urllib3/util/connection.py", line 91, in create_connection
    raise err
  File "/usr/share/python-wheels/urllib3-1.13.1-py2.py3-none-any.whl/urllib3/util/connection.py", line 81, in create_connection
    sock.connect(sa)
OSError: [Errno 99] Cannot assign requested address

During handling of the above exception, another exception occurred:
...

解决方案: 可以通过先重启docker服务, 再构建docker镜像查看问题是否解决

service docker restart

(2) 构建完成之后,通过如下命令查看镜像列表,可以发现 testflask 显示在其中:

sudo docker images

在这里插入图片描述

5. 运行 Docker 镜像

5.1 调试模式运行

在开发应用程序的过程中,快速重新构建和测试也很重要,以检查验证过程中的每个中间步骤。为此,web应用程序的开发人员需要依赖于Flask等框架提供的自动重启功能(Debug模式下,修改代码自动重启)。而这一功能也可以在容器中使用。

为了启用自动重启,在启动Docker容器时将主机中的开发目录映射到容器中的app目录。这样Flask就可以监听主机中的文件变化(通过映射)来发现代码更改,并在检测到更改时自动重启应用程序。

此外,还需要将应用程序的端口从容器转发到主机。这是为了能够让主机上的浏览器访问应用程序。

因此,启动Dokcer容器时需要使用 volume-mapping 和 port-forwarding 选项:

docker run --name flask_app(容器名) -v $PWD/app:/app -p 5000:5000 testflask(镜像名)
即:
docker run --name flask_app -v $PWD/app:/app -p 5000:5000 testflask

该命令将会执行以下操作:

  • 基于之前构建的 docker-flask 镜像启动一个容器;
  • 这个容器的名称被设置为 flask_app 。如果没有 ——name 选项,Docker将为容器生成一个名称。显式指定名称可以帮助我们定位容器(用来停止等操作);
  • -v 选项将主机的app目录挂载到容器;
  • -p 选项将容器的端口映射到主机。

看到如下页面说明Debugger模式调试已成功开启.
现在可以通过http://localhost:5000 或者 http://0.0.0.0:5000/ 访问到应用.
Flask + Docker 容器化部署Python应用_第2张图片

5.2 生产模式运行

(1)临时运行docker镜像:

sudo docker run -it --rm -p 5000:5000 testflask

可以看到Docker镜像成功地运行起来了,并处于阻塞状态。这时,我们打开浏览器,输入服务器外网 ip,可以我们的应用已经成功部署上去。

(2)生产环境运行(以daemon方式运行)
先查看所有容器:

docker ps -a
或
docker ps -a --no-trunc #不截断,查看完整信息

在这里插入图片描述可以看到我们刚构建的镜像名称 test-flask-1

sudo docker run -d -p 5000:5000 --name test-flask-1(容器名) testflask(镜像名)
即:
sudo docker run -d -p 5000:5000 --name test-flask-1 testflask

参数说明:

  • ‐d : 后台运行
  • ‐p : 将主机的端口映射到容器的一个端口 主机端口:容器内部的端口

注意1: 记得在服务器的仪表盘(dashboard)的设置里面开启相应的外网端口(这里是 5000)

(1) 查看所有开启的端口

firewall-cmd --list-ports

(2) 开启5000端口

firewall-cmd --zone=public --add-port=5000/tcp --permanent

(3) 重启防火墙,使其生效

firewall-cmd --reload

参考博客: 【解决】:外网访问阿里云服务器80端口失败

注意2: 如果出现报错,我们可以通过 docker 的日志去查看出现问题的原因:

# 查看容器日志
docker logs (容器ID 或 容器名称)

# 查看容器日志
docker logs -f -t  --tail (容器ID 或 容器名称)
如:docker logs -f -t --tail=10 f9e29e8455a5
 -f : 查看实时日志
 -t : 查看日志产生的日期

或者进入容器路径, 查看相关的日志文件.

# 进入容器路径
docker exec -it 容器ID /bin/bash

# 退出容器路径
exit

样例如下 (这里容器ID为 8741291a6fe0) :

xxx@xxx:~/projects/project_name$ docker exec -it 8741291a6fe0 /bin/bash
root@8741291a6fe0:/# 
# 已进入容器路径, 可通过linux命令查看相关日志文件

(3) nginx + uwsgi 部署运行
虽然直接使用Flask裸跑运行应用程序对于开发来说已经足够好了,但是我们需要在生产中使用更健壮的部署方法。

目前主流的部署方案是 nginx + uwsgi,下面我们将介绍如何为生产环境部署web应用程序。Nginx是一个开源web服务器,uWSGI是一个快速、自我修复、开发人员和系统管理员友好的服务器。

这里具体可以参考博客:Docker容器化部署Python应用

【参考博客】:

  • Flask + Docker 无脑部署新手教程:https://zhuanlan.zhihu.com/p/78432719?hmsr=toutiao.io
  • Docker容器化部署Python应用:https://zhuanlan.zhihu.com/p/71251233
  • Nginx+gunicorn+flask+docker算法部署: https://www.cnblogs.com/zhongzhaoxie/p/13684602.html
  • Python 项目的部署,目前互联网公司有哪些成熟的方案?:https://www.zhihu.com/question/38081354

你可能感兴趣的