连接 Google App Engine 上的 Mongoose

7
我已经成功地在Google App Engine上部署了一个自定义的Node.js应用程序。然而,当尝试连接时,mongoose超时导致无法启动该应用程序。令人沮丧的是,使用完全相同的参数在我的本地机器上可以正常连接mongoose。
我的MongoDb URI的格式为:
 mongodb://<dbuser>:<dbpassword>@xxxx.mlab.com:<portNumber>/d‌​b-name

作为URI所示,该数据库由mlab托管。它是Google Cloud Platform上的沙盒实例。但是我没有使用Google Compute Engine部署数据库。当我通过mlab的设置过程时,我只选择在GCP上进行托管。
我在SO上遇到了类似的问题,但其中大多数都没有被接受的答案。只有一些不同的评论,没有被接受的解决方案。
因此,我的问题是,在尝试连接上述URI时,我的App Engine实例和本地计算机之间有什么区别?我选择让mlab在GCP上托管它是否重要?如果我选择让它托管在Amazon AWS上,会有什么不同?问题的根本原因是什么?
供参考,以下是我找到的类似问题:

此外,如果有帮助的话,mongodb被用作业务模型的数据库,是应用程序Express Session的数据存储和socket.io中瞬态数据的存储。

部署后来自应用引擎的错误堆栈跟踪:

2017-10-18 02:13:46 default[20171017t215757]  npm ERR! enoent ENOENT: no such file or directory, open '/app/package.json'
2017-10-18 02:13:46 default[20171017t215757]  npm ERR! enoent ENOENT: no such file or directory, open '/app/package.json'
2017-10-18 02:13:46 default[20171017t215757]  npm ERR! enoent This is most likely not a problem with npm itself
2017-10-18 02:13:46 default[20171017t215757]  npm ERR! enoent and is related to npm not being able to find a file.
2017-10-18 02:13:46 default[20171017t215757]  npm ERR! enoent
2017-10-18 02:13:46 default[20171017t215757]
2017-10-18 02:13:46 default[20171017t215757]  npm ERR! Please include the following file with any support request:
2017-10-18 02:13:46 default[20171017t215757]  npm ERR!     /app/npm-debug.log
2017-10-18 02:23:41 default[20171017t215757]  npm ERR! Linux 3.16.0-4-amd64
2017-10-18 02:23:41 default[20171017t215757]  npm ERR! argv "/nodejs/bin/node" "/nodejs/bin/npm" "start"
2017-10-18 02:23:41 default[20171017t215757]  npm ERR! node v6.11.3
2017-10-18 02:23:41 default[20171017t215757]  npm ERR! npm  v3.10.10
2017-10-18 02:23:41 default[20171017t215757]  npm ERR! path /app/package.json
2017-10-18 02:23:41 default[20171017t215757]  npm ERR! code ENOENT
2017-10-18 02:23:41 default[20171017t215757]  npm ERR! errno -2
2017-10-18 02:23:41 default[20171017t215757]  npm ERR! syscall open

在Google Cloud Shell本地运行应用时的错误堆栈跟踪:

/home/myuser/src/project-id/teammate-express-server/node_modules/mongodb/lib/mongo_client.js:421
          throw err
          ^
MongoError: failed to connect to server [ds147454.mlab.com:47454] on first connect [MongoError: connection 1 to ds147454.mlab.com:47454 timed out]
    at Pool.<anonymous> (/home/myuser/src/project-id/teammate-express-server/node_modules/mongodb-core/lib/topologies/server.js:336:35)
    at emitOne (events.js:96:13)
    at Pool.emit (events.js:188:7)
    at Connection.<anonymous> (/home/myuser/src/project-id/teammate-express-server/node_modules/mongodb-core/lib/connection/pool.js:280:12)
    at Connection.g (events.js:292:16)
    at emitTwo (events.js:106:13)
    at Connection.emit (events.js:191:7)
    at Socket.<anonymous> (/home/myuser/src/project-id/teammate-express-server/node_modules/mongodb-core/lib/connection/connection.js:197:10)
    at Socket.g (events.js:292:16)
    at emitNone (events.js:86:13)
    at Socket.emit (events.js:185:7)
    at Socket._onTimeout (net.js:338:8)
    at ontimeout (timers.js:386:14)
    at tryOnTimeout (timers.js:250:5)
    at Timer.listOnTimeout (timers.js:214:5)

它实际上是托管在GCP上吗?这意味着您可以登录Google Cloud Platform控制台,在GCE实例下查找为其提供的VM服务器?如果是这样,它关联了哪些防火墙规则? - BrettJ
@BrettJ 我认为是这样的,mlab也这么说。但是实例是由mlab部署和管理的,因此不在我的GCP控制台下。我在我的笔记本电脑和DigitalOcean Droplet上运行了我的项目,它们都可以正常连接到数据库。只有App Engine拒绝连接,因此我只能假设问题源于某些App Engine配置。 - Tunji_D
2
你有没有按照 https://cloud.google.com/nodejs/getting-started/deploy-mongodb 的文档进行操作? - BrettJ
1
@BrettJ 那很有可能就是了!我有一个配置的json文件,但我的文件名叫serverConfig.json,并且键映射是不同的。在遵循教程时,我认为这是最佳实践的事情,所以我更改了键和文件名,以更好地描述我的设置。我不知道App Engine也依赖于该文件进行内部设置。我会编辑我的配置文件,以完全匹配教程,然后再试一次。 - Tunji_D
@BrettJ 快速问题,示例中的配置json指定了MONGO_COLLECTION。我的应用程序使用多个集合。我是否需要传递所有集合的json数组?我可以忽略此字段吗? - Tunji_D
虽然没有明确说明,但您现在应该能够使用任何虚拟值。 - Tarun Lalwani
3个回答

6
正如已经指出的那样,您可以按照 https://cloud.google.com/community/tutorials/nodejs-mongodb-on-appengine 上的说明使用 config.json 文件配置 Google App Engine。(更新:链接已失效,请尝试:https://cloud.google.com/community/tutorials/nodejs-mongodb-on-appengine
由于您正在使用 mongoose,因此模型将决定集合使用方式。例如:save()、update()。 如果您直接使用 node.js 进行连接,还可以轻松更改代码中的数据库/集合。

在尝试连接上述 URI 时,我的 App Engine 实例和本地计算机之间有何区别?

Google App Engine 是一个全托管的平台,它可以理解为是一个无服务器平台,您利用一个工作池来上下扩展应用程序。当请求进入您的应用程序时,工作池中的一个实例将处理任务/请求。
与本地计算机不同,请求也会由您的计算机处理。
您还可能发现Google App Engine FAQ很有用。

我选择使用 mlab 在 GCP 上托管的事实是否很重要?

不是很重要。如您所提到的,您目前正在使用 GCP 的沙盒(免费)计划。此时,这将在 us-central1 地区部署您的 MongoDB 实例,并且没有其他地区可供选择。不同云提供商之间的 RAM/存储容量/价格也略有不同。
您还可以通过选择位于 us-central1 地区的 GAE 来减少网络延迟。

问题的根本原因是什么?

如果没有适当的堆栈跟踪或错误日志来描述超时问题,则很难确定问题的确切原因。
通常,node.js 项目包含一个名为 config.js 的 JavaScript 文件,在其中有以下一行:
  nconf.argv()
       .env()
       .file({ file: path.join(__dirname, 'config.json') })
       .defaults()

该功能基本上是按以下顺序读取配置:

  • 命令行参数
  • 环境变量
  • 配置文件(指定路径)
  • 默认值

另请参见Google Cloud Platform: nodejs-getting-started

还可以参考GoogleCloudPlatform/nodejs-docs-samples/appengine/mongodb项目的示例。


你好万,感谢你提供非常详细的回复。你知道App Engine是否在内部依赖config.js文件和nconf吗?我有一个config.json文件,用它来读取我的环境变量而不使用nconf。如果App Engine不知道某些uri,会阻止连接吗?我一遍又一遍地阅读教程,似乎没有做错任何事情。我甚至尝试直接使用mongo客户端运行一个简单的helloworld节点服务器,但仍然超时。 - Tunji_D
2
嗨,不是在内部。这应该在你的node.js代码中完成。例如,参见server.js:L25,这是一个node.js示例文件,它从不同的JSON文件配置中读取。如果你仍然在GAE连接方面遇到问题,请发布你的代码和任何错误堆栈信息。 - Wan B.
3
尽管 OP 的问题与此不同,但这个回答非常详尽和深思熟虑,值得获得悬赏奖励。感谢您的帮助! - AdamMc331
这个答案中的链接无法使用。我找到了一个可能的替代方案:https://cloud.google.com/community/tutorials/nodejs-mongodb-on-appengine不幸的是,只能在灵活环境下使用... - pablo-az

3

这个问题花费了我太长时间,但是问题出在我的Dockerfile上。

我正在扩展node.js运行时,但我的Dockerfile缺少复制应用程序目录和安装npm的行。

为了创建适当的Dockerfile,我使用了以下命令:

gcloud beta app gen-config --custom

关于命令和扩展node.js运行时的更多信息,请点击这里

在我添加所需的依赖项后,我的最终Dockerfile如下:

注意:仅在部署后才能连接到MongoDb实例。在Cloud Shell中本地运行仍会超时。

# Dockerfile extending the generic Node image with application files for a
# single application.
FROM gcr.io/google_appengine/nodejs
COPY . /app/

RUN apt-get -y update && apt-get install -y libav-tools && apt-get install -y graphicsmagick

# You have to specify "--unsafe-perm" with npm install
# when running as root.  Failing to do this can cause
# install to appear to succeed even if a preinstall
# script fails, and may have other adverse consequences
# as well.
# This command will also cat the npm-debug.log file after the
# build, if it exists.
RUN npm install --unsafe-perm || \
  ((if [ -f npm-debug.log ]; then \
      cat npm-debug.log; \
    fi) && false)
CMD npm start

你在Google App Engine上成功运行了Mongoose吗?根据他们的文档,似乎需要使用Google Compute Engine(GCE)。你认为呢? - Ronnie Royston
@RonRoyston 我试过了,它的效果非常好。我可能还需要使用Compute Engine因为App Engine不支持Websockets。 - Tunji_D

0
我曾经遇到过同样的问题,但最终这个方法对我有用。希望它能帮到你。当我使用nconf包从json文件中读取数据库连接详细信息时,如Google所述https://cloud.google.com/community/tutorials/nodejs-mongodb-on-appengine,没有使用mongoose,我就能够解决它。最初我是从环境变量中读取的。
`         nconf = require('nconf');
          const mongoose = require('mongoose');
          //key.json contains mongodb connection information
          nconf.argv().env().file('keys.json');
          const user = nconf.get('mongoUser');
          const pass = nconf.get('mongoPass');
          const host = nconf.get('mongoHost');
          const port = nconf.get('mongoPort')
          const mongoDatabase=nconf.get('mongoDatabase');
          let mongo_url=`mongodb://${user}:${pass}@${host}:${port}/${mongoDatabase}`;
          mongoose.connect(mongo_url,{useNewUrlParser: true});`

您不必像其他答案建议的那样使用config.json文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接