Heroku Flask 教程 Procfile 含义

Posted

技术标签:

【中文标题】Heroku Flask 教程 Procfile 含义【英文标题】:Heroku Flask Tutorial Procfile Meaning 【发布时间】:2015-07-22 14:44:07 【问题描述】:

在herokututorial中有一段代码

hello.py

import os
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello World!'

还有一个 Procfile:

web: gunicorn hello:app --log-file=-

真正令人困惑的部分是hello:app 部分; hello 是指hello() 函数还是 hello.py 脚本?根据其含义,整个 Procfile 语句是什么意思?

【问题讨论】:

【参考方案1】:

tl;dr:hello 指的是hello.pyapp 指的是app = Flask(__name__)


上面提到的 Heroku 教程不再可用,但是 Gunicorn's doc 给出了一个很好的最小示例:

测试应用示例:

def app(environ, start_response):
    """Simplest possible application object"""
    data = b'Hello, World!\n'
    status = '200 OK'
    response_headers = [
        ('Content-type', 'text/plain'),
        ('Content-Length', str(len(data)))
    ]
    start_response(status, response_headers)
    return iter([data])

您现在可以使用以下命令运行应用程序:

$ gunicorn --workers=2 test:app


让我们试试,我的 test-directory 是这样的:

(.venv) 14:41 ~/testgunicorn % tree
.
├── requirements.txt
└── testpkg
    ├── __init__.py
    └── testfile.py

__init__.py

from flask import Flask
from .testfile import app

testfile.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

def app(environ, start_response):
    """Simplest possible application object"""
    data = b'Hello, World!\n'
    status = '200 OK'
    response_headers = [
        ('Content-type', 'text/plain'),
        ('Content-Length', str(len(data)))
    ]
    start_response(status, response_headers)
    return iter([data])

打错电话

(.venv) 14:41 ~/testgunicorn % gunicorn testfile:app         
[2018-08-24 14:41:44 +0200] [27248] [INFO] Starting gunicorn 19.9.0
[2018-08-24 14:41:44 +0200] [27248] [INFO] Listening at: http://127.0.0.1:8000 (27248)
[2018-08-24 14:41:44 +0200] [27248] [INFO] Using worker: sync
[2018-08-24 14:41:44 +0200] [27251] [INFO] Booting worker with pid: 27251
[2018-08-24 14:41:44 +0200] [27251] [ERROR] Exception in worker process
Traceback (most recent call last):
  File "~/testgunicorn/.venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
    worker.init_process()
  File "~/testgunicorn/.venv/lib/python3.6/site-packages/gunicorn/workers/base.py", line 129, in init_process
    self.load_wsgi()
  File "~/testgunicorn/.venv/lib/python3.6/site-packages/gunicorn/workers/base.py", line 138, in load_wsgi
    self.wsgi = self.app.wsgi()
  File "~/testgunicorn/.venv/lib/python3.6/site-packages/gunicorn/app/base.py", line 67, in wsgi
    self.callable = self.load()
  File "~/testgunicorn/.venv/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 52, in load
    return self.load_wsgiapp()
  File "~/testgunicorn/.venv/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 41, in load_wsgiapp
    return util.import_app(self.app_uri)
  File "~/testgunicorn/.venv/lib/python3.6/site-packages/gunicorn/util.py", line 350, in import_app
    __import__(module)
ModuleNotFoundError: No module named 'testfile'
[2018-08-24 14:41:44 +0200] [27251] [INFO] Worker exiting (pid: 27251)
[2018-08-24 14:41:44 +0200] [27248] [INFO] Shutting down: Master
[2018-08-24 14:41:44 +0200] [27248] [INFO] Reason: Worker failed to boot.
zsh: exit 3     gunicorn testfile:app    

好召唤

(.venv) 14:43 ~/testgunicorn % gunicorn testpkg:app 
[2018-08-24 14:43:56 +0200] [27302] [INFO] Starting gunicorn 19.9.0
[2018-08-24 14:43:56 +0200] [27302] [INFO] Listening at: http://127.0.0.1:8000 (27302)
[2018-08-24 14:43:56 +0200] [27302] [INFO] Using worker: sync
[2018-08-24 14:43:56 +0200] [27305] [INFO] Booting worker with pid: 27305
^C
(…)

(.venv) 15:03 ~/testgunicorn % cd testpkg    
(.venv) 15:03 fred@susa ~/git/ocp7/testpkg % gunicorn testfile:app
[2018-08-24 15:03:22 +0200] [27494] [INFO] Starting gunicorn 19.9.0
[2018-08-24 15:03:22 +0200] [27494] [INFO] Listening at: http://127.0.0.1:8000 (27494)
[2018-08-24 15:03:22 +0200] [27494] [INFO] Using worker: sync
[2018-08-24 15:03:22 +0200] [27497] [INFO] Booting worker with pid: 27497
^C
(…)

那么对于这个Procfile

web: gunicorn hello:app --log-file=-

hello 是指 hello() 函数还是 hello.py 脚本?

hello.py 脚本

根据其含义,整个 Procfile 语句是什么意思?

Heroku 的 Procfile format documentation 说:

Procfile 在单独的行上声明它的进程类型,每行都有 以下格式:

<process type>: <command>

<process type> 是您的命令的字母数字名称,例如 web、worker、urgentworker、clock 等。 <command> 表示每个进程类型的dyno在启动时应该执行的命令,例如rake jobs:work。

--logfile=- 选项似乎已被弃用,我在文档中没有找到任何关于它的信息,如果我使用它,我会收到此错误:

(.venv) 15:34 ~/testgunicorn % heroku local web
[WARN] No ENV file found
15:34:30 web.1   |  usage: gunicorn [OPTIONS] [APP_MODULE]
15:34:30 web.1   |  gunicorn: error: unrecognized arguments: --logfile=-
15:34:30 web.1   Exited with exit code 2

根据this answer,这是一个登录 Heroku 标准输出的选项。

【讨论】:

【参考方案2】:

ProcFile 包含用于在 heroku 上启动应用程序的命令行。完整的文档可以在这里找到:https://devcenter.heroku.com/articles/procfile

在这种情况下,它告诉 heroku 使用带有 gunicorn 的 hello 模块中的 app 变量(您构建的烧瓶应用程序)并启动一个 Web 进程(一个可以处理 http 请求的进程)。您还可以指定其他进程类型,例如后台工作人员。

您的烧瓶应用程序对象是一个 WSGI 应用程序,可以使用任何 WSGI 服务器运行。 Gunicorn 只是 heroku 上的选择之一。

【讨论】:

【参考方案3】:

1- 根据Heroku doc部分Procfile格式

web: gunicorn hello:app  

是一个:模式

2- web 因此是。根据同样的documentation:“Heroku 应用程序的 Web 进程类型是唯一可以从 Heroku 路由器接收外部 HTTP 流量的进程类型。如果您的应用程序包含 Web 服务器,则应将其声明为您的应用程序的 Web 进程。”

3- 现在是 部分:

gunicorn hello:app  

如果您查看gunicorn doc 部分基本用法,您会看到 gunicorn 的典型命令是

$ gunicorn [OPTIONS] APP_MODULE

APP_MODULE 的格式为 $(MODULE_NAME):$(VARIABLE_NAME)。

因此,在您的示例中,hello 指的是 $(MODULE_NAME),即 hello.py。请注意,如有必要,它可以是完整的虚线路径。同样,app 指的是一个 WSGI 可调用 $(VARIABLE_NAME),它应该在指定的 hello 模块中找到,并且在您实例化 Flask 类时实际定义: app = Flask(__name__).

【讨论】:

以上是关于Heroku Flask 教程 Procfile 含义的主要内容,如果未能解决你的问题,请参考以下文章

Heroku 服务器中 Procfile 和 Procfile.Windows 之间的区别

Heroku 在错误的目录中寻找 Procfile

Heroku for Django 1.8 的 Procfile

scala play 应用程序的 Heroku procfile

Heroku,Java,Procfile,找不到或加载主类

Procfile 在 Heroku 中声明类型 -> (none)