Java 17 现已推出预览版。

Java 11/17 运行时环境

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

如需为 App Engine 标准环境指定 Java 11/17(预览版),请在 app.yaml 文件中声明该运行时。例如:

Java 17(预览版)

runtime: java17

Java 11

runtime: java11

准备工作

  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.4.0</version>
    </plugin>

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

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

框架兼容性

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

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

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

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

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

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

gcloud app deploy pom.xml

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

使用 GraalVM 可执行文件

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

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

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

Java 版本

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

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

运行时的 Open JDK 环境

App Engine 在容器中运行 Java 11/17 应用,并由 gVisor 通过最新的 Ubuntu 18.04 Linux 发行版及其支持的 Java 11 版 openjdk-11-jdk 或 Java 17 版 openjdk-17-jdk 运行时软件包保护。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: java17 # 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 11/17 运行时之间的差异,请参阅 Java 8 和 Java 11/17 运行时之间的主要区别

环境变量

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

环境变量 说明
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 与您的应用关联的 Cloud 项目 ID。
PORT 接收 HTTP 请求的端口。

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

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/zone 实例运行的区域。
/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 发送请求。