如何在Ubuntu 18.04上使用Docker构建和部署Flask应用程序

Docker是一个开源应用程序,允许管理员使用容器创建,管理,部署和复制应用程序。 Flask是一个基于Python构建的Web微框架。在本教程中,您将创建一个Flask应用程序并使用Docker进行部署。

作者选择技术教育基金作为Write for DOnations计划的一部分接受捐赠。

介绍

Docker是一个开源应用程序,允许管理员使用容器创建,管理,部署和复制应用程序。 可以将容器视为包含应用程序在操作系统级别运行所需的依赖项的程序包。 这意味着使用Docker部署的每个应用程序都位于自己的环境中,其需求将单独处理。

Flask是一个基于Python构建的Web微框架。 它被称为微框架,因为它不需要特定的工具或插件来运行。 Flask框架轻巧灵活,结构严谨,比其他框架更受欢迎。

使用Docker部署Flask应用程序将允许您以最少的重新配置在不同的服务器上复制应用程序。

在本教程中,您将创建一个Flask应用程序并使用Docker进行部署。 本教程还将介绍如何在部署后更新应用程序。

先决条件

要学习本教程,您需要具备以下条件:

第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将在创建statictemplates目录的过程中创建app父目录。

app目录将包含与Flask应用程序相关的所有文件,例如其视图蓝图 视图是您为响应对应用程序的请求而编写的代码。 蓝图创建应用程序组件并支持应用程序内或多个应用程序中的常见模式。

static目录是图像,CSS和JavaScript文件等资源的存在。 您可以在templates目录中放置项目的HTML模板。

现在基础文件夹结构已完成,请创建运行Flask应用程序所需的文件。 首先,在app目录中创建一个__init__.py文件。 该文件告诉Python解释器app目录是一个包,应该这样对待。

运行以下命令以创建文件:

sudo nano app/__init__.py

Python中的包允许您将模块分组为逻辑命名空间或层次结构。 这种方法使代码可以分解为执行特定功能的单个和可管理的块。

接下来,您将向__init__.py添加代码,该代码将创建Flask实例并从views.py文件中导入逻辑,您将在保存此文件后创建该文件。 将以下代码添加到新文件中:

/var/www/TestApp/__init__.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! 访问您网页的用户的字符串:

/var/www/TestApp/app/views.py
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服务器:

/var/www/TestApp/uwsgi.ini
[uwsgi]
module = main
callable = app
master = true

此代码定义将从中提供Flask应用程序的模块。 在这种情况下,这是main.py文件,在此引用为main callable选项指示uWSGI使用主应用程序导出的app实例。 master选项允许您的应用程序继续运行,因此即使重新加载整个应用程序也几乎没有停机时间。

接下来,创建main.py文件,该文件是应用程序的入口点。 入口点指示uWSGI如何与应用程序交互。

sudo nano main.py

接下来,将以下内容复制并粘贴到文件中。 这将从先前创建的应用程序包中导入名为app的Flask实例。

/var/www/TestApp/main.py
from app import app

最后,创建一个requirements.txt文件以指定pip包管理器将为Docker部署安装的依赖项:

sudo nano requirements.txt

添加以下行以将Flask添加为依赖项:

/var/www/TestApp/app/requirements.txt
Flask==1.0.2

这指定了要安装的Flask的版本。 在编写本教程时, 1.0.2是最新的Flask版本。 您可以在Flask的官方网站上查看更新。

保存并关闭文件。 您已成功设置Flask应用程序并准备好设置Docker。

第2步 - 设置Docker

在此步骤中,您将创建两个文件Dockerfilestart.sh ,以创建Docker部署。 Dockerfile是一个文本文档,其中包含用于组合图像的命令。 start.sh文件是一个shell脚本,它将构建一个映像并从Dockerfile创建一个容器。

首先,创建Dockerfile

sudo nano Dockerfile

接下来,将所需的配置添加到Dockerfile 这些命令指定如何构建映像,以及将包括哪些额外要求。

在/ var / WWW / TestApp / 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映像创建一个容器。 将配置添加到新文件:

/var/www/TestApp/start.sh
#!/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

您将收到显示容器的输出:

CONTAINER 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模板来为应用程序创建主页。

首先在app/templates目录中创建一个home.html文件:

sudo nano app/templates/home.html

添加模板的代码。 此代码将创建一个包含标题和一些文本的HTML5页面。

/var/www/TestApp/app/templates/home.html

<!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文件以向用户呈现网页。

/var/www/TestApp/app/views.py
from flask import render_template
...

在文件末尾,您还将添加一个新路由以呈现模板文件。 此代码指定只要用户访问应用程序上的/template路由,就会向用户提供home.html文件的内容。

/var/www/TestApp/app/views.py
...

@app.route('/template')
def template():
    return render_template('home.html')

更新后的app/views.py文件如下所示:

/var/www/TestApp/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

接下来,将突出显示的行添加到文件的末尾:

/var/www/TestApp/uwsgi.ini
module = main
callable = app
master = true
touch-reload = /app/uwsgi.ini

这指定了一个文件,该文件将被修改以触发整个应用程序重新加载。 完成更改后,保存并关闭文件。

为了证明这一点,请对您的应用程序进行一些小改动。 首先打开你的app/views.py文件:

sudo nano app/views.py

替换home函数返回的字符串:

/var/www/TestApp/app/views.py
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的更多信息,请查看其官方文档