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

1. 概要

この一連の Codelab(ご自分のペースで進められる実践型のチュートリアル)は、一連の移行についてガイダンスを実施することにより、Google App Engine(標準)の Java デベロッパーがアプリをモダナイズできるよう支援することを目的としています。次の手順に沿ってアプリを更新すると、移植性を高め、Cloud Run、App Engine への Google Cloud のコンテナ ホスティング姉妹サービス、その他のコンテナ ホスティング サービス用にコンテナ化できます。

このチュートリアルでは、Jib を使用して App Engine アプリをコンテナ化し、Cloud Run フルマネージド サービスにデプロイする方法について説明します。Jib を使用すると、コンテナ内でのアプリケーションの開発、配布、実行に業界でよく知られている Docker イメージを作成できます。

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

アプリケーションで以前の App Engine バンドル サービスやその他の App Engine 機能を多用している場合は、Cloud Run に移行する前に、バンドル サービスから移行するか、これらの機能を置き換えることをおすすめします。移行オプションの調査に時間がかかる場合や、当面は以前のバンドル サービスを使い続ける場合は、新しいランタイムにアップグレードしても Java 11/17 用の App Engine バンドル サービスにアクセスできます。アプリのポータビリティを高めたら、この Codelab に戻って、手順をアプリに適用する方法を学びます。

GCP コンソールの

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

必要なもの

アンケート

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

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

Java のご利用経験についてお答えください。

初心者 中級者 上級者

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

初心者 中級者 上級者

2. 背景情報

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

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

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

この Codelab では、コンテナの構築とデプロイ方法について学びます。次の方法を学習します。

  • Jib を使用してアプリをコンテナ化する
  • 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 アプリです。App Engine へのデプロイ用にこのアプリを準備する方法については、README の手順に沿って行ってください。

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

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

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

  1. gcloud CLI をインストールする/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 を使用します。出荷時に App Engine が提供するバージョンと一致するように Jetty バージョンを構成することもできます。

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

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 としてパッケージ化する

Jib で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 は異なるユーザー エクスペリエンスを提供するように設計されています。Cron サービスやタスクキュー サービスなど、App Engine に標準装備の一部の機能は、手動で再作成する必要があります。これらの機能については、後のモジュールで詳しく説明します。

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

今後は 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 Run に直接デプロイできます。これは、Cloud Build をバックグラウンドで使用して、手動でデプロイする手間を省く優れた方法です。ソースのデプロイについては、後続のモジュールで詳しく説明します。

アプリのデプロイ方法をより細かく制御する必要がある場合は、目的のビルドステップを明示的にレイアウトする cloudbuild.yaml ファイルを定義することで、その制御を実現できます。

1. cloudbuild.yaml ファイルを定義する

pom.xml と同じレベルに次の cloudbuild.yaml ファイルを作成します。

steps:
  # Test your build
  - name: maven:eclipse-temurin
    entrypoint: mvn
    args: ["test"]
  # Build with Jib
  - name: maven:eclipse-temurin
    entrypoint: mvn
    args: [ "compile", "com.google.cloud.tools:jib-maven-plugin:3.2.1:build", "-Dimage=northamerica-northeast1-docker.pkg.dev/PROJECT_ID/migration/visitors:jib"]
  # Deploy to Cloud Run
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args: [ 'run', 'deploy', 'visitors', '--image', 'northamerica-northeast1-docker.pkg.dev/PROJECT_ID/migration/visitors:jib', '--region', 'northamerica-northeast1', '--allow-unauthenticated']

次の手順に従うように Cloud Build に指示すると、以下のようになります。

  1. ./mvnw test でテストを実行する
  2. Jib を使用してイメージをビルドし、Artifact Registry に push してタグを付ける
  3. gcloud run deploy を使用してイメージを Cloud Run にデプロイする

‘visitors' は、目的のサービス名として Cloud Run に提供されます。–allow-unauthenticated フラグを指定すると、ユーザーは認証なしでウェブアプリにアクセスできます。cloudbuild.yaml ファイルで、PROJECT_ID をプロジェクトの ID に置き換えてください。

次に、次の IAM ポリシー バインディングを追加して、Cloud Build サービス アカウントが Artifact Registry にアクセスできるようにします。

export PROJECT_ID=$(gcloud config list --format 'value(core.project)')
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)" )

gcloud projects add-iam-policy-binding $PROJECT_ID \
--member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
--role=roles/run.admin \
--project=$PROJECT_ID
gcloud iam service-accounts add-iam-policy-binding $PROJECT_NUMBER-compute@developer.gserviceaccount.com \
--member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
--role roles/iam.serviceAccountUser --project=$PROJECT_ID

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

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

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

gcloud builds submit

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

この Codelab の終わりには、アプリは java17-and-cloud-run/finish のアプリと同じになります。

このように、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 汎用ライセンスにより使用許諾されています。