如何在 Ubuntu 18.04 上使用 Docker 构建和部署 Flask 应用程序
作者选择了 Write for DOnations 计划。
介绍
Docker 是一个开源应用程序,允许管理员使用容器创建、管理、部署和复制应用程序。容器可以被认为是一个包,其中包含应用程序在操作系统级别运行所需的依赖项。这意味着使用 Docker 部署的每个应用程序都存在于自己的环境中,并且其要求是单独处理的。
Python。之所以称为微框架,是因为它不需要特定的工具或插件来运行。 Flask 框架轻巧灵活,但高度结构化,使其优于其他框架。
使用 Docker 部署 Flask 应用程序将允许您以最少的重新配置跨不同服务器复制应用程序。
在本教程中,您将创建一个 Flask 应用程序并使用 Docker 部署它。本教程还将介绍如何在部署后更新应用程序。
先决条件
要学习本教程,您需要具备以下条件:
- 按照 Ubuntu 18.04 初始服务器设置指南配置的具有 sudo 权限的非根用户。
- 一台安装了 Docker 的 Ubuntu 18.04 服务器,按照一键式 Docker 镜像进行设置。
- 如何在 Ubuntu 18.04 上安装 Nginx 教程。
第 1 步 — 设置 Flask 应用程序
首先,您将创建一个目录结构来保存您的 Flask 应用程序。本教程将在 /var/www
中创建一个名为 TestApp
的目录,但您可以修改命令以将其命名为任何您喜欢的名称。
- sudo mkdir /var/www/TestApp
移动到新创建的 TestApp
目录:
- cd /var/www/TestApp
接下来,为 Flask 应用程序创建基础文件夹结构:
- sudo mkdir -p app/static app/templates
-p
标志表示 mkdir
将创建一个目录和所有不存在的父目录。在这种情况下,mkdir
将在创建 static
和 templates
目录的过程中创建 app
父目录。
app
目录将包含与 Flask 应用程序相关的所有文件,例如其views 和blueprints。蓝图创建应用程序组件并支持应用程序内或跨多个应用程序的通用模式。
static
目录是存放图像、CSS 和 JavaScript 文件等资产的地方。 templates
目录是放置项目 HTML 模板的地方。
现在基本文件夹结构已完成,创建运行 Flask 应用程序所需的文件。首先,在 app
目录中创建一个 __init__.py
文件。这个文件告诉 Python 解释器 app
目录是一个包,应该被这样对待。
运行以下命令来创建文件:
- sudo nano app/__init__.py
Python 中的包允许您将模块分组到逻辑名称空间或层次结构中。这种方法使代码能够分解为执行特定功能的单独且可管理的块。
接下来,您将向 __init__.py
添加代码,这将创建一个 Flask 实例并从 views.py
文件导入逻辑,您将在保存此文件后创建该文件.将以下代码添加到您的新文件中:
from flask import Flask
app = Flask(__name__)
from app import views
添加该代码后,保存并关闭文件。
创建了 __init__.py
文件后,您就可以在 app
目录中创建 views.py
文件了。该文件将包含您的大部分应用程序逻辑。
- sudo nano app/views.py
接下来,将代码添加到您的 views.py
文件中。此代码将向访问您网页的用户返回 hello world!
字符串:
from app import app
@app.route('/')
def home():
return "hello world!"
函数上方的 @app.route
行称为装饰器。装饰器修改它后面的函数。在这种情况下,装饰器告诉 Flask 哪个 URL 将触发 home()
函数。 home
函数返回的hello world
文本将在浏览器上显示给用户。
views.py
文件就位后,您就可以创建 uwsgi.ini
文件了。该文件将包含我们应用程序的uWSGI 配置。 uWSGI 是 Nginx 的一个部署选项,它既是一个协议又是一个应用服务器;应用服务器可以服务于 uWSGI、FastCGI 和 HTTP 协议。
要创建此文件,请运行以下命令:
- sudo nano uwsgi.ini
接下来,将以下内容添加到您的文件以配置 uWSGI 服务器:
[uwsgi]
module = main
callable = app
master = true
此代码定义了 Flask 应用程序将从中提供服务的模块。在本例中,这是 main.py
文件,此处引用为 main
。 callable
选项指示uWSGI使用主应用导出的app
实例。 master
选项允许您的应用程序继续运行,因此即使重新加载整个应用程序也几乎没有停机时间。
接下来,创建 main.py
文件,这是应用程序的入口点。入口点指示 uWSGI 如何与应用程序交互。
- sudo nano main.py
接下来,将以下内容复制并粘贴到文件中。这将从先前创建的应用程序包中导入名为 app
的 Flask 实例。
from app import app
最后,创建一个 requirements.txt
文件来指定 pip
包管理器将安装到您的 Docker 部署中的依赖项:
- sudo nano requirements.txt
添加以下行以将 Flask 添加为依赖项:
Flask==1.0.2
这指定要安装的 Flask 版本。在编写本教程时,1.0.2
是最新的 Flask 版本。您可以在 Flask 的官方网站上检查更新。
保存并关闭文件。您已成功设置 Flask 应用程序并准备好设置 Docker。
第 2 步 — 设置 Docker
在此步骤中,您将创建两个文件,Dockerfile
和 start.sh
,以创建您的 Docker 部署。 Dockerfile
是一个文本文档,其中包含用于组装图像的命令。 start.sh
文件是一个 shell 脚本,它将构建一个图像并从 Dockerfile
创建一个容器。
首先,创建 Dockerfile
。
- sudo nano Dockerfile
接下来,将所需的配置添加到 Dockerfile
。这些命令指定将如何构建图像,以及将包含哪些额外要求。
FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7
RUN apk --update add bash nano
ENV STATIC_URL /static
ENV STATIC_PATH /var/www/app/static
COPY ./requirements.txt /var/www/requirements.txt
RUN pip install -r /var/www/requirements.txt
在此示例中,Docker 映像将基于现有映像 tiangolo/uwsgi-nginx-flask
构建,您可以在 DockerHub 上找到该映像。这个特殊的 Docker 镜像是一个不错的选择,因为它支持广泛的 Python 版本和操作系统镜像。
前两行指定您将用于运行应用程序并安装 bash 命令处理器和 nano
文本编辑器的父映像。它还安装了 git
客户端,用于拉取和推送到版本控制托管服务,例如 GitHub、GitLab 和 Bitbucket。 ENV STATIC_URL /static
是特定于此 Docker 映像的环境变量。它定义了静态文件夹,其中提供所有资产,例如图像、CSS 文件和 JavaScript 文件。
最后两行会将requirements.txt
文件复制到容器中执行,然后解析requirements.txt
文件安装指定的依赖。
添加配置后保存并关闭文件。
Dockerfile
就绪后,您几乎可以编写将构建 Docker 容器的 start.sh
脚本。在编写 start.sh
脚本之前,首先确保您有一个开放的端口用于配置。要检查端口是否空闲,请运行以下命令:
- sudo nc localhost 56733 < /dev/null; echo $?
如果上述命令的输出为 1
,则端口空闲且可用。否则,您将需要选择一个不同的端口以在您的 start.sh
配置文件中使用。
找到要使用的开放端口后,创建 start.sh
脚本:
sudo nano start.sh
start.sh
脚本是一个 shell 脚本,它将从 Dockerfile
构建一个图像,并从生成的 Docker 图像创建一个容器。将您的配置添加到新文件:
#!/bin/bash
app="docker.test"
docker build -t ${app} .
docker run -d -p 56733:80 \
--name=${app} \
-v $PWD:/app ${app}
第一行称为 shebang。它指定这是一个 bash 文件并将作为命令执行。下一行指定您要为图像和容器指定的名称,并将其保存为名为 app
的变量。下一行指示 Docker 从位于当前目录中的 Dockerfile
构建映像。在此示例中,这将创建一个名为 docker.test
的图像。
最后三行创建了一个名为 docker.test
的新容器,该容器暴露在端口 56733
上。最后,它将当前目录链接到容器的 /var/www
目录。
您使用 -d
标志以守护进程模式或作为后台进程启动容器。您包括 -p
标志以将服务器上的端口绑定到 Docker 容器上的特定端口。在这种情况下,您将端口 56733
绑定到 Docker 容器上的端口 80
。 -v
标志指定要挂载到容器上的 Docker 卷,在这种情况下,您将整个项目目录挂载到 Docker 上的 /var/www
文件夹容器。
执行 start.sh
脚本来创建 Docker 镜像并从生成的镜像构建容器:
- sudo bash start.sh
脚本完成运行后,使用以下命令列出所有正在运行的容器:
- sudo docker ps
您将收到显示容器的输出:
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
58b05508f4dd docker.test "/entrypoint.sh /sta…" 12 seconds ago Up 3 seconds 443/tcp, 0.0.0.0:56733->80/tcp docker.test
你会发现 docker.test
容器正在运行。现在它正在运行,在浏览器中访问指定端口的IP地址:http://ip-address:56733
您会看到类似于以下内容的页面:

在此步骤中,您已成功将 Flask 应用程序部署到 Docker 上。接下来,您将使用模板向用户显示内容。
第 3 步 — 提供模板文件
模板是向访问您的应用程序的用户显示静态和动态内容的文件。在此步骤中,您将创建一个 HTML 模板来为应用程序创建主页。
首先在 app/templates
目录中创建一个 home.html
文件:
- sudo nano app/templates/home.html
添加模板的代码。此代码将创建一个包含标题和一些文本的 HTML5 页面。
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Welcome home</title>
</head>
<body>
<h1>Home Page</h1>
<p>This is the home page of our application.</p>
</body>
</html>
添加模板后保存并关闭文件。
接下来,修改 app/views.py
文件以提供新创建的文件:
- sudo nano app/views.py
首先,在文件开头添加以下行以从 Flask 导入 render_template
方法。此方法解析 HTML 文件以向用户呈现网页。
from flask import render_template
...
在文件末尾,您还将添加一个新路由来呈现模板文件。此代码指定用户在访问您的应用程序上的 /template
路由时,将获得 home.html
文件的内容。
...
@app.route('/template')
def template():
return render_template('home.html')
更新后的 app/views.py
文件将如下所示:
from flask import render_template
from app import app
@app.route('/')
def home():
return "Hello world!"
@app.route('/template')
def template():
return render_template('home.html')
完成后保存并关闭文件。
为了使这些更改生效,您需要停止并重新启动 Docker 容器。运行以下命令重建容器:
- sudo docker stop docker.test && sudo docker start docker.test
在 http://your-ip-address:56733/template
访问您的应用程序以查看正在提供的新模板。

在这里,您创建了一个 Docker 模板文件来为您的应用程序的访问者提供服务。在下一步中,您将看到您对应用程序所做的更改如何在无需重新启动 Docker 容器的情况下生效。
第 4 步 — 更新应用程序
有时您需要对应用程序进行更改,无论是安装新需求、更新 Docker 容器,还是 HTML 和逻辑更改。在本节中,您将配置 touch-reload
以在无需重新启动 Docker 容器的情况下进行这些更改。
Python 自动重新加载 监视整个文件系统的变化并在检测到变化时刷新应用程序。在生产中不鼓励自动重新加载,因为它会很快变成资源密集型。在此步骤中,您将使用 touch-reload
来监视特定文件的更改并在文件更新或替换时重新加载。
要实现这一点,首先打开您的 uwsgi.ini
文件:
- sudo nano uwsgi.ini
接下来,将突出显示的行添加到文件末尾:
module = main
callable = app
master = true
touch-reload = /app/uwsgi.ini
这指定了一个文件,该文件将被修改以触发整个应用程序重新加载。完成更改后,保存并关闭文件。
为了演示这一点,请对您的应用程序进行一些小改动。首先打开您的 app/views.py
文件:
- sudo nano app/views.py
替换 home
函数返回的字符串:
from flask import render_template
from app import app
@app.route('/')
def home():
return "<b>There has been a change</b>"
@app.route('/template')
def template():
return render_template('home.html')
进行更改后保存并关闭文件。
接下来,如果您在 http://ip-address:56733
打开您的应用程序主页,您会注意到更改没有反映出来。这是因为重新加载的条件是更改 uwsgi.ini
文件。要重新加载应用程序,请使用 touch
激活条件:
- sudo touch uwsgi.ini
再次在浏览器中重新加载应用程序主页。您会发现该应用程序已包含更改:

在此步骤中,您设置了一个 touch-reload
条件以在进行更改后更新您的应用程序。
结论
在本教程中,您创建了一个 Flask 应用程序并将其部署到 Docker 容器中。您还配置了 touch-reload
来刷新您的应用程序而无需重新启动容器。
使用 Docker 上的新应用程序,您现在可以轻松扩展。要了解有关使用 Docker 的更多信息,请查看其官方文档。