介绍
Docker 是一个开源的容器平台。它是一个轻量级、虚拟化、便携式、软件定义的标准化环境,允许软件与运行在物理宿主机上的其他软件隔离运行。Docker 提供了一种轻量级的虚拟机替代方案。同时,它还提供了应用程序的便携性、性能、敏捷性和可扩展性。如需了解全面的 Docker 生态系统指南,请参阅我们关于使用 Docker 进行容器化的详细概述.
Flask 是一个开源的微型 Web 框架,构建于 Python。Flask 的一些伟大特性包括轻量、灵活和高度结构化。此外,它不需要任何特定的工具或插件即可运行。
将 Flask 和 Docker 结合使用,可以为您提供一个轻量、灵活且可扩展的应用程序。得益于 Docker 化容器的便携性,您可以将其部署在许多服务器和基础设施上。本教程的重点是向您展示如何使用 Docker 部署 Flask 应用程序。我们还将演示如何确保应用程序的未来更新生效。
前提条件
这是一个动手实践教程,您应该创建一个能够跟着操作的环境:
- 您应该已经安装了 Ubuntu 20.04 作为您的初始运行环境。您还需要创建一个 具有 sudo 特权的非 root 用户.
- 此外,您需要安装 Docker。我们有一篇关于如何在 Ubuntu 上安装和操作 Docker 的教程。请按照步骤 1、2、3 和 4 操作。这适用于任何 Ubuntu 发行版。
- 最后,您需要安装 Nginx。请按照我们关于在 Ubuntu 上安装 Nginx.
现在,让我们开始吧!
步骤 1:准备 Flask 应用程序
我们将首先创建一个用于存放 Flask 应用程序的目录。您可以选择自己喜欢的目录名称。不过,在本教程中,我们将其命名为 flask_demo。我们将把项目文件保存在 /var/www 目录中,这通常是 Ubuntu 默认允许访问公共互联网的目录。首先,执行以下命令创建该目录并进入其中:
|
1 2 3 |
sudo mkdir /var/www/flask_demo cd /var/www/flask_demo |
在此项目的根目录下,我们将创建 Flask 应用程序的基础文件夹结构。接下来,执行以下命令创建基础结构,并添加 -p 参数以同时创建所有父文件夹:
|
1 |
sudo mkdir -p app/static app/templates |
app 文件夹保存与 Flask 应用相关的所有文件,包括 视图 和 蓝图。视图包含您编写的用于响应访问应用程序的请求的代码。蓝图有助于构建应用程序组件并支持 Flask 应用程序中的常见模式。
顾名思义, static 文件夹保存静态资源,如图像、CSS 和 JavaScript 文件。 templates 目录保存项目的所有 HTML 模板。
现在我们可以开始编写初始化 Flask 应用程序所需的文件。首先在 app 目录下创建一个名为 __init__.py 的文件,以告诉 Python 解释器 应该将 app 目录视为一个包。在终端上执行以下命令,使用 nano 编辑器打开该文件:
|
1 |
sudo nano app/__init__.py |
我们在 Python 中使用包将模块分组到逻辑命名空间或层次结构中。模块化允许将代码分解为执行特定功能的、独立的且易于管理的块。
之后,在编辑器中打开的 __init__.py 文件中,添加以下代码片段以启动 Flask 实例,并从您将在后续步骤中创建的 views.py 中导入逻辑:
|
1 2 3 4 5 |
from flask import Flask app = Flask(__name__) from app import views |
完成后,按下 Ctrl + O 和 ENTER 以保存文件,然后使用 关闭它Ctrl + X。接下来,让我们创建 views.py,位于 app 目录中。 views.py 文件将包含大部分应用程序逻辑:
|
1 |
sudo nano app/views.py |
在文件内部,添加以下代码片段。这段代码将显示一个简单的字符串,以便在用户访问您的网站时显示您的应用程序正在运行:
|
1 2 3 4 5 |
from app import app @app.route('/') def home(): return "Our Flask application is running!" |
在此文件中,我们首先导入 Flask 应用程序实例。然后,我们需要添加一行来定义路由: @app.route(/)。 @app.route(/) 行在 Flask 中被称为 装饰器。您可以使用装饰器将附加功能注入到一个或多个函数中。在这种情况下,我们将对路由的调用传递给 / 传递给 home 函数。当用户访问此路由时,他们将看到文本: "Our Flask application is running!".
接下来,您将创建 uwsgi.ini 文件,以保存应用程序的 uWSGI 配置。 uWSGI 是 Nginx 的一种部署选项,充当协议和应用服务器。运行以下命令,使用 nano 编辑器在项目的根目录中创建该文件:
|
1 |
sudo nano uwsgi.ini |
在打开的文件中,添加以下代码片段:
|
1 2 3 4 |
[uwsgi] module = main callable = app master = true |
此文件包含一些指令。我们在下面定义它们的用途:
- module – 定义提供 Flask 应用程序服务的模块。我们将模块设置为 main,引用根目录中的 main.py 文件。我们将在下一步中创建此文件。
- callable – 指示 uWSGI 使用从应用程序导出的 app 实例。
- master – 确保应用程序保持运行,以在重新加载整个应用程序时最大程度地减少停机时间。
完成后保存并关闭文件。
现在您可以创建 main.py 文件来确定应用程序的入口点。 uWSGI 将读取此文件以了解如何与应用程序进行交互。运行以下命令,在项目的 main.py 目录中使用 nano 创建 根 目录 中:
|
1 |
sudo nano main.py |
在文件内部,添加以下行,该行将导入在应用程序包中创建的 Flask 实例:
|
1 |
from app import app |
您在此步骤中要做的最后一件事是定义应用程序运行所需的依赖项。我们将在一个名为 dependencies.txt 的文件中定义这些依赖项。当 Docker 构建应用程序的镜像时,它将执行 pip (包 管理器) 命令来安装依赖项。使用以下命令在根目录中打开该文件:
|
1 |
sudo nano dependencies.txt |
到目前为止,在我们的项目中,我们只需要一个依赖项: Flask。因此,我们可以添加以下行来引用我们项目所需的正确 Flask 版本:
|
1 |
Flask==2.0.1 |
我们决定使用 Flask 版本 2.0.1 作为依赖项。这是撰写本教程时的最新版本。您可以从 Flask Changes 页面了解有关各种版本的更多信息。这样就完成了 Flask 应用程序的设置。现在让我们准备用于部署的 Docker 配置。
Step 2: Configure Docker
要设置 Docker 部署,我们将创建两个文件: Dockerfile 和 start.sh。 Dockerfile 包含构成 Docker 镜像的声明性行。 start.sh 是一个基本的 Shell 脚本,用于构建镜像并从 Dockerfile 启动容器。在项目的根目录中,执行以下命令以创建 Dockerfile:
|
1 |
sudo nano Dockerfile |
此文件包含 Docker 镜像所需的配置。接下来,添加以下代码片段以指定依赖项以及如何构建镜像:
|
1 2 3 4 5 6 7 8 9 10 11 |
FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7 RUN apk --update add bash nano git ENV STATIC_URL /static ENV STATIC_PATH /var/www/app/static COPY ./dependencies.txt /var/www/dependencies.txt RUN pip install -r /var/www/dependencies.txt |
在 Dockerfile 中的第一行定义了我们构建镜像的基础镜像。在这种情况下,我们将基于 tiangolo/uwsgi-nginx-flask,可从 DockerHub 获取。我们选择这个特定的镜像是因为它支持许多 Python 版本。
我们还指定了要更新镜像。然后,我们需要添加 bash 命令处理器、 nano 文本编辑器,以及 git 客户端,用于从版本控制仓库(如 GitHub, Bitbucket, 或 Gitlab)拉取和推送源代码。带有 ENV 的行指定了要在容器中使用的环境变量。
The COPY 命令将依赖项复制到容器中。 RUN 命令调用 pip 包 管理器 来解析 dependencies.txt 文件并 安装 依赖项。编辑完成后保存并关闭文件。
接下来,您将创建 start.sh 脚本。该脚本将包含用于 构建 和 运行 镜像的 Docker 命令。虽然您可以在终端上逐步执行这些命令,但我们认为将它们添加到 Shell 脚本中并只需在终端中用一个命令调用它会更整洁。
在定义此文件的内容之前,我们必须首先确定一个其他服务未使用的空闲端口。我们将使用端口 45644。不过,您可以选择其他端口。执行以下行以检查该端口是否空闲:
|
1 |
sudo nc localhost 45644 < /dev/null; echo $? |
根据您选择的端口,如果上述命令的输出为 1,则表示该端口空闲。否则,您可能需要选择另一个端口并再次尝试该命令:

确定空闲端口后,我们现在可以通过运行以下命令,在项目的根目录下使用 nano 创建该文件:
|
1 |
sudo nano start.sh |
在此文件中,添加以下代码片段:
|
1 2 3 4 5 6 7 |
#!/bin/bash app_name="docker-flask-demo" docker build -t ${app_name} . docker run -d -p 45644:80 --name=${app_name} -v $PWD:/app ${app_name} |
第一行被称为 shebang,指定这是一个 bash 文件,应作为命令执行。第二行声明了一个名为 app_name 的变量。我们使用此变量来设置镜像和容器名称。第三行指示 Docker 构建 镜像,基于 Dockerfile 中的定义。该镜像将被命名为 docker-flask-demo(根据变量命名)。
最后一行创建了一个名为 docker-flask-demo 的容器(根据我们定义的变量)。 -d 标志使容器在命令执行完毕后在后台以分离状态保持运行。 -p 标志将服务器上的端口绑定到容器上的特定端口。在这种情况下,我们将主机上的端口 45644 挂载到 Docker 将在容器中公开的端口 80。
我们使用 -v 标志来指定要挂载到容器上的 Docker 数据卷。 $PWD 变量是一个默认的 Linux 变量,保存了您在特定时间所处的 当前目录的路径:

在我们的例子中,我们将整个项目目录挂载到容器的 /var/www 目录。Docker 配置现在已准备就绪。您可以通过执行以下命令来构建镜像并基于构建 of 镜像启动容器:
|
1 |
sudo bash start.sh |
等待脚本运行完毕,然后执行以下 Docker 命令以列出所有正在运行的容器:
|
1 |
sudo docker ps |
输出将显示正在运行的容器:

您应该在正在运行的容器列表中看到名为 docker-flask-demo 的容器。找到您服务器的公网 IP 并在浏览器中通过指定的端口访问它: http://your-server-public-ip:45644.
您应该会看到类似的输出:

如果您在浏览器中看到上述内容,则说明您已成功部署了 Flask 应用程序。接下来,我们将修改文件并通过模板向用户提供内容。
第 3 步:通过模板文件提供内容
在 Flask 中,模板 用于向网站访问者显示静态和动态内容。我们将向您展示如何创建一个 HTML 模板,并在用户访问特定路由时将其提供给他们。例如,这可以是主页或关于页面。
在终端上执行以下命令,在 index.html 目录中创建一个 app/templates 文件:
|
1 |
sudo nano app/templates/index.html |
然后,将以下代码片段添加到文件中:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Flask 演示</title> </head> <body> <h2>您在主页</h2> <p>欢迎来到 the Flask 与 Docker 演示页面</p> </body> </html> |
完成后保存并关闭文件。此外,使用以下命令创建另一个页面,我们称之为“关于”页面:
|
1 |
sudo nano app/templates/about.html |
将以下代码片段添加到文件中:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>关于 Flask 演示</title> </head> <body> <h2>关于 页面</h2> <p>这 是 一个 演示项目。. 它展示了如何去 构建 一个 Flask 应用,配合Docker 和 Nginx.</p> <p>您可以添加任意 多的页面和 文件,只要 您愿意</p> </body> </html> |
完成后保存并关闭文件。接下来,修改 app/views.py 文件以引用模板以及实际页面的路由:
|
1 |
sudo nano app/views.py |
修改文件,使其看起来像这样:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from flask import render_template from app import app @app.route('/') def home(): return "我们的 Flask 应用程序正在运行!" @app.route('/index') def index(): return render_template('index.html') @app.route('/about') def about(): return render_template('about.html') |
完成后保存并关闭文件。您所做的更改在停止并重新启动容器之前不会生效。运行以下 Docker 命令来停止和启动容器。请注意我们之前定义的容器名称:
|
1 |
sudo docker stop docker-flask-demo && sudo docker start docker-flask-demo |
容器启动并运行后,访问主页和关于页面以查看一些新内容:
|
1 |
主页 页面: http://your-server-public-ip:45644/index |

|
1 |
关于 页面: http://your-server-public-ip:45644/about |

到目前为止,您已经创建了一个可以向网站访问者提供内容的 Flask 应用程序。以下是该项目的文件结构:

您可能已经注意到,我们必须重新启动 Docker 容器才能使其应用新的更改。在下一步中,我们将对此进行自动化,以确保减少停机时间。
第 4 步:配置应用程序文件更新以自动重新加载
我们经常需要对应用程序进行更改,以改进逻辑、用户界面或添加一些依赖项。为了使这些更改生效,可能需要您重新启动 Docker 容器。幸运的是, uWSGI 具有一个名为 touch-reload 的功能,用于在不重新启动容器的情况下重新加载 Python 脚本。
开箱即用,Python 具有一个 auto-reloading 功能,该功能会监视整个文件系统的更改,并在发生更改时刷新应用程序。虽然自动重新加载有利于减少停机时间,但它可能会消耗大量资源。因此,不建议在生产环境中使用。
让我们看看如何使用 touch-reload 来监视特定文件的更改,并在发生更改时重新加载应用程序。使用 nano 编辑器修改 uwsgi.ini 文件:
|
1 |
sudo nano uwsgi.ini |
添加高亮显示的行,使其看起来像这样:
|
1 2 3 4 5 |
[uwsgi] module = main callable = app master = true touch-reload = /app/uwsgi.ini |
完成后保存并关闭文件。添加的行指定了一个文件,修改该文件将触发应用程序的重新加载。但是,为了在以后的修改中激活此条件,您必须先重新启动容器:
|
1 |
sudo docker stop docker-flask-demo && sudo docker start docker-flask-demo |
您现在可以修改 app/views.py 文件来演示自动重新加载的工作原理:
|
1 |
sudo nano app/views.py |
将 home 函数返回的字符串更改为高亮显示的内容:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from flask import render_template from app import app @app.route('/') def home(): return "<h3>Some changes to Our Flask application to auto reload!</h3>" @app.route('/index') def index(): return render_template('index.html') @app.route('/about') def about(): return render_template('about.html') |
完成后保存并关闭文件。
在浏览器中打开应用程序的主页: http://your-server-public-ip:45644.
您还不会看到任何更改。这是因为 touch-reload 条件检测的是对 uwsgi.ini 文件的更改。您可以使用 touch 来激活该条件,从而使用以下命令重新加载整个应用程序:
|
1 |
sudo touch uwsgi.ini |
现在,如果您重新加载主页,您将看到显示的新更改:

以后,如果您进行任何更改,只需运行以下命令: sudo touch uwsgi.ini,整个应用程序将以更短的停机时间重新加载。本教程到此结束。
总结
在本教程中,您使用 Docker 镜像和容器实现并部署了一个 Flask 应用程序。为了通过避免重启容器来最大程度地减少停机时间,您配置了 touch-reload 来监听特定文件的更改并自动重新加载整个应用程序。最后,您在浏览器中测试了所有这些,以确保其正常工作。
Docker 可确保更快的部署并允许轻松扩展应用程序。如果您想了解有关各种 Docker 命令的更多信息,请查看这篇关于 如何在 Ubuntu 上安装和使用 Docker.
有关 Docker 的更多资源,请访问我们的博客,您可以查看以下内容:
- 容器化技术:CloudSigma PaaS 平台上不同容器的类型和用途
- 如何在 Docker 容器和宿主机之间共享数据
- 在 CentOS 7 上安装和设置 Docker
- 使用 Docker Compose 部署 Laravel、Nginx 和 MySQL
- 清理 Docker 资源 – 镜像、容器和数据卷
祝您计算愉快!
评论
暂无评论。发表第一条评论吧。