Tomcat アプリケーションを Azure Container Apps に移行する

このガイドでは、既存の Tomcat アプリケーションを移行して Azure Container Apps (ACA) 上で実行する場合に注意する必要がある点について説明します。

移行前

移行を確実に成功させるには、開始する前に、次のセクションで説明する評価とインベントリの手順を完了します。

外部リソースをインベントリする

データ ソース、JMS メッセージ ブローカー、およびその他の外部リソースは、JNDI (Java Naming and Directory Interface) を介して挿入されます。 こうしたリソースの一部では、移行または再構成が必要な場合があります。

アプリケーション内

META-INF/context.xml ファイルを調べます。 <Context> 要素内の <Resource> 要素を探します。

アプリケーション サーバー上

$CATALINA_BASE/conf/context.xml および $CATALINA_BASE/conf/server.xml ファイルと、$CATALINA_BASE/conf/[engine-name]/[host-name] ディレクトリにある .xmlファイルを調べます。

context.xmlファイルでは、JNDI リソースは、最上位の <Context> 要素内の <Resource> 要素で記述されます。

server.xml ファイルでは、JNDI リソースは <GlobalNamingResources> 要素内の <Resource> 要素で記述されます。

データソース

データソースは、type 属性が javax.sql.DataSource に設定されている JNDI リソースです。 データソースごとに、次の情報を文書にまとめます。

  • データソース名
  • 接続プールの構成
  • JDBC ドライバーの JAR ファイルの場所

詳細については、Tomcat のドキュメントの「JNDI Datasource How-To」を参照してください。

その他のすべての外部リソース

このガイドでは、考えられるすべての外部依存関係を記載することはできません。 アプリケーションの外部依存関係がすべて満たされるよう確認するのは、担当チームの責任です。

シークレットをインベントリする

パスワードとセキュリティで保護された文字列

すべてのシークレット文字列とパスワードについて、運用サーバー上のすべてのプロパティと構成ファイルを確認します。 $CATALINA_BASE/conf にある server.xmlcontext.xml を必ず確認してください。 また、アプリケーション内にパスワードや資格情報を含むファイルが存在する場合もあります。 これらには、META-INF/context.xmlや、Spring Boot アプリケーションの場合は application.properties または application.yml ファイルなどがあります。

ファイル システムが使用されているかどうかとその使用方法を判断する

アプリケーション サーバーでファイル システムを使用する場合は、再構成や、まれにアーキテクチャの変更が必要になります。 次のシナリオの一部または全部を確認できます。

読み取り専用の静的コンテンツ

現在、アプリケーションで静的コンテンツを提供している場合は、そのための別の場所が必要になります。 静的コンテンツを Azure Blob Storage に移動し、グローバルな高速ダウンロードのために Azure CDN を追加することを検討できます。 詳細については、「Azure Storage での静的 Web サイト ホスティング」と「クイック スタート:Azure ストレージ アカウントと Azure CDN との統合」を参照してください。 静的コンテンツは、Azure Spring Apps Enterprise プランのアプリに直接デプロイすることもできます。 詳細については、「 Web 静的ファイルをデプロイする」を参照してください。

動的に公開される静的コンテンツ

アプリケーションによってアップロードまたは生成されるが、作成後に変更できない静的コンテンツをアプリケーションで許可する場合は、前述のように Azure Blob Storage と Azure CDN を使用し、Azure Function でアップロードと CDN の更新を処理します。 「Azure Functions を使用した静的コンテンツのアップロードと CDN の事前読み込み」で、ご利用いただけるサンプルの実装を提供しています。 静的コンテンツは、Azure Spring Apps Enterprise プランのアプリに直接デプロイすることもできます。 詳細については、「 Web 静的ファイルをデプロイする」を参照してください。

ID セッションの永続化メカニズム

使用されているセッション永続化マネージャーを特定するには、アプリケーション内の context.xml ファイルおよび Tomcat の構成を調べます。 <Manager> 要素を探して、className 属性の値を確認します。

Tomcat の組み込みの PersistentManager の実装 (StandardManagerFileStore など) は、ACA のような分散型のスケーリングされたプラットフォームで使用するように設計されていません。 ACA では、複数のインスタンス間で負荷が分散され、任意の時点で任意のインスタンスが透過的に再起動される可能性があるため、変更可能な状態をファイル システムに保持することは推奨されません。

セッションの永続化が必要な場合は、代替の PersistentManager の実装を使用する必要があります。これは、Redis Cache を使用して VMware Tanzu Session Manager などの外部データ ストアへの書き込みを行います。

特殊なケース

運用シナリオによっては、さらに変更が必要な場合や、さらに制限を課す場合があります。 そのようなシナリオはめったに発生しませんが、それらがアプリケーションに適用されないこと、または正しく解決されることを確認することが重要です。

スケジュールされたジョブにアプリケーションが依存しているかどうかを判断する

スケジュールされたジョブ (Quartz Scheduler タスクや cron ジョブなど) は、コンテナー化された Tomcat デプロイでは使用できません。 アプリケーションをスケールアウトすると、1 つのスケジュールされたジョブが、スケジュールされた期間に複数回実行されることがあります。 このような場合、意図しない結果になることがあります。

アプリケーション サーバーの内部または外部で、すべてのスケジュールされたジョブをインベントリします。

アプリケーションに OS 固有のコードが含まれているかどうかを判断する

アプリケーションにホスト OS に依存するコードが含まれている場合は、それをリファクタリングしてそれらの依存関係を削除する必要があります。 たとえば、ファイル システムのパスで / または \ を使用している場合、File.Separator または Paths.get に置き換えることが必要になる可能性があります。

MemoryRealm が使用されているかどうかを判断する

MemoryRealm には、永続化された XML ファイルが必要です。 ACA 上で、このファイルをコンテナー イメージに追加するか、コンテナーから使用できる共有ストレージにアップロードする必要があります (詳細については、「セッションの永続化メカニズムを特定する」セクションを参照してください)。それに応じて pathName パラメーターを変更する必要があります。

MemoryRealm が現在使用されているかどうかを確認するには、server.xml および context.xml ファイルを調べ、className 属性が org.apache.catalina.realm.MemoryRealm に設定されている <Realm> 要素を検索します。

インプレース テスト

コンテナー イメージを作成する前に、ACA で使用する予定のアプリケーションを JDK と Tomcat に移行します。 アプリケーションを十分にテストして、互換性とパフォーマンスを確認します。

構成のパラメーター化

多くの場合、移行前に、server.xml および context.xml ファイル内でシークレットや外部依存関係 (データソースなど) が識別されます。 そのため、識別された各項目について、ユーザー名、パスワード、接続文字列、または URL を環境変数に置き換えます。

たとえば、context.xml ファイルに次の要素が含まれているとします。

<Resource
    name="jdbc/dbconnection"
    type="javax.sql.DataSource"
    url="jdbc:postgresql://postgresdb.contoso.com/wickedsecret?ssl=true"
    driverClassName="org.postgresql.Driver"
    username="postgres"
    password="t00secure2gue$$"
/>

この場合は、次の例に示されているように変更できます。

<Resource
    name="jdbc/dbconnection"
    type="javax.sql.DataSource"
    url="${postgresdb.connectionString}"
    driverClassName="org.postgresql.Driver"
    username="${postgresdb.username}"
    password="${postgresdb.password}"
/>

移行

注意

一部の Tomcat デプロイでは、1 つの Tomcat サーバーで複数のアプリケーションが実行されている場合があります。 デプロイがこれに該当する場合は、各アプリケーションを個別のポッドで実行することを強くお勧めします。 これにより、各アプリケーションのリソース使用率を最適化しながら、複雑さと結合を最小限に抑えることができます。

デプロイの成果物を準備する

コンテナー上の Tomcat のクイックスタート GitHub リポジトリを複製します。 このリポジトリには、多くの推奨される最適化が適用された Dockerfile と Tomcat 構成ファイルが含まれています。 次の手順では、コンテナー イメージをビルドして ACA にデプロイする前に、これらのファイルに対して行う必要があると思われる変更について説明します。

JNDI リソースを追加する

次の例に示すように、server.xml を編集して、移行前の手順で準備したリソース (データ ソースなど) を追加します。

<!-- Global JNDI resources
      Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml"
               />

    <!-- Migrated datasources here: -->
    <Resource
        name="jdbc/dbconnection"
        type="javax.sql.DataSource"
        url="${postgresdb.connectionString}"
        driverClassName="org.postgresql.Driver"
        username="${postgresdb.username}"
        password="${postgresdb.password}"
    />
    <!-- End of migrated datasources -->
</GlobalNamingResources>

その他のデータ ソースの手順については、Tomcat のドキュメントで「JNDI Datasource How-To」の次のセクションを参照してください。

イメージをビルドしてプッシュする

ACA で使用するためにイメージをビルドして Azure Container Registry (ACR) にアップロードする最も簡単な方法は、az acr build コマンドを使用することです。 このコマンドでは、コンピューターに Docker をインストールする必要はありません。 たとえば、tomcat-container-quickstart リポジトリの Dockerfile とアプリケーション パッケージ petclinic.war が現在のディレクトリにある場合、次のコマンドを使って ACR にコンテナー イメージをビルドすることができます。

az acr build \
    --registry $acrName \
    --image "${acrName}.azurecr.io/petclinic:{{.Run.ID}}" 
    --build-arg APP_FILE=petclinic.war \
    --build-arg SERVER_XML=prod.server.xml .

WAR ファイルの名前が ROOT.war の場合は、--build-arg APP_FILE... パラメーターを省略できます。 サーバー XML ファイルの名前が server.xml の場合は、--build-arg SERVER_XML... パラメーターを省略できます。 どちらのファイルも Dockerfile と同じディレクトリに存在する必要があります。

または、Docker CLI を使い、次のコマンドを使ってローカルでイメージをビルドすることもできます。 この方法を使用すると、ACR への初期デプロイの前に、イメージのテストと調整を簡単に行えます。 ただし、Docker CLI がインストールされ、Docker デーモンが実行されている必要があります。

# Build the image locally.
sudo docker build . --build-arg APP_FILE=petclinic.war -t "${acrName}.azurecr.io/petclinic:1"

# Run the image locally.
sudo docker run -d -p 8080:8080 "${acrName}.azurecr.io/petclinic:1"

# You can now access your application with a browser at http://localhost:8080.

# Sign in to ACR.
sudo az acr login --name $acrName

# Push the image to ACR.
sudo docker push "${acrName}.azurecr.io/petclinic:1"

詳細については、「Azure Container Registry を使用してコンテナー イメージをビルドして格納する」を参照してください。

Azure Container Apps をデプロイする

次のコマンドはデプロイの例を示します。

az containerapp create \
    --resource-group <RESOURCE_GROUP> \
    --name <APP_NAME> \
    --environment <ENVIRONMENT_NAME> \
    --image <IMAGE_NAME> \
    --target-port 8080 \
    --ingress 'external' \
    --registry-server <REGISTRY_SERVER> \
    --min-replicas 1

さらに詳細なクイックスタートについては、「クイックスタート: 最初のコンテナー アプリをデプロイする」を参照してください。

移行後

アプリケーションを ACA に移行したので、期待どおりに動作することを確認する必要があります。 これを完了したら、アプリケーションをよりクラウド ネイティブにするための推奨事項がいくつかあります。

Recommendations

  • 事業継続とディザスター リカバリー戦略を設計し、実装します。 ミッション クリティカルなアプリケーションの場合は、複数リージョン デプロイのアーキテクチャを検討してください。 詳細については、「Azure Kubernetes Service (AKS) での事業継続とディザスター リカバリーに関するベスト プラクティス」を参照してください。

  • logging.properties ファイル内の項目を評価します。 パフォーマンスを改善するために、一部のログ出力をなくすか減らすことを検討します。

  • さらにパフォーマンスを最適化するために、コードのキャッシュ サイズを監視し、パラメーター -XX:InitialCodeCacheSize および -XX:ReservedCodeCacheSize を Dockerfile の JAVA_OPTS 変数に追加することを検討します。 詳細については、Oracle のドキュメントの「Codecache チューニング」をご覧ください。

  • 異常な状態を迅速に検出して対処するために、Azure Monitor のアラート ルールおよびアクション グループを追加することを検討します。

  • 待機時間を短くし、信頼性とフォールト トレランスを高めるために、Azure Container Apps のデプロイを別のリージョンにレプリケートすることを検討します。 Azure Traffic Manager を使用してデプロイ間で負荷を分散するか、Azure Front Door を使用して SSL オフロードと DDoS 保護付きの Web アプリケーション ファイアウォールを追加します。

  • geo レプリケーションが不要な場合は、Azure Application Gateway を追加して、SSL オフロードと DDoS 保護付きの Web アプリケーション ファイアウォールを追加することを検討します。