>问题描述
我正在尝试为Google App Engine创建一个自定义托管VM,其行为与Google提供的标准python27托管VM相同。(我这样做是将C++库添加到运行时的第一步(。
从 google 文档中,以下 Dockerfile 指定了标准的 python27 运行时:
FROM gcr.io/google_appengine/python-compat
ADD . /app
我已经通过检查使用标准 python27 运行时由 gcloud preview app run
生成的文件来验证这是正确的 Dockerfile。它与此相同。
但是当我使用 dev_appserver.py
或 gcloud preview app run
使用此 Dockerfile 运行我的应用程序时,我收到一条错误消息:
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 映像是否应该已经包含入口点?为什么需要我另外提供一个?另外,gcr.io/google_appengine/python-compat
图像的入口点应该是什么?谷歌没有为此提供任何文档。
我尝试了一个毫无意义的--custom-entrypoint="echo"
,它使错误静音,但应用程序不响应任何HTTP请求。
我发现的另外两个相关的堆栈溢出问题没有帮助。接受的答案似乎表明这是已解决的 SDK 中的错误。但是我已经在两个版本的SDK中尝试过,包括最新版本,但我仍然有问题。
- 如何解决"
The --custom_entrypoint flag must be set for custom runtimes
"? - Google 托管虚拟机错误 - 自定义入口点
步骤:
为了突出我的问题,我创建了一个生成错误的简单应用程序。它仅包含三个文件:
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 运行时的相同(实际上实际上是从使用 python27 运行时gcloud 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
更新
这可能不再准确。看到尼克的回答。
(虽然我无法做到这一点。但我并没有很努力(
自定义
托管 VM 有一条完全未记录但绝对必要的信息:
它们不能在开发服务器上运行!
如果您认为这个关键事实会在任何理智的地方提及,例如,自定义托管虚拟机的文档页面,或dev_appserver.py
,甚至在运行时作为错误消息 dev_appserver.py
,那么你给了谷歌太多的信任。
我唯一可以找到任何关于此声明的地方是在github上的appengine-java-vm-guestbook-extras演示的自述文件中(认真的(:
云 SDK 不再支持在以下情况下运行自定义运行时 提供了 Dockerfile。您必须将应用程序部署到应用 发动机
谷歌不在乎:
- 实现此基本且重要的功能。
- 记录开发服务器缺少如此重要的功能。
- 当用户疲倦执行操作时,给出任何合理的错误消息。
我希望这个答案能拯救一些可怜的开发人员,使他们免于因此而遭受折磨的日子。
编辑 1:user862857 发布的解决方案利用 Docker 本身从 Dockerfile 构建映像并在容器中运行它们。这也是在开发上下文中运行托管 VM 和自定义运行时的好方法。
接受的答案似乎不正确。在处理快速发展的 Beta 产品时,github 自述文件不应胜过官方文档的权威性。在开发环境中使用OP帖子中提到的Dockerfile完全可以runtime: custom
应用程序,
FROM gcr.io/google_appengine/python-compat
ADD . /app
使用 --runtime=python-compat
标志。不过,他们需要捕获/_ah/start
和/_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运行时完全解耦,并简单地通过a部署/测试python WSGI应用程序,他们也可以使用--custom_entrypoint
标志,只要他们有一个命令可以开始在合适的端口上运行适当的WSGI应用程序(这样的命令将是uwsgi或gunicorn(。
在尝试让我的自定义 VM 更好地与dev_appserver一起工作之后一天的一部分,被接受的这篇文章的答案是作为一个相当不愉快的惊喜。但我认为部署开发服务器不会那么麻烦,因为毕竟 VM 是标准的 Docker 映像。
好吧,确实有一些问题阻止了直接部署的工作。我在下面提供了这些问题的摘要以及我如何解决这些问题。我可能错过了Docker和App Engine环境之间的一些不兼容性(尤其是我的项目没有使用的App Engine的许多方面(,但希望这足以让人们启动并运行。
麻烦的来源
首先,我发现在计算引擎虚拟机中运行的 python 环境是一个比普通的 VM 环境更宽松一些(例如,像 webapp2
这样的软件包始终可用(。因此,部署到不太宽容的Docker上容器环境在我的项目中发现了一些潜在的错误。
话虽如此,环境存在一些差异即使您的项目完美无缺,也需要进行一些调整:
-
问题:枪角兽(或您选择的服务器(必须安装在码头工人容器的路径。
- 虽然这看起来很明显,但我遇到了麻烦,因为我包括
gunicorn
在我的项目的requirements.txt
文件中。不幸的是,我是使用只能安装 source 的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 ,请告诉我比我(我觉得我已经把标准定得很低(。