Java 运行时环境

Java 运行时是负责安装网络服务代码及其依赖项并运行服务的软件堆栈。

app.yaml 文件中声明 App Engine 标准环境的 Java 运行时。例如:

runtime: javaVERSION

其中,VERSION 是 Java MAJOR 版本号。例如,Java 21 使用 21

如需了解其他受支持的 Java 版本以及 Java 版本对应的 Ubuntu 版本,请参阅运行时支持时间表

须知事项

  1. 下载最新版本的 Google Cloud CLI 或者将 gcloud CLI 更新至当前版本:

    gcloud components update
    
  2. 如需使用 Maven 进行部署,您需要将 App Engine Maven 插件添加到 pom.xml 文件中,如下所示:

    <plugin>
       <groupId>com.google.cloud.tools</groupId>
       <artifactId>appengine-maven-plugin</artifactId>
       <version>2.7.0</version>
    </plugin>

    您还可以使用 gcloud app deploy 命令或 App Engine Gradle 插件等其他部署选项。

  3. 按照针对应用框架的说明配置可执行 JAR 文件的构建。

框架兼容性

借助 App Engine Java 运行时,您可以部署可执行的 JAR 文件。运行时不包含任何 Web 服务框架,这意味着您并非只能使用基于 servlet 的框架或库。使用原生依赖项或网络堆栈,例如 Netty 库

Google Cloud GitHub 代码库中有一些使用常见 Java Web 框架的 hello world 示例:

您无需局限于这些框架,我们建议您尝试使用您喜欢的框架,如 Grails、Blade、Play!、Vaadin 或 jHipster

将 Maven 源项目部署到 Java 运行时

您可以将 Maven 项目作为源代码进行部署,并使用 Google Cloud 的 Buildpack 构建和部署该项目。

如需将 Maven 项目作为源代码进行部署,请转到项目的顶级目录并输入以下内容:

gcloud app deploy pom.xml

系统将流式传输构建和部署日志,您可以在 Cloud 控制台的 Cloud Build 历史记录部分查看详细日志。

使用 GraalVM 可执行文件

App Engine 标准环境 Java 运行时支持 GraalVM 原生映像可执行文件。将 Java 应用编译为 GraalVM 原生映像后,您便可以使用 app.yaml 文件中的 entrypoint 设置指向可执行文件。

例如,文件名为 myexecutable 的可执行文件可能包含以下 app.yaml 配置文件:

runtime: java17 # or another supported runtime
entrypoint: ./myexecutable

您可以使用 Google Cloud 客户端库将应用编译为 GraalVM 原生映像。如需了解详情,请参阅有关如何编译原生映像的文档。

Java 版本

Java 运行时使用 app.yaml 文件中指定的版本的最新稳定版本。App Engine 会自动更新到新的补丁发布版本,但不会自动更新次要版本。

例如,您的应用可能部署在 Java 11.0.4 上,在之后的托管式平台部署中,该应用会自动更新到 Java 11.0.5 版本,但不会自动更新到 Java 12。

如需了解如何升级 Java 版本,请参阅升级现有应用

运行时的 Open JDK 环境

App Engine 在容器中运行 Java 应用,并由 gVisor 通过最新的 Ubuntu Linux 发行版及其支持的 openjdk-11-jdk(对于 Java 11 运行时)或 openjdk-17-jdk(对于 Java 17 运行时)保护。

如需查看 Java 版本支持的 Ubuntu 版本,请参阅运行时支持时间表

App Engine 会维护基础映像并更新 OpenJDK 11 和 OpenJDK 17 软件包,而无需您重新部署应用。

您部署的应用位于运行时的 /workspace 目录中。它也可以通过 /srv 中的符号链接进行访问。

App Engine Java 版本

以版本 2.x.x 开头的所有已发布工件都使用开源发布机制。以版本 1.9.9xx 或更早版本开头的已发布工件使用内部构建系统。如需了解详情,请参阅 GitHub 代码库

依赖项

如需详细了解如何声明和管理依赖项,请参阅指定依赖项

应用启动

默认情况下,框架(如 Spring Boot、Micronaut、Ktor 等)会构建可执行的超级 JAR。如果您的 Maven 或 Gradle 构建文件会生成可执行的超级 JAR,则运行时通过运行超级 JAR 应用来启动应用。

或者,App Engine 将使用 app.yaml 文件中可选 entrypoint 字段的内容。例如:

runtime: java21 # or another supported runtime
entrypoint: java -Xmx64m -jar YOUR-ARTIFACT.jar

其中,示例 YOUR-ARTIFACT.jar 应用 jar 必须:

  • 存放在 app.yaml 文件的根目录中。
  • 在相应 META-INF/MANIFEST.MF 元数据文件中包含 Main-Class 条目。
  • (可选)包含一个 Class-Path 条目以及一系列相对于其他相关 jar 的路径。这些内容将自动随应用一起上传。

为了让您的应用接收 HTTP 请求,您的入口点应启动一个 Web 服务器来监听 PORT 环境变量指定的端口。PORT 环境变量的值由 App Engine 服务环境动态设置。无法在 app.yaml 文件的 env_variables 部分中设置此值。

借助自定义入口点,您可以构建应用并将其打包为仅包含应用代码和直接依赖项的精简 JAR 文件。部署应用时,App Engine 插件将仅上传已更改的文件,而不是整个超级 JAR 软件包。

请务必使用 PORT 环境变量

如果您在应用日志文件中看到有关端口 8080 和 NGINX 的警告,则表示您应用的网络服务器正在监听默认端口 8080。这样可以防止 App Engine 使用其 NGINX 层来压缩 HTTP 响应。我们建议您在 PORT 环境变量指定的端口(通常为 8081)上配置您的网络服务器,以响应 HTTP 请求。例如:

/*
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.appengine;

import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

public class Main {

  public static void main(String[] args) throws IOException {
    // Create an instance of HttpServer bound to port defined by the
    // PORT environment variable when present, otherwise on 8080.
    int port = Integer.parseInt(System.getenv().getOrDefault("PORT", "8080"));
    HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);

    // Set root URI path.
    server.createContext("/", (var t) -> {
      byte[] response = "Hello World!".getBytes();
      t.sendResponseHeaders(200, response.length);
      try (OutputStream os = t.getResponseBody()) {
        os.write(response);
      }
    });

    // Create a second URI path.
    server.createContext("/foo", (var t) -> {
      byte[] response = "Foo!".getBytes();
      t.sendResponseHeaders(200, response.length);
      try (OutputStream os = t.getResponseBody()) {
        os.write(response);
      }
    });

    server.start();
  }
}

与以前的 Java 版本的兼容性

如需了解 Java 8 和最新支持的 Java 版本之间的区别,请参阅 Java 8 和 Java 11+ 运行时之间的主要区别

环境变量

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

环境变量 说明
GAE_APPLICATION App Engine 应用的 ID。此 ID 以“region code~”为前缀,例如“e~”(对于在欧洲部署的应用)。
GAE_DEPLOYMENT_ID 当前部署的 ID。
GAE_ENV App Engine 环境。设置为 standard
GAE_INSTANCE 当前运行您的服务的实例的 ID。
GAE_MEMORY_MB 可供应用进程使用的内存量,以 MB 为单位。
GAE_RUNTIME app.yaml 文件中指定的运行时环境。
GAE_SERVICE app.yaml 文件中指定的服务名称。如果未指定服务名称,则将其设置为 default
GAE_VERSION 服务的当前版本标签。
GOOGLE_CLOUD_PROJECT 与您的应用关联的 Google Cloud 项目 ID。
PORT 接收 HTTP 请求的端口。
NODE_ENV(仅在 Node.js 运行时中可用) 当服务已部署时,将其设置为 production

您可以app.yaml 文件中定义其他环境变量,但不能替换上述值(NODE_ENV 除外)。

HTTPS 和转发代理

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

文件系统访问

运行时包括可写的 /tmp 目录,其他所有目录仅具有只读访问权限。对 /tmp 执行写入操作会占用系统内存。

元数据服务器

应用的每个实例都可以使用 App Engine 元数据服务器来查询有关实例和项目的信息。

您可以通过以下端点访问元数据服务器:

  • http://metadata
  • http://metadata.google.internal

发送到元数据服务器的请求必须包含请求标头 Metadata-Flavor: Google。此标头表明请求是为了检索元数据值而发出的。

下表列出了您可以针对特定元数据发出 HTTP 请求的端点:

元数据端点 说明
/computeMetadata/v1/project/numeric-project-id 分配给项目的项目编号。
/computeMetadata/v1/project/project-id 分配给项目的项目 ID。
/computeMetadata/v1/instance/region 实例运行的区域。
/computeMetadata/v1/instance/service-accounts/default/aliases
/computeMetadata/v1/instance/service-accounts/default/email 分配给项目的默认服务账号电子邮件地址。
/computeMetadata/v1/instance/service-accounts/default/ 列出项目的所有默认服务账号。
/computeMetadata/v1/instance/service-accounts/default/scopes 列出默认服务账号的所有受支持范围。
/computeMetadata/v1/instance/service-accounts/default/token 返回可用于向其他 Google Cloud API 验证您的应用的身份验证令牌。

例如,要检索您的项目 ID,请向 http://metadata.google.internal/computeMetadata/v1/project/project-id 发送请求。