Node.js 运行时

Node.js 运行时是负责安装应用代码和依赖项,然后在柔性环境中运行该应用的软件栈。

  • 18 版及更高版本是使用 buildpack 构建的,后者要求您在 app.yaml 文件中选择操作系统。例如,要使用 Node.js 20,您必须将 Ubuntu 22 指定为操作系统。

  • 16 及更低版本使用 Docker 构建。

  • 默认的 Node.js 引擎使用最新的 LTS 版本

如需查看支持的 Node.js 版本及其相应 Ubuntu 版本的完整列表,请参阅运行时支持时间表

软件包管理器

在部署期间,运行时使用 npmyarnPnpm 软件包管理器来安装依赖项并启动应用。软件包管理器是使用以下逻辑进行设置的:

  • 默认软件包管理器为 npm
  • 如果应用的根目录中存在 yarn.lock 文件,运行时会改为使用 yarn 软件包管理器。
  • 仅对于 Node.js 运行时版本 18 和版本 20,如果应用根目录中存在 pnpm-lock.yaml 文件,则运行时会改用 Pnpm 软件包管理器。
  • 如果 package-lock.jsonyarn.lockpnpm-lock.yaml 都存在,则部署将失败并报错。如果您需要 package-lock.json 文件,则必须在 app.yaml 文件的 skip_files 部分中指定其他软件包管理器文件,以解析要使用哪个软件包管理器。

选择 Node.js 版本

新运行时版本

对于 Node.js 运行时版本 18 及更高版本,您必须在 app.yaml 文件中添加 runtime_configoperating_system 设置以指定操作系统。

如需使用新版运行时,您必须安装 gcloud CLI 420.0.0 版或更高版本。 您可以通过运行 gcloud components update 命令来更新 CLI 工具。如需查看已安装的版本,您可以运行 gcloud version 命令。

(可选)通过以下方式指定版本:

  • app.yaml 文件中添加 runtime_version 设置。默认情况下,如果未指定 runtime_version 设置,则使用最新的 Node.js 版本。 例如,

    • 如需在 Ubuntu 22 上指定 Node.js 20,请运行以下命令:
      runtime: nodejs
      env: flex
    
      runtime_config:
          operating_system: "ubuntu22"
          runtime_version: "20"
    
    • 如需在 Ubuntu 22 上指定受支持的最新 Node.js 版本,请运行以下命令:
      runtime: nodejs
      env: flex
    
      runtime_config:
          operating_system: "ubuntu22"
    
  • 使用 engines 字段在应用的 package.json 文件中添加任何 Node.js 版本。请注意,如果您同时使用 engines 字段指定了版本,runtime_version 设置优先。为防止出现意外中断,建议您在 engines 字段中指定 Node.js 版本。例如

      {
        "engines": {
          "node": "20.x"
        }
      }
    

    engines.node 属性可以是 semver 范围。如果您指定此属性,则运行时会下载并安装与 semver 范围匹配的最新版 Node.js。如果找不到匹配项,则应用将无法部署,并且运行时将返回错误消息。

过往运行时版本

对于 Node.js 运行时 16 及更早版本,请在应用的 package.json 文件中使用 engines 字段指定版本。

以下示例将运行时配置为使用最新的 Node 9 版本。

{
  "engines": {
    "node": "9.x"
  }
}

engines.node 属性可以是 semver 范围。如果您指定此属性,则运行时会下载并安装与 semver 范围匹配的最新版 Node.js。如果找不到匹配项,则应用将无法部署,并且运行时将返回错误消息。

软件包管理器版本

运行时映像旨在使用 最新的 Node.js LTS 版本中提供的最新 yarn 版本和 npm 版本。

您可以使用 engines 字段指定要在应用的 package.json 文件中使用的其他软件包管理器版本。在这种情况下,运行时将确保用于部署的软件包管理器具有与 engines 字段中列出的规范相匹配的版本。

如果同时指定了 yarnnpm 版本规范,则只会根据需要更新用于部署的软件包管理器。如果实际上未使用软件包管理器来部署应用,则不会安装自定义版本的软件包管理器,这样就节省了部署时间。

以下示例将运行时配置为使用自定义版本的 npm

{
  "engines": {
    "npm": "5.x"
  }
}

下一个示例将运行时配置为使用自定义版本的 yarn

{
  "engines": {
    "yarn": ">=1.0.0 <2.0.0"
  }
}

engines.npmengines.yarn 属性都可以是 semver 范围

依赖项

在部署期间,运行时将使用 npmyarn 软件包管理器,通过运行 npm installyarn install 来安装依赖项。请参阅软件包管理器部分,详细了解运行时如何选择要使用的软件包管理器。

此外,如需详细了解如何在 Google App Engine 上管理 Node.js 软件包,请参阅使用 Node.js 库

为了支持使用需要原生扩展的 Node.js 软件包,Docker 映像中预先安装了以下Ubuntu 软件包

  • build-essential
  • ca-certificates
  • curl
  • git
  • imagemagick
  • libkrb5-dev
  • netbase
  • python

如果您的应用需要其他操作系统级依赖项,您将需要使用基于此运行时的自定义运行时来安装相应的软件包。

NPM 构建脚本

对于 Node.js 运行时版本 18 及更高版本,如果 package.json 中默认检测到 build 脚本,则运行时环境将执行 npm run build。如果您需要在启动应用之前对构建步骤进行额外的控制,则可以通过向 package.json 文件添加 gcp-build 脚本来提供自定义构建步骤

如需阻止构建运行 npm run build 脚本,您必须执行以下操作之一:

  • package.json 文件中添加具有空值的 gcp-build 脚本:"gcp-build":""
  • app.yaml 文件中添加具有空值的 GOOGLE_NODE_RUN_SCRIPTS 构建环境变量。

    build_env_variables:
      GOOGLE_NODE_RUN_SCRIPTS: ''
    
如需详细了解如何指定构建环境变量,请参阅 app.yaml 文件中的 build_env_variables 部分。

应用启动

运行时通过使用 npm start(使用 package.json 中指定的命令)启动应用。例如:

"scripts": {
  "start": "node app.js"
}

您的启动脚本应该启动一个网络服务器以响应 PORT 环境变量所指定的端口(通常为 8080)上的 HTTP 请求。

扩展运行时

您可以使用自定义运行时为 App Engine 柔性环境中运行的 Node.js 应用添加额外功能。如需配置自定义运行时,请将 app.yaml 文件中的以下行:

runtime: nodejs

替换为以下行:

runtime: custom

您还必须在 app.yaml 文件所在的目录中添加 Dockerfile.dockerignore 文件。

请参阅自定义运行时文档,了解如何在自定义运行时中定义 Dockerfile。

HTTPS 和转发代理

App Engine 会在负载均衡器上终止 HTTPS 连接,并将请求转发给您的应用。某些应用需要确定原始请求 IP 和协议。用户的 IP 地址可在标准 X-Forwarded-For 标头中获取。需要此信息的应用要将其网络框架配置为信任代理.

Express.js 框架中,使用 trust proxy 设置:

app.set('trust proxy', true);

要了解如何强制执行 HTTPS 连接,请参阅请求的处理方式

环境变量

以下环境变量由运行时环境设置:

环境变量 说明
GAE_INSTANCE 当前实例的名称。
GAE_MEMORY_MB 可供应用进程使用的内存量。
GAE_SERVICE 在应用的 app.yaml 文件中指定的服务名称,如果未指定服务名称,则设置为 default
GAE_VERSION 当前应用的版本标签。
GOOGLE_CLOUD_PROJECT 与您的应用关联的项目 ID,可在 Google Cloud 控制台中查看
NODE_ENV 部署应用时,该值为 production
PORT 将接收 HTTP 请求的端口。设置为 8080

您可以使用 app.yaml 设置其他环境变量。

元数据服务器

应用的每个实例都可以使用 Compute Engine 元数据服务器来查询有关实例的信息,包括实例的主机名、外部 IP 地址、实例 ID、自定义元数据和服务账号信息。App Engine 不支持为每个实例设置自定义元数据,但您可以设置项目范围的自定义元数据并从 App Engine 和 Compute Engine 实例中读取这些元数据。

此示例函数使用元数据服务器来获取 Node.js 运行时版本 16 及更早版本和版本 18 及更高版本的实例的外部 IP 地址。请注意,您必须更新 app.yaml 才能使用新版本。如需详细了解如何使用较新版本,请参阅 Node.js 运行时

const express = require('express');
const fetch = require('node-fetch');

const app = express();
app.enable('trust proxy');

const METADATA_NETWORK_INTERFACE_URL =
  'http://metadata/computeMetadata/v1/' +
  '/instance/network-interfaces/0/access-configs/0/external-ip';

const getExternalIp = async () => {
  const options = {
    headers: {
      'Metadata-Flavor': 'Google',
    },
    json: true,
  };

  try {
    const response = await fetch(METADATA_NETWORK_INTERFACE_URL, options);
    const ip = await response.json();
    return ip;
  } catch (err) {
    console.log('Error while talking to metadata server, assuming localhost');
    return 'localhost';
  }
};

app.get('/', async (req, res, next) => {
  try {
    const externalIp = await getExternalIp();
    res.status(200).send(`External IP: ${externalIp}`).end();
  } catch (err) {
    next(err);
  }
});

const PORT = parseInt(process.env.PORT) || 8080;
app.listen(PORT, () => {
  console.log(`App listening on port ${PORT}`);
  console.log('Press Ctrl+C to quit.');
});