作为Write for DOnations计划的一部分,作者选择了技术教育基金来接受捐赠。
介绍
Docker是一个开源应用程序,允许管理员使用容器创建、管理、部署和复制应用程序。容器可以被认为是一个包,其中包含应用程序在操作系统级别运行所需的依赖项。这意味着使用 Docker 部署的每个应用程序都存在于自己的环境中,并且其需求是单独处理的。
Flask是一个基于Python的 Web 微框架。之所以称为微框架,是因为它不需要特定的工具或插件即可运行。Flask 框架是轻量级和灵活的,但高度结构化,使其优于其他框架。
使用 Docker 部署 Flask 应用程序将允许您以最少的重新配置跨不同服务器复制应用程序。
在本教程中,您将创建一个 Flask 应用程序并使用 Docker 部署它。本教程还将介绍如何在部署后更新应用程序。
先决条件
要遵循本教程,您将需要以下内容:
- 具有 sudo 权限的非 root 用户按照Ubuntu 18.04指南的初始服务器设置进行配置。
- 一台安装了 Docker 的 Ubuntu 18.04 服务器,按照本教程或使用 DigitalOcean一键式 Docker 镜像进行设置。
- Nginx的安装由下面的步骤一个如何在Ubuntu 18.04安装Nginx的教程。
第 1 步 – 设置 Flask 应用程序
首先,您将创建一个目录结构来保存您的 Flask 应用程序。本教程将创建一个名为TestApp
in的目录/var/www
,但您可以修改该命令以将其命名为您喜欢的任何名称。
- sudo mkdir /var/www/TestApp
移动到新创建的TestApp
目录:
- cd /var/www/TestApp
接下来,为 Flask 应用程序创建基本文件夹结构:
- sudo mkdir -p app/static app/templates
该-p
标志表示mkdir
将创建一个目录和所有不存在的父目录。在这种情况下,mkdir
将app
在制作static
和templates
目录的过程中创建父目录。
该app
目录将包含与 Flask 应用程序相关的所有文件,例如其视图和蓝图。视图是您为响应对应用程序的请求而编写的代码。蓝图创建应用程序组件并支持应用程序内或跨多个应用程序的通用模式。
该static
目录是图像、CSS 和 JavaScript 文件等资产所在的位置。该templates
目录是您将放置项目的 HTML 模板的位置。
现在基本文件夹结构已完成,创建运行 Flask 应用程序所需的文件。首先,__init__.py
在app
目录中创建一个文件。这个文件告诉 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
创建的文件,你可以创建views.py
在您的文件app
目录。此文件将包含您的大部分应用程序逻辑。
- 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()
函数。该函数hello world
返回的文本home
将在浏览器上显示给用户。
随着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
的地方,你几乎可以编写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 镜像构建一个镜像并从生成的 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
port的新容器56733
。最后,它将当前目录链接到/var/www
容器的目录。
您可以使用该-d
标志以守护程序模式或作为后台进程启动容器。您包括将-p
服务器上的端口绑定到 Docker 容器上的特定端口的标志。在这种情况下,您将端口绑定56733
到80
Docker 容器上的端口。该-v
标志指定要挂载在容器上的 Docker 卷,在这种情况下,您将整个项目目录挂载到/var/www
Docker 容器上的文件夹中。
执行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
您将看到类似于以下内容的页面:
在此步骤中,您已成功在 Docker 上部署 Flask 应用程序。接下来,您将使用模板向用户显示内容。
第 3 步 — 提供模板文件
模板是向访问您的应用程序的用户显示静态和动态内容的文件。在此步骤中,您将创建一个 HTML 模板来为应用程序创建主页。
首先home.html
在app/templates
目录中创建一个文件:
- 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
首先,在文件开头添加以下行以render_template
从 Flask导入方法。此方法解析 HTML 文件以向用户呈现网页。
from flask import render_template
...
在文件的末尾,您还将添加一个新路由来渲染模板文件。此代码指定用户home.html
在访问/template
您的应用程序上的路由时将获得文件的内容。
...
@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 的更多信息,请查看他们的官方文档。