Heroku 使用教程

作者: 超net | 来源:发表于2016-02-17 15:53 被阅读20166次

    Heroku平台


    Heroku平台的灵活性极高且支持多种编程语言。若想把程序部署到Heroku上,开发者要使用Git把程序推送到HerokuGit服务器上。在服务器上,git push命令会自动触发安装、配置和部署程序。

    Heroku使用名为Dyno的计算单元衡量用量,并以此为依据收取服务费用。最常用的Dyno类型是Web Dyno,表示一个Web服务器实例。程序可以通过使用更多的Web Dyno以增强其请求处理能力。另一种Dyno类型是Worker Dyno,用来执行后台作业或其他辅助任务。

    Heroku提供了大量的插件和扩展,可用于数据库、电子邮件支持和其他很多服务。

    准备程序


    若想使用 Heroku,程序必须托管在 Git 仓库中。如果你的程序托管在像 GitHub 或 BitBucket 这样的远程 Git 服务器上,那么在本地 clone 程序后会创建一个本地 Git 仓库,可无缝用于 Heroku。如果你的程序没有托管在 Git 仓库中,那么必须在开发电脑上创建一个仓库。

    注册Heroku账户


    heroku 官网

    安装Heroku Toolbelt


    Heroku Toolbelt

    Heroku Toolbelt是用于创建、管理Herokuapps的命令行工具

    heroku 的命令行客户端将被安装到/usr/local/heroku,同时,/usr/local/heroku/bin将被添加到你的PATH环境变量

    下载并安装完成后,在 shell 中输入heroku login,用创建heroku账号的email密码登陆

    $ heroku login
    Enter your Heroku credentials.
    Email: adam@example.com
    Password (typing will be hidden):
    Authentication successful.
    

    把你的 SSH 公钥上传到 Heroku,这一点很重要,上传后才能使用 git push 命令。正常情况下,login 命令会自动创建并上传 SSH 公钥。

    创建程序


    首先要确保程序在 Git 源码控制系统中,然后在程序的顶级目录下运行创建命令

    在 Heroku 创建一个 app, 以便 Heroku 准备好接收你的代码

    当你创建一个 app, 将创建并关联一个名为heroku的远端到你的本地仓库

    apps:create [NAME] # create a new app 名称必须以字母开始,只能包含小写字母,数字和连字符, 而且名称在 heroku 的所有程序中必须是唯一的

    ➜  flask_blog git:(rest) ✗ heroku apps:create flask-blog-chaonet
    Creating flask-blog-chaonet... done, stack is cedar-14
    https://flask-blog-chaonet.herokuapp.com/ | https://git.heroku.com/flask-blog-chaonet.git
    Git remote heroku added
    

    查看已创建的 app

    ➜  flask_blog git:(rest) ✗ heroku apps
    === My Apps
    flask-blog-chaonet
    
    

    默认 Heroku 会为你的 app 生成一个随机的名字, 或者 你可以通过可选参数指定你的 app名。

    现在,你可以向 Heroku 部署你的代码了

    $ git push heroku master # 必须将 本地 的 master push 到 heroku 的 master

    应用现在已经部署了,确保至少一个 app 的实例正在运行:

    $ heroku ps:scale web=1

    现在,可以用创建的包含 app 名称的 URL 访问 app. 有一个便捷的方法, 你可以像这样打开web站点:

    $ heroku open

    配置数据库


    Heroku 以扩展形式支持 Postgres 数据库。少于 1 万条记录、同时连接数 20 、没有缓存 、不允许fork/follow、没有 Postgres 日志 的小型数据库无需付费即可添加 到程序中。

    官网教程: heroku-postgresql

    添加 Postgres 到 Heroku 应用

    通过命令行,将 Heroku Postgres 添加到一个 Heroku 应用:

    ➜  flask_blog git:(rest) ✗ heroku addons:create heroku-postgresql:hobby-dev
    Creating postgresql-sinuous-8326... done, (free)
    Adding postgresql-sinuous-8326 to flask-blog-chaonet... done
    Setting DATABASE_URL and restarting flask-blog-chaonet... done, v3
    Database has been created and is available
     ! This database is empty. If upgrading, you can transfer
     ! data from another database with pg:copy
    Use `heroku addons:docs heroku-postgresql` to view documentation.
    

    选择正确的 Heroku Postgres 方案

    heroku-postgresql 插件

    最低等级的业余版本有两种方案 hobby-dev 和 hobby-basic

    一旦 Heroku Postgres 被添加,一个 DATABASE_URL 设置将在 app 配置中生效,并包含用于访问新提供的 Heroku Postgres 服务的 URL 。

    这可以使用 heroku config 命令确认:

    ➜  flask_blog git:(rest) ✗ heroku config -s | grep DATABASE_URL
    DATABASE_URL=postgres://bjtrukgnhvnban:T0_N_OWYVz6NnasUwOf0FxVscO@ec2-54-83-52-71.compute-1.amazonaws.com:5432/d44ph8k76dl0h0
    

    amazonaws ?

    • 建立主数据库

    Heroku 中的每个程序都支持多个数据库。Heroku 建议使用 DATABASE_URL 变量保存主用数据库信息。在单个数据库的情况下,新的数据库已经被指定到 DATABASE_URL 。

    对于多个数据库的情况,可以设置主用数据库:

    $ heroku pg:promote HEROKU_POSTGRESQL_RED
    Promoting HEROKU_POSTGRESQL_RED_URL to DATABASE_URL... done
    

    DATABASE_URL 环境变量的格式正是 SQLAlchemy 所需的。回想一下 config.py 脚本的内容,如果 设定了 DATABASE_URL,就使用其中保存的值,所以现在程序可以自动连接到 Postgres 数据库。

    • 查看数据库使用信息
    ➜  flask_blog git:(rest) ✗ heroku pg:info
    === DATABASE_URL
    Plan:        Hobby-dev
    Status:      Available
    Connections: 0/20
    PG Version:  9.4.5
    Created:     2016-01-09 02:57 UTC
    Data Size:   6.7 MB
    Tables:      0
    Rows:        0/10000 (In compliance)
    Fork/Follow: Unsupported
    Rollback:    Unsupported
    Add-on:      postgresql-sinuous-8326
    

    heroku 的命令行命令

    在 MAC 中安装 Postgres

    推荐在本地开发环境与生产环境运行相同的数据库

    使用Postgres.app,是在 Mac 下使用PostgreSQL的最简单的方法

    postgresapp下载Postgres.app
    解压后将Postgres移到应用程序文件夹
    双击,然后你的 MAC 中就有一个PostgreSQL服务器在运行了

    • 使用 Postgres.app 的命令行工具

    配置$PATH变量

    ➜  psycopg2-2.6.1  which psql
    psql not found
    ➜  psycopg2-2.6.1  export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/latest/bin
    ➜  psycopg2-2.6.1  which psql
    /Applications/Postgres.app/Contents/Versions/latest/bin/psql
    

    通过命令psql连接你的数据库

    ➜  psycopg2-2.6.1  psql -h localhost
    psql (9.5.0)
    Type "help" for help.
    
    chao-# \q
    ➜  psycopg2-2.6.1
    

    Using Command Line Tools with Postgres.app

    在本地安装 Heroku Postgres

    与 Python 对接

    官网教程

    ➜  psycopg2-2.6.1  pip install psycopg2
    Collecting psycopg2
      Using cached psycopg2-2.6.1.tar.gz
    Building wheels for collected packages: psycopg2
      Running setup.py bdist_wheel for psycopg2
      Stored in directory: /Users/chao/Library/Caches/pip/wheels/e2/9a/5e/7b620848bbc7cfb9084aafea077be11618c2b5067bd532f329
    Successfully built psycopg2
    Installing collected packages: psycopg2
    Successfully installed psycopg2-2.6.1
    

    遇到的问题:

    没有通过 postgres.app 安装 Postgres,就安装 psycopg2 ,结果报错

    • pip 安装
    ➜  flask_blog git:(rest) ✗ pip install psycopg2
    Collecting psycopg2
      Using cached psycopg2-2.6.1.tar.gz
        Complete output from command python setup.py egg_info:
        running egg_info
        creating pip-egg-info/psycopg2.egg-info
        writing pip-egg-info/psycopg2.egg-info/PKG-INFO
        writing top-level names to pip-egg-info/psycopg2.egg-info/top_level.txt
        writing dependency_links to pip-egg-info/psycopg2.egg-info/dependency_links.txt
        writing manifest file 'pip-egg-info/psycopg2.egg-info/SOURCES.txt'
        warning: manifest_maker: standard file '-c' not found
    
        Error: pg_config executable not found.
    
        Please add the directory containing pg_config to the PATH
        or specify the full executable path with the option:
    
            python setup.py build_ext --pg-config /path/to/pg_config build ...
    
        or with the pg_config option in 'setup.cfg'.
    
        ----------------------------------------
    Command "python setup.py egg_info" failed with error code 1 in /private/var/folders/36/tdbs35wx1sx4d6nm4hrmwy0h0000gn/T/pip-build-XR5kDF/psycopg2
    
    
    • 下载安装包安装
    ➜  psycopg2-2.6.1  ls
    AUTHORS     LICENSE     MANIFEST.in NEWS        README.rst  examples    psycopg     setup.cfg   tests
    INSTALL     MANIFEST    Makefile    PKG-INFO    doc         lib         scripts     setup.py
    
    ➜  psycopg2-2.6.1  python setup.py build
    running build
    running build_py
    creating build
    creating build/lib.macosx-10.6-intel-2.7
    creating build/lib.macosx-10.6-intel-2.7/psycopg2
    copying lib/__init__.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
    copying lib/_json.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
    copying lib/_range.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
    copying lib/errorcodes.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
    copying lib/extensions.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
    copying lib/extras.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
    copying lib/pool.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
    copying lib/psycopg1.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
    copying lib/tz.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
    creating build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/__init__.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/dbapi20.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/dbapi20_tpc.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_async.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_bug_gc.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_bugX000.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_cancel.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_connection.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_copy.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_cursor.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_dates.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_extras_dictcursor.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_green.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_lobject.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_module.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_notify.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_psycopg2_dbapi20.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_quote.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_transaction.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_types_basic.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_types_extras.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/test_with.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/testconfig.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    copying tests/testutils.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
    running build_ext
    Error: pg_config executable not found.
    
    Please add the directory containing pg_config to the PATH
    or specify the full executable path with the option:
    
        python setup.py build_ext --pg-config /path/to/pg_config build ...
    
    or with the pg_config option in 'setup.cfg'.
    ➜  psycopg2-2.6.1
    

    配置 Python 用于 Postgres.app

    在 Flask 中使用 Flask-SQLAlchemy 扩展时,可以直接在配置中定义,并由 app 读取。

    Postgres.app 的配置文档

    配置日志


    任何写到 标准输出(stdout) 或标准错误(stderr) 的信息才会被 Heroku 抓取到日志,并在 Heroku 客户端通过heroku logs命令查看。

    config.py

            # 输出到 stderr,以便被 Heroku 抓取到 logs
            import logging
            from logging import StreamHandler
            file_handler = StreamHandler()
            file_handler.setLevel(logging.WARNING)
            app.logger.addHandler(file_handler)
    

    定义配置变量


    Heroku 可以让你在程序外部配置变量 —— 存储类似加密密钥外部资源地址的数据。

    在运行时, 配置的变量被当做环境变量暴露给应用。

    变量可以用Heroku的命令行工具配置,也可以在应用的Dashboard页面的settings页签下配置。

    官网资料

    配置电子邮件


    Heroku 没有提供 SMTP 服务器,所以我们要配置一个外部服务器。很多第三方扩展能把 适用于生产环境的邮件发送服务集成到 Heroku 中,但对于测试和评估而言,使用继承自 Config 基类的 mail 配置已经足够了。

    由于直接把安全密令写入脚本存在安全隐患,所以我们把访问 mail SMTP服务器的用户 名和密码保存在环境变量中。

    运行生产 Web 服务器


    Heroku 没有为托管程序提供 Web 服务器,相反,它希望程序启动自己的服务器并监听环 境变量 PORT 中设定的端口。

    Flask 自带的开发 Web 服务器表现很差,因为它不是为生产环境设计的服务器。有两个 可以在生产环境中使用、性能良好且支持 Flask 程序的服务器,分别是GunicornuWSGI

    若想在本地测试 Heroku 配置,我们最好在虚拟环境中安装 Web 服务器。例如,可通过如下命令安装 Gunicorn:

    (venv) $ pip install gunicorn

    若要使用 Gunicorn 运行程序,可执行下面的命令:

         (venv) $ gunicorn manage:app
         2013-12-03 09:52:10 [14363] [INFO] Starting gunicorn 18.0
         2013-12-03 09:52:10 [14363] [INFO] Listening at: http://127.0.0.1:8000 (14363)
         2013-12-03 09:52:10 [14363] [INFO] Using worker: sync
         2013-12-03 09:52:10 [14368] [INFO] Booting worker with pid: 14368
    

    manage:app 参数冒号左边的部分表示定义程序的包或者模块,冒号右边的部分表示包中程序实例的名字注意,Gunicor 默认使用端口 8000,而 Flask 默认使用 5000

    添加依赖需求文件


    Heroku 从程序顶级文件夹下的 requirements.txt 文件中加载包依赖。这个文件中的所有依赖都会在部署过程中导入 Heroku 创建的虚拟环境。

    Heroku 的需求文件必须包含程序在生产环境中使用的所有通用依赖,以及支持 Postgres 数据库的 psycopg2 包和 Gunicorn Web 服务器。

    可以在需求文件中导入需求文件。

    requirements.txt

         -r requirements/prod.txt
         gunicorn==18.0
         psycopg2==2.5.1
    

    添加Procfile文件


    Heroku 需要知道使用哪个命令启动程序。命令在一个名为Procfile(没有后缀)的特殊文件中指定。这个文件必须放在程序的顶级文件夹中。

    web: gunicorn manage:app

    Procfile文件内容的格式很简单:在每一行中指定一个任务名,后跟一个冒号,然后是执行这个任务的命令。名为web的任务比较特殊任务,Heroku 使用这个任务启动 Web 服务器。

    Heroku 会为这个任务提供一个PORT环境变量,用于设定程序监听请求的端口。如果设定了PORT变量, Gunicorn默认就会使用其中保存的值,因此无需将其包含在启动命令中。

    部署程序后,Heroku 会运行 Procfile 中列出的所有任务。

    任务格式模板

    程序可在 Procfile 中使用 web 之外的名字声明其他任务,例如程序所需的其他服务。

    声明任务类型的方式

    使用 Heroku Local 进行本地测试


    官方教程

    Heroku Local作为Heroku Toolbelt的一部分, 自动被安装。

    • 在本地启动所有在你的Profile中定义的任务

    $ heroku local

    heroku localheroku local:start的简写,作用相同

    ➜  flask_blog git:(rest) ✗ heroku local
    Downloading forego-0.16.1 to /Users/chao/.heroku... done
    forego | starting web.1 on port 5000
    web.1  | [2016-01-10 00:11:00 +0800] [17093] [INFO] Starting gunicorn 19.4.5
    web.1  | [2016-01-10 00:11:00 +0800] [17093] [INFO] Listening at: http://0.0.0.0:5000 (17093)
    web.1  | [2016-01-10 00:11:00 +0800] [17093] [INFO] Using worker: sync
    web.1  | [2016-01-10 00:11:00 +0800] [17096] [INFO] Booting worker with pid: 17096
    

    指定运行的端口

    ➜  flask_blog git:(rest) ✗ heroku local -p 8000
    forego | starting web.1 on port 8000
    web.1  | [2016-01-10 00:20:22 +0800] [17237] [INFO] Starting gunicorn 19.4.5
    web.1  | [2016-01-10 00:20:22 +0800] [17237] [INFO] Listening at: http://0.0.0.0:8000 (17237)
    web.1  | [2016-01-10 00:20:22 +0800] [17237] [INFO] Using worker: sync
    web.1  | [2016-01-10 00:20:22 +0800] [17240] [INFO] Booting worker with pid: 17240
    web.1  | [2016-01-10 00:21:11 +0800] [17237] [CRITICAL] WORKER TIMEOUT (pid:17240)
    web.1  | [2016-01-10 00:21:11 +0800] [17240] [INFO] Worker exiting (pid: 17240)
    web.1  | [2016-01-10 00:21:11 +0800] [17244] [INFO] Booting worker with pid: 17244
    

    可以在本地指定运行一个特定的进程类型,例如webworker

    $ heroku local web

    然后,你就可以在本地测试 app。使用Ctrl+C停止

    • 设置本地环境变量

    在本地运行 APP,同样需要输入一系列 配置变量 作为 app 的配置。.env文件让你可以收集 app 在本地运行所需要的配置变量。当使用heroku local命令运行 APP,将会读取.env文件,并且,每一个 名称/值 对会被插入环境中,模仿实际的配置变量。

    增加一个配置变量到你的.env文件:编辑.env文件,并在新的一行增加一个新name=value对。

    由于.env文件中包含密码和其他敏感的账户信息, 所以决不能将其添加到 Git 仓库中,这个文件应该只在存在于本地配置中。使用:echo .env >> .gitignore, 将.env文件列入 git 的忽略文件列表。

    需要注意,你部署的生产 app 可能使用到与本地开发 app 不同的服务。例如,部署的生产 app 可能有一个引用Heroku Postgres数据库的DATABASE_URL配置变量,但你的本地 app可能在.env文件中有一个引用本地安装的PostgresDATABASE_URL变量。

    有时你可能想要在本地使用和 Heroku 环境相同的配置变量。对于每一个你想要添加到.env文件的配置变量,使用如下命令:

    $ heroku config:get CONFIG-VAR-NAME -s >> .env

    • 查看环境变量

    使用heroku config查看 app 的所有配置变量。使用cat .env查看.env文件的内容

    • 另一个本地测试工具 Foreman

    除了heroku local,原本的foreman也可以使用,但不再提供官方的支持,需要另外安装。

    Heroku Local has replaced Foreman in the Heroku Toolbelt

    执行 git push 命令部署


    部署过程的最后一步是把程序上传到 Heroku 服务器。在此之前,你要确保所有改动都已经提交到本地Git仓库,然后执行git push heroku master把程序上传到远程仓库heroku

    上传代码,中间遇到一个坑,一开始从本地的rest分支向herokumaster推送,报错

    ➜  flask_blog git:(rest) git push heroku master
    Counting objects: 315, done.
    Delta compression using up to 4 threads.
    Compressing objects: 100% (309/309), done.
    Writing objects: 100% (315/315), 82.51 KiB | 0 bytes/s, done.
    Total 315 (delta 190), reused 3 (delta 0)
    remote: Compressing source files... done.
    remote: Building source:
    remote:
    remote:
    remote:  !     Push rejected, no Cedar-supported app detected
    remote: HINT: This occurs when Heroku cannot detect the buildpack
    remote:       to use for this application automatically.
    remote: See https://devcenter.heroku.com/articles/buildpacks
    remote:
    remote: Verifying deploy....
    remote:
    remote: !   Push rejected to flask-blog-chaonet.
    remote:
    To https://git.heroku.com/flask-blog-chaonet.git
     ! [remote rejected] master -> master (pre-receive hook declined)
    error: failed to push some refs to 'https://git.heroku.com/flask-blog-chaonet.git'
    
    ➜  flask_blog git:(rest) heroku buildpacks:set heroku/python
    Buildpack set. Next release on flask-blog-chaonet will use heroku/python.
    Run git push heroku master to create a new release using this buildpack.
    
    ➜  flask_blog git:(rest) git push heroku master
    Counting objects: 315, done.
    Delta compression using up to 4 threads.
    Compressing objects: 100% (309/309), done.
    Writing objects: 100% (315/315), 82.56 KiB | 0 bytes/s, done.
    Total 315 (delta 190), reused 3 (delta 0)
    remote: Compressing source files... done.
    remote: Building source:
    remote:
    remote: -----> Using set buildpack heroku/python
    remote:
    remote:  !     Push rejected, failed to detect set buildpack heroku/python
    remote: More info: https://devcenter.heroku.com/articles/buildpacks#detection-failure
    remote:
    remote: Verifying deploy....
    remote:
    remote: !   Push rejected to flask-blog-chaonet.
    remote:
    To https://git.heroku.com/flask-blog-chaonet.git
     ! [remote rejected] master -> master (pre-receive hook declined)
    error: failed to push some refs to 'https://git.heroku.com/flask-blog-chaonet.git'
    

    感觉可能是 分支名称的问题,尝试切换到 master,合并分支后再试

    ➜  flask_blog git:(rest) git checkout master
    Switched to branch 'master'
    Your branch is up-to-date with 'origin/master'.
    
    ➜  flask_blog git:(master) ✗ git merge rest
    Updating 40d4e6e..90872cd
    Fast-forward
     .gitignore                                      |   2 +
     Procfile                                        |   1 +
     app.db                                          | Bin 76800 -> 83968 bytes
     app/__init__.py                                 |  67 +++++----
     app/api_1_0/__init__.py                         |   5 +
     app/api_1_0/authentication.py                   |  59 ++++++++
     app/api_1_0/comments.py                         |  79 +++++++++++
     app/api_1_0/decorators.py                       |  21 +++
     app/api_1_0/errors.py                           |  21 +++
     app/api_1_0/posts.py                            |  74 ++++++++++
     app/api_1_0/users.py                            |  75 ++++++++++
     app/auth/__init__.py                            |   5 +
     app/auth/forms.py                               |  65 +++++++++
     app/auth/views.py                               | 196 ++++++++++++++++++++++++++
     app/email.py                                    |  11 ++
     app/exceptions.py                               |   4 +
     app/main/__init__.py                            |  13 ++
     app/main/error.py                               |  12 ++
     app/main/forms.py                               |  69 ++++++++++
     app/main/views.py                               | 401 +++++++++++++++++++++++++++++++++++++++++++++++++++++
     app/models.py                                   |  71 +++++++++-
     app/templates/_comments.html                    |  10 +-
     app/templates/_posts.html                       |  12 +-
     app/templates/{ => auth/email}/confirm.html     |   2 +-
     app/templates/auth/email/confirm.txt            |   6 +
     app/templates/{ => auth/email}/confirmmail.html |   2 +-
     app/templates/{ => auth/email}/confirmmail.txt  |   2 +-
     app/templates/{ => auth}/login.html             |   4 +-
     app/templates/{ => auth}/register.html          |   0
     app/templates/{ => auth}/renew.html             |   0
     app/templates/{ => auth}/unconfirmed.html       |   2 +-
     app/templates/base.html                         |  14 +-
     app/templates/changepassword.html               |   2 +-
     app/templates/changepassword.txt                |   2 +-
     app/templates/confirm.txt                       |   6 -
     app/templates/followers.html                    |   2 +-
     app/templates/{ => main}/index.html             |   6 +-
     app/templates/main/moderate.html                |  16 +++
     app/templates/user.html                         |  14 +-
     app/views.py                                    |   1 -
     app_pro.db                                      |   0
     app_test.db                                     | Bin 0 -> 24576 bytes
     config.py                                       | 130 +++++++++++++----
     requirements.txt                                |  43 ++++++
     run.py                                          | 114 ++++++++++++++-
     test/test_api.py                                |  71 ++++++++++
     test/test_basics.py                             |  24 ++++
     test/test_client.py                             |  86 ++++++++++++
     test/test_selenium.py                           |  90 ++++++++++++
     test/test_user_model.py                         |  45 +++++-
     tmp/coverage/app___init___py.html               | 195 ++++++++++++++++++++++++++
     tmp/coverage/app_api_1_0_authentication_py.html | 209 ++++++++++++++++++++++++++++
     tmp/coverage/app_api_1_0_comments_py.html       | 249 +++++++++++++++++++++++++++++++++
     tmp/coverage/app_api_1_0_decorators_py.html     | 133 ++++++++++++++++++
     tmp/coverage/app_api_1_0_errors_py.html         | 133 ++++++++++++++++++
     tmp/coverage/app_api_1_0_posts_py.html          | 239 ++++++++++++++++++++++++++++++++
     tmp/coverage/app_api_1_0_users_py.html          | 241 ++++++++++++++++++++++++++++++++
     tmp/coverage/app_auth_forms_py.html             | 221 +++++++++++++++++++++++++++++
     tmp/coverage/app_auth_views_py.html             | 483 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     tmp/coverage/app_email_py.html                  | 113 +++++++++++++++
     tmp/coverage/app_main___init___py.html          | 117 ++++++++++++++++
     tmp/coverage/app_main_views_py.html             | 823 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     tmp/coverage/app_models_py.html                 | 981 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     tmp/coverage/coverage_html.js                   | 512 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     tmp/coverage/index.html                         | 260 ++++++++++++++++++++++++++++++++++
     tmp/coverage/jquery.debounce.min.js             |   9 ++
     tmp/coverage/jquery.hotkeys.js                  |  99 +++++++++++++
     tmp/coverage/jquery.isonscreen.js               |  53 +++++++
     tmp/coverage/jquery.min.js                      |   4 +
     tmp/coverage/jquery.tablesorter.min.js          |   2 +
     tmp/coverage/keybd_closed.png                   | Bin 0 -> 264 bytes
     tmp/coverage/keybd_open.png                     | Bin 0 -> 267 bytes
     tmp/coverage/status.json                        |   1 +
     tmp/coverage/style.css                          | 326 +++++++++++++++++++++++++++++++++++++++++++
     74 files changed, 7248 insertions(+), 112 deletions(-)
     create mode 100644 Procfile
     create mode 100644 app/api_1_0/__init__.py
     create mode 100644 app/api_1_0/authentication.py
     create mode 100644 app/api_1_0/comments.py
     create mode 100644 app/api_1_0/decorators.py
     create mode 100644 app/api_1_0/errors.py
     create mode 100644 app/api_1_0/posts.py
     create mode 100644 app/api_1_0/users.py
     create mode 100644 app/auth/__init__.py
     create mode 100644 app/auth/forms.py
     create mode 100644 app/auth/views.py
     create mode 100644 app/email.py
     create mode 100644 app/exceptions.py
     create mode 100644 app/main/__init__.py
     create mode 100644 app/main/error.py
     create mode 100644 app/main/forms.py
     create mode 100644 app/main/views.py
     rename app/templates/{ => auth/email}/confirm.html (75%)
     create mode 100644 app/templates/auth/email/confirm.txt
     rename app/templates/{ => auth/email}/confirmmail.html (74%)
     rename app/templates/{ => auth/email}/confirmmail.txt (50%)
     rename app/templates/{ => auth}/login.html (71%)
     rename app/templates/{ => auth}/register.html (100%)
     rename app/templates/{ => auth}/renew.html (100%)
     rename app/templates/{ => auth}/unconfirmed.html (80%)
     delete mode 100644 app/templates/confirm.txt
     rename app/templates/{ => main}/index.html (81%)
     create mode 100644 app/templates/main/moderate.html
     create mode 100644 app_pro.db
     create mode 100644 app_test.db
     create mode 100644 requirements.txt
     create mode 100644 test/test_api.py
     create mode 100644 test/test_basics.py
     create mode 100644 test/test_client.py
     create mode 100644 test/test_selenium.py
     create mode 100644 tmp/coverage/app___init___py.html
     create mode 100644 tmp/coverage/app_api_1_0_authentication_py.html
     create mode 100644 tmp/coverage/app_api_1_0_comments_py.html
     create mode 100644 tmp/coverage/app_api_1_0_decorators_py.html
     create mode 100644 tmp/coverage/app_api_1_0_errors_py.html
     create mode 100644 tmp/coverage/app_api_1_0_posts_py.html
     create mode 100644 tmp/coverage/app_api_1_0_users_py.html
     create mode 100644 tmp/coverage/app_auth_forms_py.html
     create mode 100644 tmp/coverage/app_auth_views_py.html
     create mode 100644 tmp/coverage/app_email_py.html
     create mode 100644 tmp/coverage/app_main___init___py.html
     create mode 100644 tmp/coverage/app_main_views_py.html
     create mode 100644 tmp/coverage/app_models_py.html
     create mode 100644 tmp/coverage/coverage_html.js
     create mode 100644 tmp/coverage/index.html
     create mode 100644 tmp/coverage/jquery.debounce.min.js
     create mode 100644 tmp/coverage/jquery.hotkeys.js
     create mode 100644 tmp/coverage/jquery.isonscreen.js
     create mode 100644 tmp/coverage/jquery.min.js
     create mode 100644 tmp/coverage/jquery.tablesorter.min.js
     create mode 100644 tmp/coverage/keybd_closed.png
     create mode 100644 tmp/coverage/keybd_open.png
     create mode 100644 tmp/coverage/status.json
     create mode 100644 tmp/coverage/style.css
    
    ➜  flask_blog git:(master) git push heroku master
    Counting objects: 491, done.
    Delta compression using up to 4 threads.
    Compressing objects: 100% (482/482), done.
    Writing objects: 100% (491/491), 232.17 KiB | 0 bytes/s, done.
    Total 491 (delta 301), reused 2 (delta 0)
    remote: Compressing source files... done.
    remote: Building source:
    remote:
    remote: -----> Using set buildpack heroku/python
    remote: -----> Python app detected
    remote: -----> Installing runtime (python-2.7.11)
    remote: -----> Installing dependencies with pip
    remote:        Collecting alembic==0.8.4 (from -r requirements.txt (line 1))
    remote:        Downloading alembic-0.8.4.tar.gz (950kB)
    remote:        Collecting bleach==1.4.2 (from -r requirements.txt (line 2))
    remote:        Downloading bleach-1.4.2-py2.py3-none-any.whl
    remote:        Collecting blinker==1.4 (from -r requirements.txt (line 3))
    remote:        Downloading blinker-1.4.tar.gz (111kB)
    remote:        Collecting coverage==4.0.3 (from -r requirements.txt (line 4))
    remote:        Downloading coverage-4.0.3.tar.gz (354kB)
    remote:        Collecting decorator==4.0.6 (from -r requirements.txt (line 5))
    remote:        Downloading decorator-4.0.6-py2.py3-none-any.whl
    remote:        Collecting dominate==2.1.16 (from -r requirements.txt (line 6))
    remote:        Downloading dominate-2.1.16.zip
    remote:        Collecting Flask==0.10.1 (from -r requirements.txt (line 7))
    remote:        Downloading Flask-0.10.1.tar.gz (544kB)
    remote:        Collecting Flask-Bootstrap==3.3.5.7 (from -r requirements.txt (line 8))
    remote:        Downloading Flask-Bootstrap-3.3.5.7.tar.gz (451kB)
    remote:        Collecting Flask-HTTPAuth==2.7.0 (from -r requirements.txt (line 9))
    remote:        Downloading Flask-HTTPAuth-2.7.0.tar.gz
    remote:        Collecting Flask-Login==0.3.2 (from -r requirements.txt (line 10))
    remote:        Downloading Flask-Login-0.3.2.tar.gz
    remote:        Collecting Flask-Mail==0.9.1 (from -r requirements.txt (line 11))
    remote:        Downloading Flask-Mail-0.9.1.tar.gz (45kB)
    remote:        Collecting Flask-Markdown==0.3 (from -r requirements.txt (line 12))
    remote:        Downloading Flask-Markdown-0.3.tar.gz (165kB)
    remote:        Collecting Flask-Migrate==1.6.0 (from -r requirements.txt (line 13))
    remote:        Downloading Flask-Migrate-1.6.0.tar.gz
    remote:        Collecting Flask-Moment==0.5.1 (from -r requirements.txt (line 14))
    remote:        Downloading Flask-Moment-0.5.1.tar.gz
    remote:        Collecting Flask-PageDown==0.2.1 (from -r requirements.txt (line 15))
    remote:        Downloading Flask-PageDown-0.2.1.tar.gz
    remote:        Collecting Flask-Script==2.0.5 (from -r requirements.txt (line 16))
    remote:        Downloading Flask-Script-2.0.5.tar.gz (42kB)
    remote:        Collecting Flask-SQLAlchemy==2.1 (from -r requirements.txt (line 17))
    remote:        Downloading Flask-SQLAlchemy-2.1.tar.gz (95kB)
    remote:        Collecting Flask-SSLify==0.1.5 (from -r requirements.txt (line 18))
    remote:        Downloading Flask-SSLify-0.1.5.tar.gz
    remote:        Collecting Flask-WTF==0.12 (from -r requirements.txt (line 19))
    remote:        Downloading Flask_WTF-0.12-py2-none-any.whl
    remote:        Collecting ForgeryPy==0.1 (from -r requirements.txt (line 20))
    remote:        Downloading ForgeryPy-0.1.tar.gz
    remote:        Collecting gunicorn==19.4.5 (from -r requirements.txt (line 21))
    remote:        Downloading gunicorn-19.4.5-py2.py3-none-any.whl (112kB)
    remote:        Collecting html5lib==0.9999999 (from -r requirements.txt (line 22))
    remote:        Downloading html5lib-0.9999999.tar.gz (889kB)
    remote:        Collecting httpie==0.9.3 (from -r requirements.txt (line 23))
    remote:        Downloading httpie-0.9.3-py2.py3-none-any.whl (66kB)
    remote:        Collecting itsdangerous==0.24 (from -r requirements.txt (line 24))
    remote:        Downloading itsdangerous-0.24.tar.gz (46kB)
    remote:        Collecting Jinja2==2.8 (from -r requirements.txt (line 25))
    remote:        Downloading Jinja2-2.8-py2.py3-none-any.whl (263kB)
    remote:        Collecting Mako==1.0.3 (from -r requirements.txt (line 26))
    remote:        Downloading Mako-1.0.3.tar.gz (565kB)
    remote:        Collecting Markdown==2.6.5 (from -r requirements.txt (line 27))
    remote:        Downloading Markdown-2.6.5.tar.gz (301kB)
    remote:        Collecting MarkupSafe==0.23 (from -r requirements.txt (line 28))
    remote:        Downloading MarkupSafe-0.23.tar.gz
    remote:        Collecting pbr==1.8.1 (from -r requirements.txt (line 29))
    remote:        Downloading pbr-1.8.1-py2.py3-none-any.whl (89kB)
    remote:        Collecting psycopg2==2.6.1 (from -r requirements.txt (line 30))
    remote:        Downloading psycopg2-2.6.1.tar.gz (371kB)
    remote:        Collecting Pygments==2.0.2 (from -r requirements.txt (line 31))
    remote:        Downloading Pygments-2.0.2-py2-none-any.whl (672kB)
    remote:        Collecting python-editor==0.5 (from -r requirements.txt (line 32))
    remote:        Downloading python-editor-0.5.tar.gz
    remote:        Collecting requests==2.9.1 (from -r requirements.txt (line 33))
    remote:        Downloading requests-2.9.1-py2.py3-none-any.whl (501kB)
    remote:        Collecting selenium==2.48.0 (from -r requirements.txt (line 34))
    remote:        Downloading selenium-2.48.0-py2-none-any.whl (872kB)
    remote:        Collecting six==1.10.0 (from -r requirements.txt (line 35))
    remote:        Downloading six-1.10.0-py2.py3-none-any.whl
    remote:        Collecting SQLAlchemy==1.0.10 (from -r requirements.txt (line 36))
    remote:        Downloading SQLAlchemy-1.0.10.tar.gz (4.7MB)
    remote:        Collecting sqlalchemy-migrate==0.10.0 (from -r requirements.txt (line 37))
    remote:        Downloading sqlalchemy_migrate-0.10.0-py2-none-any.whl (108kB)
    remote:        Collecting sqlparse==0.1.18 (from -r requirements.txt (line 38))
    remote:        Downloading sqlparse-0.1.18.tar.gz (58kB)
    remote:        Collecting Tempita==0.5.2 (from -r requirements.txt (line 39))
    remote:        Downloading Tempita-0.5.2.tar.gz
    remote:        Collecting visitor==0.1.2 (from -r requirements.txt (line 40))
    remote:        Downloading visitor-0.1.2.tar.gz
    remote:        Collecting Werkzeug==0.11.2 (from -r requirements.txt (line 41))
    remote:        Downloading Werkzeug-0.11.2-py2.py3-none-any.whl (304kB)
    remote:        Collecting wheel==0.24.0 (from -r requirements.txt (line 42))
    remote:        Downloading wheel-0.24.0-py2.py3-none-any.whl (63kB)
    remote:        Collecting WTForms==2.0.2 (from -r requirements.txt (line 43))
    remote:        Downloading WTForms-2.0.2-py27-none-any.whl (128kB)
    remote:        Installing collected packages: SQLAlchemy, MarkupSafe, Mako, python-editor, alembic, six, html5lib, bleach, blinker, coverage, decorator, dominate, Werkzeug, Jinja2, itsdangerous, Flask, visitor, Flask-Bootstrap, Flask-HTTPAuth, Flask-Login, Flask-Mail, Markdown, Flask-Markdown, Flask-SQLAlchemy, Flask-Script, Flask-Migrate, Flask-Moment, WTForms, Flask-PageDown, Flask-SSLify, Flask-WTF, ForgeryPy, gunicorn, Pygments, requests, httpie, pbr, psycopg2, selenium, sqlparse, Tempita, sqlalchemy-migrate, wheel
    remote:        Running setup.py install for SQLAlchemy
    remote:        Running setup.py install for MarkupSafe
    remote:        Running setup.py install for Mako
    remote:        Running setup.py install for python-editor
    remote:        Running setup.py install for alembic
    remote:        Running setup.py install for html5lib
    remote:        Running setup.py install for blinker
    remote:        Running setup.py install for coverage
    remote:        Running setup.py install for dominate
    remote:        Running setup.py install for itsdangerous
    remote:        Running setup.py install for Flask
    remote:        Running setup.py install for visitor
    remote:        Running setup.py install for Flask-Bootstrap
    remote:        Running setup.py install for Flask-HTTPAuth
    remote:        Running setup.py install for Flask-Login
    remote:        Running setup.py install for Flask-Mail
    remote:        Running setup.py install for Markdown
    remote:        Running setup.py install for Flask-Markdown
    remote:        Running setup.py install for Flask-SQLAlchemy
    remote:        Running setup.py install for Flask-Script
    remote:        Running setup.py install for Flask-Migrate
    remote:        Running setup.py install for Flask-Moment
    remote:        Running setup.py install for Flask-PageDown
    remote:        Running setup.py install for Flask-SSLify
    remote:        Running setup.py install for ForgeryPy
    remote:        Running setup.py install for psycopg2
    remote:        Running setup.py install for sqlparse
    remote:        Running setup.py install for Tempita
    remote:        Successfully installed Flask-0.10.1 Flask-Bootstrap-3.3.5.7 Flask-HTTPAuth-2.7.0 Flask-Login-0.3.2 Flask-Mail-0.9.1 Flask-Markdown-0.3 Flask-Migrate-1.6.0 Flask-Moment-0.5.1 Flask-PageDown-0.2.1 Flask-SQLAlchemy-2.1 Flask-SSLify-0.1.5 Flask-Script-2.0.5 Flask-WTF-0.12 ForgeryPy-0.1 Jinja2-2.8 Mako-1.0.3 Markdown-2.6.5 MarkupSafe-0.23 Pygments-2.0.2 SQLAlchemy-1.0.10 Tempita-0.5.2 WTForms-2.0.2 Werkzeug-0.11.2 alembic-0.8.4 bleach-1.4.2 blinker-1.4 coverage-4.0.3 decorator-4.0.6 dominate-2.1.16 gunicorn-19.4.5 html5lib-0.9999999 httpie-0.9.3 itsdangerous-0.24 pbr-1.8.1 psycopg2-2.6.1 python-editor-0.5 requests-2.9.1 selenium-2.48.0 six-1.10.0 sqlalchemy-migrate-0.10.0 sqlparse-0.1.18 visitor-0.1.2 wheel-0.24.0
    remote:
    remote:
    remote: -----> Discovering process types
    remote:        Procfile declares types -> web
    remote:
    remote: -----> Compressing... done, 44.6MB
    remote: -----> Launching...
    remote:        Released v7
    remote:        https://flask-blog-chaonet.herokuapp.com/ deployed to Heroku
    remote:
    remote: Verifying deploy... done.
    To https://git.heroku.com/flask-blog-chaonet.git
     * [new branch]      master -> master
    

    成功,按照requirements.txt安装依赖的库

    建立运行环境数据库

    ➜  flask_blog git:(master) heroku run python run.py deploy
    Running python run.py deploy on flask-blog-chaonet... up, run.6723
    /app/.heroku/python/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.
      warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.')
    INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
    INFO  [alembic.runtime.migration] Will assume transactional DDL.
    INFO  [alembic.runtime.migration] Running upgrade  -> c1b387222189, empty message
    INFO  [alembic.runtime.migration] Running upgrade c1b387222189 -> c4a4f802bdf4, empty message
    INFO  [alembic.runtime.migration] Running upgrade c4a4f802bdf4 -> 83e0975c0db1, add role permission
    INFO  [alembic.runtime.migration] Running upgrade 83e0975c0db1 -> ee9c55ba9b22, add user profile
    INFO  [alembic.runtime.migration] Running upgrade ee9c55ba9b22 -> 431d275d6a70, add user.about_me
    INFO  [alembic.runtime.migration] Running upgrade 431d275d6a70 -> d6f4efe3ffe1, add User.avatar_hash
    INFO  [alembic.runtime.migration] Running upgrade d6f4efe3ffe1 -> ac6e9871c9a4, add Post ,relationship with User
    INFO  [alembic.runtime.migration] Running upgrade ac6e9871c9a4 -> 6f219f6bca6e, add Post.on_changed_body, body_html, db.event.listen
    INFO  [alembic.runtime.migration] Running upgrade 6f219f6bca6e -> 3aca4362a467, add Follow model, user.followers
                                                                                                                    ollowed
    INFO  [alembic.runtime.migration] Running upgrade 3aca4362a467 -> e3cfb10aeab6, add comment model
    

    创建并配置好数据库表之后就可以重启程序了,直接使用下述命令即可:

         $ heroku restart
         Restarting dynos... done
    

    至此,程序就完全部署好了,可通过 https://<appname>.hero-kuapp.com 访问。

    查看日志


    不同类型的消息,会通过颜色区分显示

    ➜  flask_blog git:(master) heroku logs
    ...
    2016-01-10T09:04:16.778460+00:00 heroku[run.6723]: Awaiting client
    2016-01-10T09:04:16.871340+00:00 heroku[run.6723]: Starting process with command `python run.py deploy`
    2016-01-10T09:04:17.236929+00:00 heroku[run.6723]: State changed from starting to up
    2016-01-10T09:04:20.574974+00:00 heroku[run.6723]: State changed from up to complete
    2016-01-10T09:04:20.567984+00:00 heroku[run.6723]: Process exited with status 0
    2016-01-10T09:14:49.296965+00:00 heroku[web.1]: State changed from up to starting
    2016-01-10T09:14:53.791001+00:00 heroku[web.1]: Starting process with command `gunicorn run:app`
    2016-01-10T09:14:54.840605+00:00 heroku[web.1]: Stopping all processes with SIGTERM
    2016-01-10T09:14:56.154205+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Starting gunicorn 19.4.5
    2016-01-10T09:14:56.230606+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [10] [INFO] Booting worker with pid: 10
    2016-01-10T09:14:56.154848+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Listening at: http://0.0.0.0:10268 (3)
    2016-01-10T09:14:56.154974+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Using worker: sync
    2016-01-10T09:14:56.160120+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [9] [INFO] Booting worker with pid: 9
    2016-01-10T09:14:56.476881+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [10] [INFO] Worker exiting (pid: 10)
    2016-01-10T09:14:56.547413+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Shutting down: Master
    2016-01-10T09:14:56.475915+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [9] [INFO] Worker exiting (pid: 9)
    2016-01-10T09:14:56.529060+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Handling signal: term
    2016-01-10T09:14:56.954815+00:00 app[web.1]: /app/.heroku/python/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.
    2016-01-10T09:14:56.954818+00:00 app[web.1]:   warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.')
    2016-01-10T09:14:57.283202+00:00 app[web.1]:   warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.')
    2016-01-10T09:14:57.283198+00:00 app[web.1]: /app/.heroku/python/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.
    2016-01-10T09:14:57.480937+00:00 heroku[web.1]: State changed from starting to up
    2016-01-10T09:14:57.513335+00:00 heroku[web.1]: Process exited with status 0
    2016-01-10T09:15:06.569626+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=32f4cf3a-d766-441b-bbe1-0e7052a37209 fwd="107.161.27.197" dyno=web.1 connect=0ms service=291ms status=200 bytes=3417
    2016-01-10T09:15:09.079151+00:00 heroku[router]: at=info method=GET path="/favicon.ico" host=flask-blog-chaonet.herokuapp.com request_id=4e065440-cb19-420a-834e-8e4d8e4c956c fwd="107.161.27.197" dyno=web.1 connect=1ms service=19ms status=404 bytes=655
    2016-01-10T09:15:16.012079+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=ac1e63ac-0133-4cad-adac-66563437c70c fwd="107.161.27.197" dyno=web.1 connect=0ms service=506ms status=200 bytes=3504
    2016-01-10T09:15:17.703574+00:00 heroku[router]: at=info method=GET path="/followed" host=flask-blog-chaonet.herokuapp.com request_id=0fc98138-ca6f-4873-8327-4a22f892d432 fwd="107.161.27.197" dyno=web.1 connect=1ms service=13ms status=302 bytes=875
    2016-01-10T09:15:18.327896+00:00 heroku[router]: at=info method=GET path="/auth/login?next=%2Ffollowed" host=flask-blog-chaonet.herokuapp.com request_id=8d44ff19-c673-4e61-929e-d6ce89678b3a fwd="107.161.27.197" dyno=web.1 connect=0ms service=25ms status=200 bytes=4071
    2016-01-10T09:15:19.085786+00:00 heroku[router]: at=info method=GET path="/favicon.ico" host=flask-blog-chaonet.herokuapp.com request_id=d327a6e7-f26b-4514-8813-c2af94dfd639 fwd="107.161.27.197" dyno=web.1 connect=0ms service=3ms status=404 bytes=655
    2016-01-10T09:15:20.795897+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=de598303-d092-4647-8758-9e050d089f2e fwd="107.161.27.197" dyno=web.1 connect=2ms service=23ms status=200 bytes=3504
    2016-01-10T09:15:22.840818+00:00 heroku[router]: at=info method=GET path="/auth/login" host=flask-blog-chaonet.herokuapp.com request_id=db4a579c-d80b-4205-963e-53d4f8aeb4a3 fwd="107.161.27.197" dyno=web.1 connect=2ms service=9ms status=200 bytes=4014
    2016-01-10T09:15:25.834388+00:00 heroku[router]: at=info method=GET path="/auth/register" host=flask-blog-chaonet.herokuapp.com request_id=32a0d112-6dfa-4c8b-bd25-2bf0296add0d fwd="107.161.27.197" dyno=web.1 connect=2ms service=31ms status=200 bytes=4084
    2016-01-10T09:15:28.548938+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=0f731062-0cfe-4e51-8967-13ab87ef03c5 fwd="107.161.27.197" dyno=web.1 connect=2ms service=15ms status=200 bytes=3504
    

    应用程序维护模式


    维护时可以设置显示维护信息

    ➜  flask_blog git:(master) heroku maintenance -h
    Usage: heroku maintenance
    
    display the current maintenance status of app
    
     -a, --app APP       # app to run command against
     -r, --remote REMOTE # git remote of app to run command against
    
    Additional commands, type "heroku help COMMAND" for more details:
    
      maintenance:off  #  take the app out of maintenance mode
      maintenance:on   #  put the app into maintenance mode
    

    开启显示维护信息

    ➜  flask_blog git:(master) heroku maintenance:on
    Enabling maintenance mode for flask-blog-chaonet... done
    

    页面显示的内容

    Application Offline for Maintenance
    This application is undergoing maintenance right now. Please check back later.
    

    维护结束后,重新开启应用,正常访问

    ➜  flask_blog git:(master) heroku maintenance:off
    Disabling maintenance mode for flask-blog-chaonet... done
    

    相关文章

      网友评论

      • cc716df53c9f:您好,我是按照https://devcenter.heroku.com/articles/getting-started-with-python的步骤部署我的python代码的,可是在执行了heroku create之后命令窗口中没有出现Git remote heroku added 这句话,导致我最后打开网页的时候是Getting Started with Python on Heroku的主页.不知道如何调整,是不是前面做的不对?求教,谢谢...
      • 武林盟主vs:看了半天没搞懂。我就想问一下“➜ flask_blog git:(rest) ✗ heroku local” 这个玩意是什么东西,为什么我本地不一样,git bash 开头是 已“$ ”开始的。你这是咋整的
      • 地表最强程序员小白:收费的吗
        927cd4088d63:https://fsdhub.com/
        这里入门有教,不过你需要买书。
      • 目染江夏:注册怎么老提示这个呀 ,,,,

        Please confirm you're not a robot.
        目染江夏:@SweetMacaron 哈哈哈
        mah93:需要科学上网
      • 路墨:注册不了,真伤心,作者能不能帮我注册下
        目染江夏:@路墨 这样呀
        路墨:@目染江夏 对的,需要翻墙
        目染江夏:@路墨 你的是提示 Please confirm you're not a robot.这个吗?
        我的一直提示呀
      • LEONYao:最后部署成功了,可是发不了新的信息,新注册用户过一段时间会被清空。。。这应该是数据库问题,怎么破
      • 凌越:为什么我安装的时候会提示
        This script requires superuser access to install software.
        You will be prompted for your password by sudo.
        然后就没反应了?
        超net:@凌越 用 root 权限安装

      本文标题:Heroku 使用教程

      本文链接:https://www.haomeiwen.com/subject/crlmkttx.html