演習 - Java EE (Jakarta EE) アプリケーションを JBoss EAP on Azure App Service にデプロイする

完了

この演習では、Java EE (Jakarta EE) アプリケーションを JBoss EAP on Azure App Service にデプロイします。 Maven プラグインを使用し、プロジェクトの構成、アプリケーションのコンパイルとデプロイ、データ ソースの構成を行います。

Azure App Service 用の Maven プラグインを使用してアプリを構成する

Azure App Service 用の Maven プラグインで構成目標を実行することにより、アプリケーションを構成しましょう。

./mvnw com.microsoft.azure:azure-webapp-maven-plugin:2.9.0:config

重要

MySQL サーバーのリージョンを変更した場合、待機時間の遅延を最小限に抑えるために、Java EE アプリケーション サーバーも同じリージョンに変更する必要があります。
コマンドで、Java バージョンに Java 11、ランタイム スタックに JBoss EAP 7 を選択します。

入力要素
Available subscriptions: Your appropriate subsctioption
Choose a Web Container Web App [\<create\>]: 1: <create>
Define value for OS [Linux]: Linux
Define value for javaVersion [Java 17]: 2: Java 11
Define value for runtimeStack: 1: Jbosseap 7
Define value for pricingTier [P1v3]: P1v3
Confirm (Y/N) [Y]: Y

コマンドを実行すると、ターミナルに次のようなメッセージが表示されます。

$ ./mvnw com.microsoft.azure:azure-webapp-maven-plugin:2.9.0:config
[INFO] Scanning for projects...
[INFO] 
[INFO] ---------< com.microsoft.azure.samples:jakartaee-app-on-jboss >---------
[INFO] Building jakartaee-app-on-jboss 1.0-SNAPSHOT
[INFO] --------------------------------[ war ]---------------------------------
[INFO] 
[INFO] --- azure-webapp-maven-plugin:2.5.0:config (default-cli) @ jakartaee-app-on-jboss ---
[WARNING] The POM for com.microsoft.azure.applicationinsights.v2015_05_01:azure-mgmt-insights:jar:1.0.0-beta is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details
[INFO] Auth type: OAUTH2
Username: YOUR_EMAIL_ADDRESS@microsoft.com
Available subscriptions:
[INFO] Subscription: YOUR_SUBSCRIPTION(********-****-****-****-************)
[INFO] It may take a few minutes to load all Java Web Apps, please be patient.
Web Container Web Apps in subscription Microsoft Azure Internal Billing-CDA:
* 1: <create>
  2: jakartaee-app-on-jboss-yoshio (linux, jbosseap 7.2-java8)
Please choose a Web Container Web App [<create>]: 
Define value for OS [Linux]:
* 1: Linux
  2: Windows
  3: Docker
Enter your choice: 
Define value for javaVersion [Java 8]:
* 1: Java 8
  2: Java 11
Enter your choice: 
Define value for runtimeStack:
  1: Jbosseap 7.2
  2: Jbosseap 7
* 3: Tomcat 8.5
  4: Tomcat 9.0
Enter your choice: 1
Define value for pricingTier [P1v3]:
  1: P3v3
  2: P2v3
* 3: P1v3
Enter your choice: 
Please confirm webapp properties
Subscription Id : ********-****-****-****-************
AppName : jakartaee-app-on-jboss-1625038814881
ResourceGroup : jakartaee-app-on-jboss-1625038814881-rg
Region : westeurope
PricingTier : P1v3
OS : Linux
Java : Java 8
Web server stack: Jbosseap 7.2
Deploy to slot : false
Confirm (Y/N) [Y]: 
[INFO] Saving configuration to pom.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:43 min
[INFO] Finished at: 2021-06-30T16:40:47+09:00
[INFO] ------------------------------------------------------------------------
$ 

コマンドが完了すると、Maven の pom.xml ファイルに次のエントリが追加されていることがわかります。

  <build>
    <finalName>ROOT</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.3.2</version>
      </plugin>
        <plugin>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-webapp-maven-plugin</artifactId>
            <version>2.9.0</version>
            <configuration>
                <schemaVersion>v2</schemaVersion>
                <resourceGroup>jakartaee-app-on-jboss-1625038814881-rg</resourceGroup>
                <appName>jakartaee-app-on-jboss-1625038814881</appName>
                <pricingTier>P1v3</pricingTier>
                <region>centralus</region>
                <runtime>
                    <os>Linux</os>
                    <javaVersion>Java 11</javaVersion>
                    <webContainer>Jbosseap 7</webContainer>
                </runtime>
                <deployment>
                    <resources>
                        <resource>
                            <directory>${project.basedir}/target</directory>
                            <includes>
                                <include>*.war</include>
                            </includes>
                        </resource>
                    </resources>
                </deployment>
            </configuration>
        </plugin>
    </plugins>
  </build>

重要

<region> 要素を確認します。 MySQL と同じインストール場所でない場合は、同じ場所に変更します。

Azure に展開するために上記の構成を追加した後、次の XML エントリを追加してスタート アップファイルを展開します。 リソース <type>startup</type> によって、指定されたスクリプトは startup.sh (Linux) または startup.cmd (Windows) として /home/site/scripts/ に展開されます。 スタートアップ スクリプトは次の手順で構成します。

              <!-- Please add following lines -->
              <resource>
                <type>startup</type>
                <directory>${project.basedir}/src/main/webapp/WEB-INF/</directory>
                <includes>
                  <include>createMySQLDataSource.sh</include>
                </includes>
              </resource>
              <!-- Please add following lines -->

Note

XML では次のリソースを指定してデプロイできます。

  • type=<war|jar|ear|lib|startup|static|zip>

    • path が指定されて "いない" 場合、type=war により、war ファイルは /home/site/wwwroot/app.war に展開されます。
    • type=war&path=webapps/<appname>\ の場合、アプリを /home/site/wwwroot/webapps/<appname> に解凍することで、WarDeploy とまったく同じように動作します。
    • type=jar の場合、war ファイルは /home/site/wwwroot/app.jar に展開されます。 path パラメーターは無視されます
    • type=ear の場合、war ファイルは /home/site/wwwroot/app.ear に展開されます。 path パラメーターは無視されます
    • type=lib の場合、jar は /home/site/libs に展開されます。 path パラメーターを指定する必要があります
    • type=static の場合、スクリプトは /home/site/scripts に展開されます。 path パラメーターを指定する必要があります
    • type=startup の場合、スクリプトは startup.sh (Linux) または startup.cmd (Windows) として /home/site/scripts/ に展開されます。 path パラメーターは無視されます
    • type=zip の場合、zip は /home/site/wwwroot に解凍されます。 path パラメーターは省略可能です。

次に、上記の XML ファイルのリソース グループ名とアプリケーション名の値を確認します。 これらの名前をメモするか、環境変数に割り当てます。

<resourceGroup>jakartaee-app-on-jboss-1625038814881-rg</resourceGroup>
<appName>jakartaee-app-on-jboss-1625038814881</appName>

Bash を使用している場合、次のコマンドを使用して環境変数を構成します。 これらの値は後ほど使用します。

export RESOURCEGROUP_NAME=jakartaee-app-on-jboss-1625038814881-rg
export WEBAPP_NAME=jakartaee-app-on-jboss-1625038814881

Java EE アプリをコンパイルしてビルドする

Azure App Service のデプロイ設定を構成した後、ソース コードをコンパイルしてパッケージ化します。

./mvnw clean package

ターミナルに次の出力が表示されます。

[INFO] Packaging webapp
[INFO] Assembling webapp [jakartaee-app-on-jboss] in [/private/tmp/mslearn-jakarta-ee-azure/target/ROOT]
[INFO] Processing war project
[INFO] Copying webapp resources [/private/tmp/mslearn-jakarta-ee-azure/src/main/webapp]
[INFO] Webapp assembled in [369 msecs]
[INFO] Building war: /private/tmp/mslearn-jakarta-ee-azure/target/ROOT.war
[INFO] WEB-INF/web.xml already added, skipping
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  7.656 s
[INFO] Finished at: 2023-03-04T12:35:43-05:00
[INFO] ------------------------------------------------------------------------

Java EE アプリを JBoss EAP on Azure App Service にデプロイする

コードをコンパイルしてパッケージ化した後、アプリケーションをデプロイします。

./mvnw azure-webapp:deploy

ターミナルに次のメッセージが表示されます。

[INFO] Creating resource group jakartaee-app-on-jboss-1625038814881-rg in region westeurope...
[INFO] Successfully created resource group jakartaee-app-on-jboss-1625038814881-rg.
[INFO] Creating app service plan...
[INFO] Successfully created app service plan asp-jakartaee-app-on-jboss-1625038814881.
[INFO] Creating web app jakartaee-app-on-jboss-1625038814881...
[INFO] Successfully created Web App jakartaee-app-on-jboss-1625038814881.
[INFO] Trying to deploy artifact to jakartaee-app-on-jboss-1625038814881...
[INFO] Deploying (/private/tmp/mslearn-jakarta-ee-azure/target/ROOT.war)[war]  ...
[INFO] Successfully deployed the artifact to https://jakartaee-app-on-jboss-1625038814881.azurewebsites.net
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  02:11 min
[INFO] Finished at: 2023-03-04T12:38:39-05:00
[INFO] ------------------------------------------------------------------------

デプロイされたアプリケーションの URL (特に Maven 出力の次の行) をメモしておきます。

[INFO] Successfully deployed the artifact to https://jakartaee-app-on-jboss-1625038814881.azurewebsites.net

データベース接続の構成

サンプル アプリケーションが MySQL データベースに接続され、データが表示されます。

pom.xml の Maven プロジェクト構成では、MySQL JDBC ドライバーを次のように指定しました。

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>${mysql-jdbc-driver}</version>
    </dependency>

この結果、JDBC ドライバーは、JBoss EAP によってデプロイ パッケージ ROOT.war に自動的にインストールされます。 MySQL JDBC ドライバーの名前は次のように参照できます。

ROOT.war_com.mysql.cj.jdbc.Driver_8_0

JBoss EAP で MySQL の DataSource オブジェクトを作成する

Azure Database for MySQL にアクセスするには、JBoss EAP で DataSource オブジェクトを構成し、ソース コードで JNDI 名を指定する必要があります。

JBoss EAP で MySQL の DataSource オブジェクトを作成するため、次のスタートアップ シェル スクリプトを作成しました。 スクリプト ファイルは、/WEB-INF ディレクトリにある createMySQLDataSource.sh です。

Note

このスクリプトで、JBoss CLI コマンドを使用して MySQL の DataSource をバインドします。 接続文字列、ユーザー名、パスワードには、環境変数 MYSQL_CONNECTION_URLMYSQL_USERMYSQL_PASSWORD を使用します。

次にスクリプト ファイルのソースが表示されます。 このスクリプト ファイルは App Service に既にアップロードされていますが、呼び出されるようにはまだ構成されていません。

#!/usr/bin/bash

# In order to use the variables in JBoss CLI scripts
# https://access.redhat.com/solutions/321513
#
sed -i -e "s|.*<resolve-parameter-values.*|<resolve-parameter-values>true</resolve-parameter-values>|g" /opt/eap/bin/jboss-cli.xml

/opt/eap/bin/jboss-cli.sh --connect <<EOF
data-source add --name=JPAWorldDataSourceDS \
--jndi-name=java:jboss/datasources/JPAWorldDataSource \
--connection-url=${MYSQL_CONNECTION_URL} \
--driver-name=ROOT.war_com.mysql.cj.jdbc.Driver_8_0 \
--user-name=${MYSQL_USER} \
--password=${MYSQL_PASSWORD} \
--min-pool-size=5 \
--max-pool-size=20 \
--blocking-timeout-wait-millis=5000 \
--enabled=true \
--driver-class=com.mysql.cj.jdbc.Driver \
--jta=true \
--use-java-context=true \
--valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker \
--exception-sorter-class-name=com.mysql.cj.jdbc.integration.jboss.ExtendedMysqlExceptionSorter
exit
EOF

次に、スタートアップ スクリプトを呼び出すように App Service インスタンスを構成します。

az webapp config set --startup-file '/home/site/scripts/startup.sh' \
-n ${WEBAPP_NAME} \
-g ${RESOURCEGROUP_NAME}

スクリプトは、実行された後、アプリケーション サーバーが再起動されるたびに呼び出されます。

Note

デプロイ成果物が ROOT.war ではない場合は、--driver-name=YOUR_ARTIFACT.war_com.mysql.cj.jdbc.Driver_8_0 の値も変更する必要があります。

MySQL に接続するための環境変数を構成する

スタートアップ スクリプトを構成した後、特定の環境変数を使用するように App Service を構成します。

az webapp config appsettings set \
  --resource-group ${RESOURCEGROUP_NAME} --name ${WEBAPP_NAME} \
  --settings \
  MYSQL_CONNECTION_URL='jdbc:mysql://mysqlserver-**********.mysql.database.azure.com:3306/world?useSSL=true&requireSSL=false' \
  MYSQL_PASSWORD='************' \
  MYSQL_USER=azureuser

ヒント

MYSQL_CONNECTION_URLMYSQL_USERMYSQL_PASSWORD は、前のユニットの設定値を使用します。

コード内のデータソース参照を確認する

アプリケーションから MySQL データベースにアクセスするには、アプリケーション プロジェクトでデータ ソース参照を構成する必要があります。 Java Persistence API (JPA) を使用して、データベース アクセス コードを実装しました。

DataSource の参照の構成が、JPA の構成ファイルである persistence.xml に追加されています。

次のファイルにアクセスします。

├── src
│   ├── main
│   │   ├── resources
│   │   │   └── META-INF
│   │   │       └── persistence.xml

DataSource の名前が、構成で使用されている名前と一致するかどうかを確認します。 コードによって JNDI 名が java:jboss/datasources/JPAWorldDataSource として既に作成されています。

  <persistence-unit name="JPAWorldDatasourcePU" transaction-type="JTA">
    <jta-data-source>java:jboss/datasources/JPAWorldDataSource</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="hibernate.generate_statistics" value="true" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
    </properties>
  </persistence-unit>
</persistence>

次に、PersistenceContext のユニット名で次のように参照される MySQL データベースにアクセスできます。

@Transactional(REQUIRED)
@RequestScoped
public class CityService {

    @PersistenceContext(unitName = "JPAWorldDatasourcePU")
    EntityManager em;

アプリケーションへのアクセス

サンプル アプリケーションで、3 つの REST エンドポイントを実装しました。 Web ブラウザーまたは curl コマンドを使用して、アプリケーションにアクセスし、これらのエンドポイントを検証することができます。

アプリケーションにアクセスするには、前のセクションで取得したアプリケーションの URL を参照する必要があります。

[INFO] Successfully deployed the artifact to  
https://jakartaee-app-on-jboss-1606464084546.azurewebsites.net

次のコマンドを実行し、すべての大陸情報を JSON 形式で取得します。

Screenshot that shows area as the REST endpoint.

$ curl https://${WEBAPP_NAME}.azurewebsites.net/area
["North America","Asia","Africa","Europe","South America","Oceania","Antarctica"]$ 

URL で大陸を指定すると、指定した大陸のすべての国/地域を取得できます。

Screenshot that shows continent as the REST endpoint.

$ curl https://${WEBAPP_NAME}.azurewebsites.net/area/Asia | jq '.[] | { name: .name, code: .code }'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--   100 16189  100 16189    0     0  65278      0 --:--:-- --:--:-- --:--:-- 65542
{
  "name": "Afghanistan",
  "code": "AFG"
}
{
  "name": "United Arab Emirates",
  "code": "ARE"
}
{
  "name": "Armenia",
  "code": "ARM"
}
{
  "name": "Azerbaijan",
  "code": "AZE"
}
{
  "name": "Bangladesh",
  "code": "BGD"
}
....

最後に、/countries の後に国/地域番号を指定すると、その国/地域内で人口が 100 万を超えるすべての都市を確認できます。

Screenshot that shows cities as the REST endpoint.

$ curl https://${WEBAPP_NAME}.azurewebsites.net/countries/JPN | jq '.[].name'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--   100   788  100   788    0     0   2671      0 --:--:-- --:--:-- --:--:--  2662
"Tokyo"
"Jokohama [Yokohama]"
"Osaka"
"Nagoya"
"Sapporo"
"Kioto"
"Kobe"
"Fukuoka"
"Kawasaki"
"Hiroshima"
"Kitakyushu"

演習の概要

これで、アプリケーションの REST エンドポイントを検証し、アプリケーションで MySQL データベースのデータを取得できることをテストしました。

次のユニットでは、サーバー ログを調べます。