返回博客

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

在 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 + OENTER 以保存文件,然后使用 关闭它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.shDockerfile 包含构成 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 的更多资源,请访问我们的博客,您可以查看以下内容:

祝您计算愉快!

author

Pranay Kapgate

作者 · CloudSigma

Preslav Dobrev 是 CloudSigma 的创意设计师,专注于通过传统和创新营销渠道打造一致的企业形象。他擅长将艺术愿景与战略营销相融合,创造具有影响力的品牌叙事。

评论

暂无评论。发表第一条评论吧。