Flask Mega-Tutorial V2.0 第18章:在Heroku上部署

伍光济
2023-12-01

最近在Flask Web Development作者博客看到第二版Flask Mega-Tutorial已在2017年底更新,现翻译给大家参考,希望帮助大家学习flask。

这是Flask Mega-Tutorial系列的第十八章,我将在其中部署Microblog到Heroku云平台。供您参考,以下是本系列文章的列表。

注意1:如果您正在寻找本教程的旧版本,请在此处

注意2:如果您想在此博客上支持我的工作,或者只是没有耐心等待每周的文章,我将提供完整的本教程版本,打包成电子书或视频集。欲了解更多信息,请访问courses.miguelgrinberg.com

在上一篇文章中,我向您展示了托管Python应用的“传统”方式,并且为您提供了两个实际的示例,以将其部署到基于Linux的服务器上。如果您不习惯于管理Linux系统,您可能会认为需要花很多精力在任务上,并且肯定有一种更简单的方法。

在本章中,我将向您展示一种完全不同的方法,在这种方法中,您依赖第三方托管提供商来执行大多数管理任务,从而使您腾出更多时间来处理应用程序。

许多云托管提供商提供了一个应用程序可以运行的托管平台。 你只需提供部署到这些平台上的实际应用程序,因为硬件,操作系统,脚本语言解释器,数据库等都由该服务管理。 这种服务称为平台即服务(PaaS)。

听起来好得令人难以置信,对吧?

我将研究将Microblog部署到HerokuHeroku是一种流行的云托管服务,对Python应用程序也非常友好。我之所以选择Heroku,不仅是因为它很受欢迎,还因为它具有免费的服务水平,使您可以跟随我并进行完整的部署而无需花任何钱。

本章的GitHub链接是:BrowseZipDiff


在Heroku上托管

Heroku是最早的服务提供商平台之一。它最初是作为基于Ruby的应用程序的托管选项,但后来发展为支持许多其他语言,例如Java,Node.js,当然还有Python。

将Web应用部署到Heroku是通过git版本控制工具完成的,因此您必须将应用程序放置在git代码库中。Heroku在应用程序的根目录中查找一个名为Procfile的文件,以获取有关如何启动该应用的说明。对于Python项目,Heroku还希望有一个requirements.txt文件,其中列出了需要安装的所有模块依赖项。通过git将应用程序上传到Heroku的服务器后,您基本上已经完成,只需等待几秒钟,直到应用程序在线即可。真的就是这么简单。

Heroku提供的不同服务级别,允许您选择为应用程序获得多少计算能力和时间,因此随着用户群的增长,您将需要购买更多的计算单元,Heroku称之为“ dynos”。

准备尝试Heroku了吗?让我们开始吧!

创建Heroku帐户

您需要先拥有一个帐户,然后才能部署到Heroku。因此,请访问heroku.com并创建一个免费帐户。拥有帐户并登录到Heroku后,您将可以访问dashboard,其中列出了你的所有应用程序。

安装Heroku CLI

Heroku提供了一个命令行工具,用于与其名为Heroku CLI的服务进行交互,该工具可用于Windows,Mac OS X和Linux。 该文档包括了支持的所有平台的安装说明。 如果你计划部署应用程序以测试该服务,请将其安装在你的系统上。

一旦安装了CLI,您应该做的第一件事就是登录到您的Heroku帐户:

$ heroku login

Heroku CLI会要求您输入电子邮件地址和帐户密码。你的身份验证状态将在随后的命令中被记住。

设置Git

git工具是Heroku应用程序部署的核心,因此如果你还没有安装它的话,则必须将它安装到你的系统上。 如果你没有可用于你的操作系统的安装包,则可以访问git站点以下载安装程序。

使用git的原因很多并且都理由充分。 如果你打算部署应用到Heroku,那么这些原因就要又增加一个,因为要部署应用到Heroku,你的应用程序必须在git代码库中。 如果你要为Microblog执行测试部署,可以从GitHub克隆应用程序:

$ git clone https://github.com/miguelgrinberg/microblog
$ cd microblog
$ git checkout v0.18

git checkout命令将代码库切换到指定的历史提交点,也就是本章所处的位置。

如果您喜欢使用自己的代码而不是我的代码,你可以通过在顶层目录中运行git init .来将你自己的项目转换成git代码库(注意init后面的句号,它告诉git你想要在当前目录中初始化代码库)。

创建一个Heroku应用

要向Heroku注册新应用,请使用应用程序根目录中的命令apps:create,并将应用程序名称作为唯一参数传递:

$ heroku apps:create flask-microblog
Creating flask-microblog... done
http://flask-microblog.herokuapp.com/ | https://git.heroku.com/flask-microblog.git

Heroku要求应用程序具有唯一的名称。我上面使用的名称flask-microblog将无法使用,因为我正在使用它,因此您需要为部署选择其他不同的名称。

该命令的输出将包含Heroku分配给应用程序的URL以及git代码库。 你的本地git代码库将配置一个额外的remote,称为heroku。 你可以用git remote命令验证它是否存在:

$ git remote -v
heroku  https://git.heroku.com/flask-microblog.git (fetch)
heroku  https://git.heroku.com/flask-microblog.git (push)

根据您创建git代码库的方式,上述命令的输出还可能包含另一个名为origin的远程仓库地址。

临时文件系统

Heroku平台与其他部署平台的不同之处在于,它具有在虚拟化平台上运行的临时文件系统。那是什么意思?这意味着Heroku可以随时将服务器上运行的虚拟服务器重置为干净状态。您不能假设保存到文件系统的任何数据都会保留,实际上,Heroku经常回收服务器。

在这些条件下工作会给我的应用带来一些问题,因为它使用了如下的几个文件:

  • 默认的SQLite数据库引擎将数据写入磁盘文件中
  • 该应用程序的日志也被写入磁盘文件中
  • 编译后的语言翻译存储库也被写入本地文件

以下各节将介绍这三个领域。

使用Heroku Postgres数据库

为了解决第一个问题,我将切换到其他数据库引擎。在第17章中,看到我使用MySQL数据库为Ubuntu部署添加健壮性。 Heroku基于Postgres数据库提供了自己的数据库产品,因此我将转而使用它来避免使用基于文件的SQLite。

Heroku应用的数据库配备了相同的Heroku CLI。在本章中,我将创建一个免费级别的数据库:

$ heroku addons:add heroku-postgresql:hobby-dev
Creating heroku-postgresql:hobby-dev on flask-microblog... free
Database has been created and is available
 ! This database is empty. If upgrading, you can transfer
 ! data from another database with pg:copy
Created postgresql-parallel-56076 as DATABASE_URL
Use heroku addons:docs heroku-postgresql to view documentation

新创建的数据库的URL存储在 DATABASE_URL 环境变量中,该环境变量在应用程序运行时将可用。这非常方便,因为应用程序已经设定为在该变量中查找数据库URL。

输出日志到标准输出

Heroku希望应用程序直接输出日志到stdout。 当你使用heroku logs命令时,应用程序打印到标准输出的任何内容都将被保存并返回。 所以我要添加一个配置变量,指示我是要输出日志到stdout,还是像我之前那样输出到文件。 这是配置的变化:

config.py日志到标准输出的选项。

class Config(object):
    # ...
    LOG_TO_STDOUT = os.environ.get('LOG_TO_STDOUT')

然后在应用程序工厂函数中,我可以检查此配置,以了解如何配置应用程序的日志记录器:

app/__ init__.py:日志到标准输出或文件。

def create_app(config_class=Config):
    # ...
    if not app.debug and not app.testing:
        # ...

        if app.config['LOG_TO_STDOUT']:
            stream_handler = logging.StreamHandler()
            stream_handler.setLevel(logging.INFO)
            app.logger.addHandler(stream_handler)
        else:
            if not os.path.exists('logs'):
                os.mkdir('logs')
            file_handler = RotatingFileHandler('logs/microblog.log',
                                               maxBytes=10240, backupCount=10)
            file_handler.setFormatter(logging.Formatter(
                '%(asctime)s %(levelname)s: %(message)s '
                '[in %(pathname)s:%(lineno)d]'))
            file_handler.setLevel(logging.INFO)
            app.logger.addHandler(file_handler)

        app.logger.setLevel(logging.INFO)
        app.logger.info('Microblog startup')

    return app

一因此现在我需要在Heroku中运行应用程序时,设置环境变量LOG_TO_STDOUT,但在其他配置中则不需要。 Heroku CLI使得做到这一点变得简单,因为它提供了一个选项来设置运行时使用的环境变量:

$ heroku config:set LOG_TO_STDOUT=1
Setting LOG_TO_STDOUT and restarting flask-microblog... done, v4
LOG_TO_STDOUT: 1

编译翻译

Microblog依赖本地文件的第三个方面是编译后的语言翻译文件。要确保这些文件永远不会从临时文件系统中消失,更直接的选择是将已编译的语言文件添加到git存储库中,以便一旦将其部署到Heroku中,它们便成为应用程序初始状态的一部分。

在我看来,更优雅的选择是在Heroku的启动命令中包含flask translate compile命令,以便在服务器重新启动时再次编译这些文件。 我打算选择这个方案,因为我知道启动过程需要多个命令,至少我还需要运行数据库迁移。所以现在,我将这个问题搁置一旁,稍后在写Procfile时将再次进行讨论。

Elasticsearch托管

Elasticsearch是可以添加到Heroku项目中的众多服务之一,但是与Postgres不同的是,它不是Heroku提供的服务,而是与Heroku合作提供附加组件的第三方提供的服务。在撰写本文时,集成Elasticsearch服务的三个不同提供程序。

在配置Elasticsearch之前,请注意,Heroku要求您的帐户在安装任何第三方附加组件之前都必须具有信用卡信息,即使您处于其免费套餐中。如果您不想将信用卡提供给Heroku,请跳过此部分。您仍然可以部署该应用程序,但是搜索功能将无法使用。

在可作为附加组件提供的Elasticsearch选项中,我决定尝试SearchBox,它附带一个免费的初试计划。 要将SearchBox添加到你的帐户,你必须在登录到Heroku后运行以下命令:

$ heroku addons:create searchbox:starter

此命令将部署Elasticsearch服务,并将该服务的连接URL保存在与你的应用程序关联的SEARCHBOX_URL环境变量中。 请记住,除非您将信用卡添加到Heroku帐户,否则此命令将失败。

如果您从第16章回顾过,我的应用会在Elasticsearch连接URL中查找的是ELASTICSEARCH_URL变量,因此我需要添加这个变量并将其设置为SearchBox分配的连接URL:

$ heroku config:get SEARCHBOX_URL
<your-elasticsearch-url>
$ heroku config:set ELASTICSEARCH_URL=<your-elasticsearch-url>

在这里,我首先要求Heroku打印SEARCHBOX_URL的值,然后将其添加到一个名为ELASTICSEARCH_URL的新环境变量中。

更新依赖

Heroku希望这些依赖项将在requirements.txt文件中,就像我在第15章中定义的那样。但是要使该应用程在Heroku上运行,我需要向该文件添加两个新的依赖项。

Heroku不提供自己的Web服务器。相反,它希望应用程序在环境变量$PORT中给定的端口号上启动自己的Web服务器。由于Flask开发Web服务器不够强大,无法用于生产,因此我将再次使用gunicorn,这是Heroku推荐用于Python应用程序的服务器。

该应用程序还将连接到Postgres数据库,为此SQLAlchemy需要psycopg2安装该软件包。

gunicorn 和psycopg2 都需要添加到requirements.txt文件中。

Procfile

Heroku需要知道如何执行应用程序,为此,它在应用程序的根目录中使用了一个名为Procfile的文件。该文件的格式很简单,每一行都包含一个进程名称,一个冒号,然后是启动该进程的命令。在Heroku上运行的最常见的应用程序类型是Web应用程序,对于这种类型的应用程序,进程名称应为web。在下面,您可以看到Microblog的Procfile

Procfile:Heroku Procfile。

web: flask db upgrade; flask translate compile; gunicorn microblog:app

在这里,我定义的启动命令中将按顺序执行三个命令作以启动Web应用程序。首先,我运行数据库迁移升级,然后编译语言翻译,最后启动服务器。

因为前两个子命令基于flask命令,所以我需要添加FLASK_APP环境变量:

$ heroku config:set FLASK_APP=microblog.py
Setting FLASK_APP and restarting flask-microblog... done, v4
FLASK_APP: microblog.py

该应用程序还依赖于其他环境变量,例如那些配置电子邮件服务器或实时翻译令牌的变量。那些需要与附加命令heroku config:set一起添加。

gunicorn命令比我用于Ubuntu部署的命令更简单,因为这个服务与Heroku环境具有很好的集成。例如,$PORT环境变量默认会被设置,取代使用-w选项来设置worker的数量,heroku推荐添加一个名为WEB_CONCURRENCY的环境变量,在-w参数没有提供的时候,就会使用这个环境变量,因此你可以灵活地控制worker的数量而无需修改Procfile。

部署应用

所有准备步骤均已完成,因此现在该执行部署了。要将应用程序上传到Heroku的服务器以进行部署,请使用git push命令。 这与你将本地git代码库中的更改推送到GitHub或其他远程git服务器的方式类似。

现在我到达了最有趣的部分,将应用程序推送到我们的Heroku托管帐户。这实际上非常简单,我只需要使用git将应用程序推送到Heroku git代码库的master分支即可。根据您创建git代码库的方式,如何执行此操作有多种变体。如果使用的是我的v0.18代码,则需要基于此标记创建一个分支,并将其作为远程主分支推送,如下所示:

$ git checkout -b deploy
$ git push heroku deploy:master

相反,如果您正在使用自己的代码库,则您的代码已经在一个master分支中,因此您首先需要确保所做的更改已提交:

$ git commit -a -m "heroku deployment changes"

然后,您可以运行以下命令启动部署:

$ git push heroku master

无论如何推动分支,都应该从Heroku中看到以下输出:

$ git push heroku deploy:master
Counting objects: 247, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (238/238), done.
Writing objects: 100% (247/247), 53.26 KiB | 3.80 MiB/s, done.
Total 247 (delta 136), reused 3 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Python app detected
remote: -----> Installing python-3.6.2
remote: -----> Installing pip
remote: -----> Installing requirements with pip
...
remote:
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote:
remote: -----> Compressing...
remote:        Done: 57M
remote: -----> Launching...
remote:        Released v5
remote:        https://flask-microblog.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/flask-microblog.git
 * [new branch]      deploy -> master

我们在git push命令中使用的heroku标签是创建应用程序时由Heroku CLI自动添加的远程服务器。deploy:master参数,意味着我正在将代码从本地存储库的deploy分支推送到Heroku代码库上的master分支。当您处理自己的项目时,你可能会用git push heroku master命令推动你的本地master分支。由于该项目的代码库分支结构,我要推送一个非master的分支,但Heroku侧要求的目标分支是'master',因为这是Heroku唯一接受部署的分支。

就这样,应用程序现在应该已经部署在创建应用程序的命令的输出中给出的URL上了。 在我的案例中,URL是 https://flask-microblog.herokuapp.com ,所以这就是我需要键入和访问该应用程序的URL。

如果您想查看正在运行的应用程序的日志,请使用heroku logs命令。 如果由于任何原因导致应用程序无法启动,该命令可能很有用。 如果有任何错误,将在日志中显示。

部署应用程序更新

要部署新版本的应用程序,您只需git push使用新代码运行新命令。这将重复部署过程,关停旧部署,然后用新代码替换它。Procfile中的命令将作为新部署的一部分再次运行,因此任何新的数据库迁移或翻译都将在此过程中进行更新。


原文链接:https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xviii-deployment-on-heroku

 类似资料: