← Back to blog

在 Ubuntu 20.04 上使用 Docker 构建和部署 Flask 应用程序

Category
在 Ubuntu 20.04 上使用 Docker 构建和部署 Flask 应用程序

介绍

Docker 是一个开源的容器平台。它是一个轻量级、虚拟化、便携式、软件定义的标准化环境,允许软件与运行在物理宿主机上的其他软件隔离运行。Docker 提供了一种轻量级的虚拟机替代方案。同时,它还提供了应用程序的便携性、性能、敏捷性和可扩展性。如需了解全面的 Docker 生态系统指南,请参阅我们关于使用 Docker 进行容器化的详细概述.

Flask 是一个开源的微型 Web 框架,构建于 Python。Flask 的一些伟大特性包括轻量、灵活和高度结构化。此外,它不需要任何特定的工具或插件即可运行。

将 Flask 和 Docker 结合使用,可以为您提供一个轻量、灵活且可扩展的应用程序。得益于 Docker 化容器的便携性,您可以将其部署在许多服务器和基础设施上。本教程的重点是向您展示如何使用 Docker 部署 Flask 应用程序。我们还将演示如何确保应用程序的未来更新生效。

前提条件

这是一个动手实践教程,您应该创建一个能够跟着操作的环境:

现在,让我们开始吧!

步骤 1:准备 Flask 应用程序

我们将首先创建一个用于存放 Flask 应用程序的目录。您可以选择自己喜欢的目录名称。不过,在本教程中,我们将其命名为 flask_demo。我们将把项目文件保存在 /var/www 目录中,这通常是 Ubuntu 默认允许访问公共互联网的目录。首先,执行以下命令创建该目录并进入其中:

在此项目的根目录下,我们将创建 Flask 应用程序的基础文件夹结构。接下来,执行以下命令创建基础结构,并添加 -p 参数以同时创建所有父文件夹:

app 文件夹保存与 Flask 应用相关的所有文件,包括 视图 和 蓝图。视图包含您编写的用于响应访问应用程序的请求的代码。蓝图有助于构建应用程序组件并支持 Flask 应用程序中的常见模式。

顾名思义, static 文件夹保存静态资源,如图像、CSS 和 JavaScript 文件。 templates 目录保存项目的所有 HTML 模板。

现在我们可以开始编写初始化 Flask 应用程序所需的文件。首先在 app 目录下创建一个名为 __init__.py 的文件,以告诉 Python 解释器 应该将 app 目录视为一个包。在终端上执行以下命令,使用 nano 编辑器打开该文件:

我们在 Python 中使用包将模块分组到逻辑命名空间或层次结构中。模块化允许将代码分解为执行特定功能的、独立的且易于管理的块。

之后,在编辑器中打开的 __init__.py 文件中,添加以下代码片段以启动 Flask 实例,并从您将在后续步骤中创建的 views.py 中导入逻辑:

完成后,按下 Ctrl + O 和 ENTER 以保存文件,然后使用 关闭它Ctrl + X。接下来,让我们创建 views.py,位于 app 目录中。 views.py 文件将包含大部分应用程序逻辑:

在文件内部,添加以下代码片段。这段代码将显示一个简单的字符串,以便在用户访问您的网站时显示您的应用程序正在运行:

在此文件中,我们首先导入 Flask 应用程序实例。然后,我们需要添加一行来定义路由: @app.route(/)。 @app.route(/) 行在 Flask 中被称为 装饰器。您可以使用装饰器将附加功能注入到一个或多个函数中。在这种情况下,我们将对路由的调用传递给 / 传递给 home 函数。当用户访问此路由时,他们将看到文本: "Our Flask application is running!".

接下来,您将创建 uwsgi.ini 文件,以保存应用程序的 uWSGI 配置。 uWSGI 是 Nginx 的一种部署选项,充当协议和应用服务器。运行以下命令,使用 nano 编辑器在项目的根目录中创建该文件:

在打开的文件中,添加以下代码片段:

此文件包含一些指令。我们在下面定义它们的用途:

  • module – 定义提供 Flask 应用程序服务的模块。我们将模块设置为 main,引用根目录中的 main.py 文件。我们将在下一步中创建此文件。
  • callable – 指示 uWSGI 使用从应用程序导出的 app 实例。
  • master – 确保应用程序保持运行,以在重新加载整个应用程序时最大程度地减少停机时间。

完成后保存并关闭文件。

现在您可以创建 main.py 文件来确定应用程序的入口点。 uWSGI 将读取此文件以了解如何与应用程序进行交互。运行以下命令,在项目的 main.py  目录中使用 nano 创建 根 目录 中:

在文件内部,添加以下行,该行将导入在应用程序包中创建的 Flask 实例:

您在此步骤中要做的最后一件事是定义应用程序运行所需的依赖项。我们将在一个名为 dependencies.txt 的文件中定义这些依赖项。当 Docker 构建应用程序的镜像时,它将执行 pip (包 管理器) 命令来安装依赖项。使用以下命令在根目录中打开该文件:

到目前为止,在我们的项目中,我们只需要一个依赖项: Flask。因此,我们可以添加以下行来引用我们项目所需的正确 Flask 版本:

我们决定使用 Flask 版本 2.0.1 作为依赖项。这是撰写本教程时的最新版本。您可以从 Flask Changes 页面了解有关各种版本的更多信息。这样就完成了 Flask 应用程序的设置。现在让我们准备用于部署的 Docker 配置。

Step 2: Configure Docker

要设置 Docker 部署,我们将创建两个文件: Dockerfile 和 start.sh。 Dockerfile 包含构成 Docker 镜像的声明性行。 start.sh 是一个基本的 Shell 脚本,用于构建镜像并从 Dockerfile 启动容器。在项目的根目录中,执行以下命令以创建 Dockerfile:

此文件包含 Docker 镜像所需的配置。接下来,添加以下代码片段以指定依赖项以及如何构建镜像:

在 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,则表示该端口空闲。否则,您可能需要选择另一个端口并再次尝试该命令:

Flask application Port Check

确定空闲端口后,我们现在可以通过运行以下命令,在项目的根目录下使用 nano 创建该文件:

在此文件中,添加以下代码片段:

第一行被称为 shebang,指定这是一个 bash 文件,应作为命令执行。第二行声明了一个名为 app_name 的变量。我们使用此变量来设置镜像和容器名称。第三行指示 Docker 构建 镜像,基于 Dockerfile 中的定义。该镜像将被命名为 docker-flask-demo(根据变量命名)。

最后一行创建了一个名为 docker-flask-demo 的容器(根据我们定义的变量)。 -d 标志使容器在命令执行完毕后在后台以分离状态保持运行。 -p 标志将服务器上的端口绑定到容器上的特定端口。在这种情况下,我们将主机上的端口 45644 挂载到 Docker 将在容器中公开的端口 80。

我们使用 -v 标志来指定要挂载到容器上的 Docker 数据卷。 $PWD 变量是一个默认的 Linux 变量,保存了您在特定时间所处的 当前目录的路径:

Flask application pwd

在我们的例子中,我们将整个项目目录挂载到容器的 /var/www 目录。Docker 配置现在已准备就绪。您可以通过执行以下命令来构建镜像并基于构建 of 镜像启动容器:

等待脚本运行完毕,然后执行以下 Docker 命令以列出所有正在运行的容器:

输出将显示正在运行的容器:

Demo Docker

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

您应该会看到类似的输出:

Flask App Running

如果您在浏览器中看到上述内容,则说明您已成功部署了 Flask 应用程序。接下来,我们将修改文件并通过模板向用户提供内容。

第 3 步:通过模板文件提供内容

在 Flask 中,模板 用于向网站访问者显示静态和动态内容。我们将向您展示如何创建一个 HTML 模板,并在用户访问特定路由时将其提供给他们。例如,这可以是主页或关于页面。

在终端上执行以下命令,在 index.html 目录中创建一个 app/templates 文件:

然后,将以下代码片段添加到文件中:

完成后保存并关闭文件。此外,使用以下命令创建另一个页面,我们称之为“关于”页面:

将以下代码片段添加到文件中:

完成后保存并关闭文件。接下来,修改 app/views.py 文件以引用模板以及实际页面的路由:

修改文件,使其看起来像这样:

完成后保存并关闭文件。您所做的更改在停止并重新启动容器之前不会生效。运行以下 Docker 命令来停止和启动容器。请注意我们之前定义的容器名称:

容器启动并运行后,访问主页和关于页面以查看一些新内容:

Flask application Index

 Flask application 1

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

File Structure

您可能已经注意到,我们必须重新启动 Docker 容器才能使其应用新的更改。在下一步中,我们将对此进行自动化,以确保减少停机时间。

第 4 步:配置应用程序文件更新以自动重新加载

我们经常需要对应用程序进行更改,以改进逻辑、用户界面或添加一些依赖项。为了使这些更改生效,可能需要您重新启动 Docker 容器。幸运的是, uWSGI 具有一个名为 touch-reload 的功能,用于在不重新启动容器的情况下重新加载 Python 脚本。

开箱即用,Python 具有一个 auto-reloading 功能,该功能会监视整个文件系统的更改,并在发生更改时刷新应用程序。虽然自动重新加载有利于减少停机时间,但它可能会消耗大量资源。因此,不建议在生产环境中使用。

让我们看看如何使用 touch-reload 来监视特定文件的更改,并在发生更改时重新加载应用程序。使用 nano 编辑器修改 uwsgi.ini 文件:

添加高亮显示的行,使其看起来像这样:

完成后保存并关闭文件。添加的行指定了一个文件,修改该文件将触发应用程序的重新加载。但是,为了在以后的修改中激活此条件,您必须先重新启动容器:

您现在可以修改 app/views.py 文件来演示自动重新加载的工作原理:

将 home 函数返回的字符串更改为高亮显示的内容:

完成后保存并关闭文件。

在浏览器中打开应用程序的主页: http://your-server-public-ip:45644.

您还不会看到任何更改。这是因为 touch-reload 条件检测的是对 uwsgi.ini 文件的更改。您可以使用 touch 来激活该条件,从而使用以下命令重新加载整个应用程序:

现在,如果您重新加载主页,您将看到显示的新更改:

Touch Reload

以后,如果您进行任何更改,只需运行以下命令: sudo touch uwsgi.ini,整个应用程序将以更短的停机时间重新加载。本教程到此结束。

总结

在本教程中,您使用 Docker 镜像和容器实现并部署了一个 Flask 应用程序。为了通过避免重启容器来最大程度地减少停机时间,您配置了 touch-reload 来监听特定文件的更改并自动重新加载整个应用程序。最后,您在浏览器中测试了所有这些,以确保其正常工作。

Docker 可确保更快的部署并允许轻松扩展应用程序。如果您想了解有关各种 Docker 命令的更多信息,请查看这篇关于 如何在 Ubuntu 上安装和使用 Docker.

有关 Docker 的更多资源,请访问我们的博客,您可以查看以下内容:

祝您计算愉快!

Pranay Kapgate

Author · CloudSigma

Comments

No comments yet. Be the first.