Docker を使用した Google App Engine Java アプリから Cloud Run への移行

1. 概要

この一連の Codelab(セルフペース型のハンズオン チュートリアル)は、Google App Engine(スタンダード)Java デベロッパーが一連の移行手順をご案内し、アプリをモダナイズできるようにすることを目的としています。以下の手順に沿って、アプリのポータビリティを高め、Cloud Run(App Engine に対する Google Cloud のコンテナ ホスティング シスター サービス、その他のコンテナ ホスティング サービス)用にコンテナ化することを決定できます。

このチュートリアルでは、Dockerfile を使用して App Engine アプリをコンテナ化し、Cloud Run フルマネージド サービスにデプロイする方法について説明します。Dockerfile は、この移行に最も実践的デプロイ方法ですが、ビルドプロセスをカスタマイズするためのオプションも多数用意されています。

App Engine から Cloud Run に移行するために必要な手順に加えて、Java 8 App Engine アプリを Java 17 にアップグレードする方法も学習します。

移行対象のアプリケーションで App Engine の以前のバンドル サービスやその他の App Engine 固有の機能を多用している場合は、この Codelab よりも出発点として Java 11/17 用の App Engine バンドル サービスへのアクセス ガイドをご覧ください。

GCP コンソールの

  • Cloud Shell を使用する
  • Cloud Run、Artifact Registry、Cloud Build API を有効にする
  • Docker、Docker、Cloud Build を使用してアプリをコンテナ化する
  • コンテナ イメージを Cloud Run にデプロイする

必要なもの

アンケート

このチュートリアルをどのように使用されますか?

通読するのみ 通読し、演習を行う

Java の使用経験をどのように評価されますか。

初心者 中級者 上級者

Google Cloud サービスの使用経験はどの程度ありますか?

<ph type="x-smartling-placeholder"></ph> 初心者 中級 上達

2. 背景情報

App Engine や Cloud Functions などの PaaS システムは、SysAdmin や DevOps がソリューションの構築に集中できるなど、チームとアプリケーションに多くの利便性を提供します。サーバーレスなプラットフォームにより、アプリは必要に応じて自動スケーリングでき、従量課金制でゼロにスケールダウンして費用を管理できるほか、さまざまな一般的な開発言語を使用できます。

その一方で、コンテナの柔軟性も魅力的です。コンテナでは、任意の言語、ライブラリ、バイナリを選択できるため、サーバーレスの利便性とコンテナの柔軟性という両方の長所を活用できます。これこそが Google Cloud Run の特長です。

Cloud Run の使用方法は、この Codelab の対象外です。Cloud Run のドキュメントをご覧ください。ここでの目標は、Cloud Run(または他のコンテナホスト型サービス)向けに App Engine アプリをコンテナ化する方法を理解することです。先に進む前に、いくつか知っておくべきことがあります。主に、ユーザー エクスペリエンスが多少変わるということです。

この Codelab では、コンテナをビルドしてデプロイする方法を学びます。ここでは、Dockerfile を使用してアプリをコンテナ化する方法、App Engine 構成から移行する方法、Cloud Build のビルドステップを定義する方法を学びます。これには、特定の App Engine 固有の機能からの移行が含まれます。この方法を使用しない場合は、App Engine にアプリを保持したまま Java 11/17 ランタイムにアップグレードできます。

3. 設定/事前作業

1. プロジェクトをセットアップする

このチュートリアルでは、新規プロジェクトappengine-java-migration-samples リポジトリにあるサンプルアプリを使用します。プロジェクトに有効な請求先アカウントがあることを確認します。

既存の App Engine アプリを Cloud Run に移行する場合は、代わりにそのアプリを使用できます。

次のコマンドを実行して、プロジェクトに必要な API を有効にします。

gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com

2. ベースラインのサンプルアプリを取得する

自分のマシンまたは Cloud Shell でサンプルアプリのクローンを作成し、baseline フォルダに移動します。

このサンプルは、App Engine へのデプロイを想定した Java 8 のサーブレット ベースの Datastore アプリです。README に記載されている手順に沿って、このアプリを App Engine のデプロイ用に準備します。

3. (省略可)ベースライン アプリをデプロイする

以下の手順は、Cloud Run に移行する前にアプリが App Engine で動作することを確認する場合にのみ必要です。

README.md の手順を参照してください。

  1. gcloud CLI をインストールする/再度確認する
  2. gcloud init を使用してプロジェクトの gcloud CLI を初期化する
  3. gcloud app create で App Engine プロジェクトを作成する
  4. サンプルアプリを App Engine にデプロイする
./mvnw package appengine:deploy -Dapp.projectId=$PROJECT_ID
  1. アプリが App Engine で問題なく動作することを確認する

4. Artifact Registry リポジトリを作成する

アプリをコンテナ化した後は、イメージを push して保存する場所が必要になります。Google Cloud でこれを実現するには、Artifact Registry を使用することをおすすめします。

次のように gcloud を使用して、migration という名前のリポジトリを作成します。

gcloud artifacts repositories create migration --repository-format=docker \
--description="Docker repository for the migrated app" \
--location="northamerica-northeast1"

このリポジトリは docker 形式タイプを使用しますが、利用可能な複数のリポジトリ タイプがあります。

この時点で、ベースラインとなる App Engine アプリが用意され、Google Cloud プロジェクトで Cloud Run に移行する準備が整いました。

4. アプリケーション ファイルの変更

アプリで以前の App Engine のバンドル サービス、構成、その他の App Engine 専用機能を多用している場合は、新しいランタイムにアップグレードする際に、それらのサービスへのアクセスを継続することをおすすめします。この Codelab では、すでにスタンドアロン サービスを使用している、または可能なようにリファクタリングできるアプリケーションの移行パスについて説明します。

1. Java 17 へのアップグレード

アプリが Java 8 で実行されている場合は、セキュリティ アップデートに対応し、新しい言語機能を利用できるようにするため、11 や 17 などの新しい LTS 候補にアップグレードすることを検討してください。

まず、pom.xml のプロパティを更新して以下を含めます。

<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
</properties>

これにより、プロジェクトのバージョンが 17 に設定され、Java 17 言語機能にアクセスしたいこと、コンパイル済みクラスに Java 17 JVM と互換性があることがコンパイラ プラグインに通知されます。

2. ウェブサーバーを含める

App Engine と Cloud Run との間を移動する場合は、考慮すべき点が多数あります。1 つ異なる点として、App Engine の Java 8 ランタイムでは、ホストするアプリ用に Jetty サーバーが提供され、管理されますが、Cloud Run はそうではありません。Spring Boot を使用して、ウェブサーバーとサーブレット コンテナを提供します。

次の依存関係を追加します。

<dependencies>
<!-- ... -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
       <version>2.6.6</version>
       <exclusions>
           <!-- Exclude the Tomcat dependency -->
           <exclusion>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-tomcat</artifactId>
           </exclusion>
       </exclusions>
   </dependency>
   <!-- Use Jetty instead -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-jetty</artifactId>
       <version>2.6.6</version>
   </dependency>
<!-- ... -->
</dependencies>

Spring Boot にはデフォルトで Tomcat サーバーが埋め込まれますが、このサンプルでは、そのアーティファクトを除外し、移行後のデフォルトの動作の違いを最小限に抑えるために Jetty のみを使用します。

3. Spring Boot のセットアップ

Spring Boot はサーブレットを変更せずに再利用できますが、サーブレットを検出可能にするためにいくつかの構成が必要になります。

com.example.appengine パッケージに次の MigratedServletApplication.java クラスを作成します。

package com.example.appengine;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
@EnableAutoConfiguration
public class MigratedServletApplication {
    public static void main(String[] args) {
        SpringApplication.run(MigratedServletApplication.class, args);
    }
}

これには @ServletComponentScan アノテーションが含まれます。このアノテーションは、(デフォルトでは現在のパッケージ内で)任意の @WebServlets を検索し、期待どおりに利用できるようにします。

4. アプリを JAR としてパッケージ化する

アプリを war の状態からコンテナ化することは可能ですが、実行可能な JAR としてアプリをパッケージ化すると簡単になります。特に Maven をビルドツールとして使用するプロジェクトでは、jar パッケージ化がデフォルトの動作であるため、多くの構成は必要ありません。

pom.xml ファイルの packaging タグを削除します。

<packaging>war</packaging>

次に、spring-boot-maven-plugin を追加します。

<plugins>
<!-- ... -->
  <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.6.6</version>
  </plugin>
<!-- ... -->
</plugins>

5. App Engine の構成、サービス、依存関係からの移行

Codelab の冒頭で説明したように、Cloud Run と App Engine はそれぞれ異なるユーザー エクスペリエンスを提供できるように設計されています。App Engine に標準装備の一部の機能(cronTask Queue サービスなど)は手動で再作成する必要があります。これらの機能については、後のモジュールで詳しく説明します。

このサンプルアプリでは、以前のバンドル サービスを使用しませんが、使用するアプリを使用しているユーザーは、次のガイドを参照してください。

今後は Cloud Run にデプロイするため、appengine-maven-plugin を削除できます。

<plugin>
 <groupId>com.google.cloud.tools</groupId>
 <artifactId>appengine-maven-plugin</artifactId>
 <version>2.4.1</version>
 <configuration>
   <!-- can be set w/ -DprojectId=myProjectId on command line -->
   <projectId>${app.projectId}</projectId>
   <!-- set the GAE version or use "GCLOUD_CONFIG" for an autogenerated GAE version -->
   <version>GCLOUD_CONFIG</version>
 </configuration>
</plugin>

5. アプリケーションをコンテナ化する

これで、アプリケーションのコンテナを実際にビルドする方法を Cloud Build に伝える準備が整いました。このコンテナ化方法では、個別のビルド構成ファイル(cloudbuild.yaml)は必要ありません。出発点として最小限の Dockerfile を定義するだけです。

日食のテムリンから

ARG JAR_FILE=JAR_FILE_MUST_BE_SPECIFIED_AS_BUILD_ARG

${JAR_FILE} の app.jar をコピー

エントリポイント ["java", "-jar","/app.jar"]

この dockerfile は、Spring Boot サービスの uber-jar 版を 1 つのレイヤにバンドルしています。これは Dockerfile コンテナ化の最もシンプルなアプローチですが、依存関係が比較的安定している繰り返し回数を比較する場合は特に、多くの欠点があります。このような懸念から、このコンテナ化手法はより高度なものとみなされます。その一方で、独自の dockerfile を作成すると、ベースイメージを完全に制御でき、慎重にレイヤ化されたイメージを作成することによるパフォーマンス上のメリットを享受できます。

2**。ビルドプロセスを実行する**

目的のビルドステップを Cloud Build に通知できたので、ワンクリックでデプロイできるようになりました。

次のコマンドを実行します。

gcloud builds submit --tag LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME

上記のコマンドのプレースホルダ値を次のように置き換えます。

  • LOCATION: リポジトリのリージョンまたはマルチリージョンのロケーション。
  • PROJECT_ID: Cloud プロジェクト ID。
  • REPOSITORY: Artifact Registry リポジトリの名前。
  • IMAGE_NAME: コンテナ イメージの名前。

プロセスが完了すると、コンテナ イメージがビルドされて Artifact Registry に保存され、Cloud Run にデプロイされます。

この Codelab を終えると、アプリは mod4-migrate-to-cloud-run フォルダにあるアプリと同じように表示されます。

このように、Java 8 App Engine アプリを Java 17 と Cloud Run に正常に移行できました。これにより、ホスティング オプションを切り替えて選択する際の作業について、より明確に理解できるようになりました。

6. 概要/クリーンアップ

これで、アプリのアップグレード、コンテナ化、移行が完了しました。このチュートリアルはこれで終了です。

次のステップでは、Cloud Build でデプロイできるようになった CI/CD とソフトウェア サプライ チェーンのセキュリティ機能について詳しく学びます。

省略可: クリーンアップとサービスの無効化

このチュートリアル中にサンプルアプリを App Engine にデプロイした場合は、課金が発生しないようにアプリを無効にしてください。次の Codelab に進む準備ができたら、再度有効にします。App Engine アプリが無効になっている間は、トラフィックが発生することはありませんが、Datastore の使用量無料の割り当てを超過した場合は、課金対象になる可能性があるため、上限に収まるように十分な量を削除します。

一方、移行を続行せず、すべてを完全に削除したい場合は、サービスを削除するか、プロジェクトを完全にシャットダウンします。

7. 参考情報

App Engine 移行モジュールの Codelab に関する問題 / フィードバック

この Codelab に問題が見つかった場合は、提出する前にまず問題を検索してください。新しい問題の検索と登録を行うためのリンク:

移行に関するリソース

オンライン リソース

このチュートリアルに関連する可能性のあるオンライン リソースは次のとおりです。

App Engine

Cloud のその他の情報

動画

ライセンス

この作業はクリエイティブ・コモンズの表示 2.0 汎用ライセンスにより使用許諾されています。