5

问题描述

我正在尝试为 Google App Engine 创建一个自定义托管 VM,其行为与 Google 提供的标准 python27 托管 VM 相同。(我这样做是向运行时添加 C++ 库的第一步)。

从 google文档中,以下 Dockerfile 指定了标准的 python27 运行时:

FROM gcr.io/google_appengine/python-compat
ADD . /app

gcloud preview app run通过检查使用标准 python27 运行时生成的文件,我已经验证了这是正确的 Dockerfile 。它与此相同。

但是当我使用这个 Dockerfile 运行我的应用程序时dev_appserver.pygcloud preview app run我收到一条错误消息:

The --custom_entrypoint flag must be set for custom runtimes

我正在使用最新版本的 gcloud(1.9.86,带有 app-engine-python 组件版本 1.9.28)和独立的 python 应用引擎 SDK(1.9.28)。我之前的版本也有同样的问题,所以我更新到最新版本。

我尝试过的事情:

gcloud preview app run --help有以下要说的--custom-entrypoint

 --custom-entrypoint CUSTOM_ENTRYPOINT
    Specify an entrypoint for custom runtime modules. This is required when
    such modules are present. Include "{port}" in the string (without
    quotes) to pass the port number in as an argument. For instance:
    --custom_entrypoint="gunicorn -b localhost:{port} mymodule:application"

我不知道该怎么做。docker 映像是否应该尚未包含 ENTRYPOINT?为什么我需要另外提供一份?另外,图像的入口点应该gcr.io/google_appengine/python-compat是什么?谷歌没有为此提供任何文档。

我尝试了一个无意义的--custom-entrypoint="echo",它使错误静音,但应用程序不响应任何 HTTP 请求。

我发现的另外两个相关的 stackoverflow 问题没有帮助。接受的答案似乎表明这是已解决的 SDK 中的错误。但是我在两个版本的SDK中都试过了,包括最新的,还是有问题。

重现步骤:

为了突出我的问题,我创建了一个生成错误的简单应用程序。它仅包含三个文件:

app.yaml

module: default
version: 1
runtime: custom
api_version: 1
threadsafe: true
vm: true

handlers:
- url: /.*
  script: wsgi.app

Dockerfile

FROM gcr.io/google_appengine/python-compat
ADD . /app

Dockerfile与用于 python27 运行时的相同(实际上是从使用 python27gcloud preview app run运行时生成的 Dockerfile 复制粘贴的),因此这应该与设置相同runtime: python27

wsgi.py

import webapp2

class Hello(webapp2.RequestHandler):
    def get(self):
        self.response.write(u'Hello')

app = webapp2.WSGIApplication([('/Hello', Hello)], debug=True)

但是,当我dev_appserver.py app.yaml在包含这三个文件的目录中运行时,出现以下错误:

Traceback (most recent call last):
  File "/home/vagrant/google-cloud-sdk/platform/google_appengine/dev_appserver.py", line 83, in <module>
    _run_file(__file__, globals())
  File "/home/vagrant/google-cloud-sdk/platform/google_appengine/dev_appserver.py", line 79, in _run_file
    execfile(_PATHS.script_file(script_name), globals_)
  File "/home/vagrant/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/devappserver2.py", line 1033, in <module>
    main()
  File "/home/vagrant/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/devappserver2.py", line 1026, in main
    dev_server.start(options)
  File "/home/vagrant/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/devappserver2.py", line 818, in start
    self._dispatcher.start(options.api_host, apis.port, request_data)
  File "/home/vagrant/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/dispatcher.py", line 194, in start
    _module.start()
  File "/home/vagrant/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/module.py", line 1555, in start
    self._add_instance()
  File "/home/vagrant/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/module.py", line 1707, in _add_instance
    expect_ready_request=True)
  File "/home/vagrant/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/custom_runtime.py", line 73, in new_instance
    assert self._runtime_config_getter().custom_config.custom_entrypoint
  File "/home/vagrant/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/module.py", line 383, in _get_runtime_config
    raise ValueError('The --custom_entrypoint flag must be set for '
ValueError: The --custom_entrypoint flag must be set for custom runtimes
4

3 回答 3

10

更新

这可能不再准确。见尼克的回答。

(虽然我不能让它工作。但我没有很努力)


自定义托管虚拟机有一个完全未记录但绝对重要的信息:

它们不能在开发服务器上运行!

如果你认为这个重要的事实会在任何理智的地方被提及,比如自定义托管 VM 的文档页面,或者 for dev_appserver.py,甚至是运行时的错误消息dev_appserver.py,那么你对谷歌的信任太高了。

我唯一能找到任何关于此声明的地方是在github 上的appengine-java-vm-guestbook-extras 演示的自述文件中(说真的):

提供 Dockerfile 时,Cloud SDK 不再支持运行自定义运行时。您必须将应用程序部署到 App Engine

Google 不关心:

  1. 实现这个基本且重要的功能。
  2. 记录开发服务器缺少如此重要的功能。
  3. 当用户厌倦执行操作时,给出任何合理的错误信息。

我希望这个答案可以让一些遗憾的开发人员免于我因此而遭受的折磨。

于 2015-11-19T20:48:52.907 回答
6

编辑 1user862857发布的解决方案利用 Docker 本身从 Dockerfile 构建图像并在容器中运行它们。这也是在开发环境中运行托管 VM 和自定义运行时的好方法。


接受的答案似乎不正确。在处理快速发展的 Beta 产品时,github README 不应该胜过官方文档的权威性。runtime: custom使用OP帖子中提到的Dockerfile,开发环境中的应用程序完全有可能,

FROM gcr.io/google_appengine/python-compat
ADD . /app

使用--runtime=python-compat标志。不过,他们需要捕获对/_ah/startand的请求/_ah/health。尝试运行以下命令,给定以下文件,并亲自查看:

devserver command

$ dev_appserver.py app.yaml --runtime=python-compat

app.yaml

runtime: custom
vm: true
api_version: 1
threadsafe: true

handlers:
- url: /.*
  script: main.app

Dockerfile

FROM gcr.io/google_appengine/python-compat

RUN apt-get update

RUN apt-get install -y gwhois

ADD . /app

main.py

import logging
import webapp2
from subprocess import Popen, PIPE

class OkHandler (webapp2.RequestHandler):
    def get (self): 
        self.response.write ('ok')

class MainPage(webapp2.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        domain = self.request.get ('domain')
        cmd = ["gwhois", domain]
        process = Popen (cmd, stdout=PIPE, stderr=PIPE)
        output, err = process.communicate()
        exit_code = process.wait()
        self.response.write('stdout: %s' % output)
        logging.info ('stderr: %s' % err)

app = webapp2.WSGIApplication([
    ('/', MainPage),
    ('/_ah/start', OkHandler),
    ('/_ah/health', OkHandler)
], debug=True)

发送请求以/?domain=stackoverflow.com查看此操作。


注意

如果他们希望完全从 python-compat 运行时中解耦并简单地部署/测试一个 python WSGI 应用程序,他们也可以使用该--custom_entrypoint标志,只要他们有一个命令可以开始在合适的端口上运行适当的 WSGI 应用程序(这样的命令将是uwsgigunicorn)。

于 2015-12-15T00:37:16.100 回答
0

在尝试让我的自定义 VM 与 dev_appserver 一起工作一天的大部分时间后,这篇文章的公认答案令人非常不愉快。但我认为部署开发服务器不会那么麻烦,因为毕竟虚拟机是标准的 Docker 映像。

好吧,确实有一些问题阻止了直接部署的工作。我在下面提供了这些问题的摘要以及我如何解决它们。我可能错过了 Docker 和 App Engine 环境之间的一些不兼容性(尤其是我的项目没有使用的 App Engine 的许多方面),但希望它足以让人们启动和运行。

麻烦的来源

首先,我发现在 Compute Engine 虚拟机中运行的 python 环境比普通的虚拟机环境要宽松一些(例如,像这样的包webapp2总是可用的)。因此,部署到不太宽容的 Docker 容器环境中,我的项目中出现了一些潜在的错误。

话虽如此,即使您的项目完美无缺,环境也存在一些差异,需要进行一些调整:

  • 问题:gunicorn(或您选择的服务器)必须安装在 Docker 容器的路径上。

    • 虽然这看起来很明显,但我遇到了麻烦,因为我包含 gunicorn在我的项目requirements.txt文件中。不幸的是,我正在使用pip install -t ...只能安装源代码的所有这些依赖项进行安装。结果,gunicorn图像上没有二进制文件,更不用说PATH.
  • 解决方案:明确pip install gunicorn


  • 问题: google.appengine.* App Engine 基础 Docker 映像中不提供包,也不能通过 pip (AFAICT) 提供包。
    • 这可能是一个常见的问题来源,因为这google.appengine.ext.vendor是将第三方库导入 App Engine 应用程序的推荐界面。
  • 解决方案:我通过下载整个 Google App Engine 包层次结构并将其放在应用程序的路径上来解决这个问题。

脚本获取方式

此处提供了用于构建 VM docker 映像并将其部署到本地运行的 docker 容器的脚本 。

对于一个工作示例,请查看我的项目

如果您有评论、功能请求,或者您是否编写了比我更漂亮的 bash,请告诉我(我觉得我在这方面设置的标准非常低)。

于 2015-12-16T06:15:21.653 回答