Java 11 ランタイム環境

Java 11 ランタイムは、ウェブサービスのコードとその依存関係をインストールしてサービスを実行する役割を果たすソフトウェア スタックです。

App Engine スタンダード環境用の Java 11 ランタイムは app.yaml ファイル内で次のように宣言されています。

runtime: java11

始める前に

  1. Cloud SDK の最新バージョンをダウンロードするか、Cloud SDK を現在のバージョンに更新します。

    gcloud components update
    
  2. Maven を使用してデプロイするには、App Engine Maven プラグインpom.xml ファイルに追加する必要があります。

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

    デプロイには、gcloud app deploy コマンドや App Engine Gradle プラグインの使用などの他のオプションがあります。

  3. アプリケーション フレームワークの手順に従って、実行可能 JAR ファイルのビルドを構成します。

フレームワークの互換性

App Engine Java 11 ランタイムでは、実行可能な JAR ファイルをデプロイできます。ランタイムには、ウェブサービス フレームワークは含まれません。つまり、サーブレット ベースのフレームワークやライブラリの使用に制限されません。ネイティブの依存関係またはネットワーク スタック(Netty ライブラリなど)を使用します。

Google Cloud GitHub リポジトリには、一般的な Java ウェブ フレームワークを使用した hello world サンプルがあります。

これらのフレームワークに限定されるものではありません。お好みのフレームワーク(Grails、Blade、Play、Vaadin、jHipster など)をお試しください。

Maven ソース プロジェクトを Java 11 ランタイムにデプロイする

Maven プロジェクトをソースコードとしてデプロイできます。ビルドしてデプロイするには、App Engine Buildpacks を使用します。

Maven プロジェクトをソースコードとしてデプロイするには、プロジェクトの最上位ディレクトリに移動し、次のように入力します。

gcloud app deploy pom.xml

ビルドとデプロイのログがストリーミングされます。詳細なログは Cloud Console の Cloud Build の履歴のセクションで確認できます。

GraalVM 実行可能ファイルの使用

App Engine スタンダード環境用の Java 11 ランタイムは、GraalVM ネイティブ イメージ実行可能ファイルをサポートしています。GraalVM ネイティブ イメージを使用して Java 11 アプリをコンパイルしたら、app.yaml ファイルentrypoint 設定を使用して実行可能ファイルを指定できます。

たとえば、ファイル名が myexecutable の実行可能ファイルには、次の app.yaml 構成ファイルがあります。

runtime: java11
entrypoint: ./myexecutable

Java のバージョン

Java 11 ランタイム環境では、最新の安定版 Java 11 が使用されています。App Engine では、マイナー バージョンは新しいものに自動で更新されますが、メジャー バージョンの更新は自動的には行われません。

たとえば、アプリケーションが Java 11.0.4 でデプロイされ、その後のマネージドプラットフォームのデプロイ時にバージョン Java 11.0.5 に自動的に更新されることはあっても、Java 12 には自動更新されません。

ランタイムの Open JDK 環境

App Engine は、gVisor によって保護されたコンテナにおいて、最新の Ubuntu 18.04 Linux ディストリビューションとサポート対象の openjdk-11-jdk パッケージで Java 11 アプリを実行します。App Engine ではベースイメージが維持され、OpenJDK 11 パッケージが更新されます。その際、アプリを再デプロイする必要はありません。

デプロイされたアプリは、ランタイムの /workspace ディレクトリにあります。/srv のシンボリック リンクからもアクセスできます。

依存関係

依存関係の宣言と管理については、依存関係の指定をご覧ください。

アプリケーションの起動

Spring Boot、Micronaut、Ktor などのフレームワークは、デフォルトで実行可能な uber JAR をビルドします。Maven または Gradle ビルドファイルが実行可能な Uber JAR をビルドする場合、ランタイムは Uber JAR アプリケーションを実行してアプリケーションを起動します。

または、App Engine は app.yaml ファイルのオプションの entrypoint フィールドの内容を使用します。例:

runtime: java11
entrypoint: java -Xmx64m -jar YOUR-ARTIFACT.jar

例に示す YOUR-ARTIFACT.jar アプリケーション jar は次の要件を満たす必要があります。

  • ルート ディレクトリ内に app.yaml ファイルとともに存在する。
  • META-INF/MANIFEST.MF メタデータ ファイルに Main-Class エントリが含まれている。
  • 必要に応じて、他の依存 jar への相対パスのリストを格納する Class-Path エントリを含んでいる。これらはアプリケーションとともに自動的にアップロードされます。

アプリで HTTP リクエストを受信するには、PORT 環境変数で指定されたポートをリッスンするウェブサーバーをエントリポイントで起動する必要があります。

カスタム エントリポイントによって、アプリケーション コードと直接の依存関係のみを含む thin JAR ファイルとしてアプリケーションを構築しパッケージ化できます。アプリケーションをデプロイする際は、App Engine プラグインは uber 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 から次の機能にアクセスできます。

  • var キーワードによる高度なタイプの推論。
  • 不変のコレクションを使用してリストやマップを簡単に作成します。
  • 移行した HttpClient を使用してリモートホストを呼び出します。
  • JPMS モジュール システムを使用します。
  • Apache GroovyKotlinScala などの代替的な JVM 言語を使用します。

環境変数

ランタイムは以下の環境変数を設定します。

環境変数 説明
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 ヘッダーで確認できます。この情報が必要なアプリケーションでは、プロキシを信頼するようにウェブ フレームワークを構成してください。

ファイル システムへのアクセス

ランタイムは書き込み可能な /tmp ディレクトリを持ち、それ以外のディレクトリはすべて読み取り専用です。/tmp に書き込むとシステムメモリが消費されます。

メタデータ サーバー

アプリケーションの各インスタンスは、App Engine メタデータ サーバーを使用してインスタンスとプロジェクトに関する情報を照会できます。

次のエンドポイントを介してメタデータ サーバーにアクセスできます。

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

次の表に、特定のメタデータを取得するための 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 APIs に認証させるための認証トークンを返します。

たとえば、プロジェクト ID を取得するには、リクエストを http://metadata.google.internal/computeMetadata/v1/project/project-id に送信します。