Esercizio: Distribuire un'applicazione Jakarta EE in JBoss EAP nel servizio app di Azure
In questa unità si distribuisce un'applicazione Jakarta EE in Red Hat JBoss Enterprise Application Platform (JBoss EAP) nel servizio app di Azure. Usa il Maven Plugin per Azure App Service per configurare il progetto, compilare e distribuire l'applicazione, e configurare una fonte di dati.
Configurare l'app
Configurare l'app con il plug-in Maven per il servizio app di Azure seguendo questa procedura:
Eseguire l'obiettivo di configurazione del plug-in di Azure in modo interattivo usando il comando seguente:
./mvnw com.microsoft.azure:azure-webapp-maven-plugin:2.13.0:configImportante
Se si modifica l'area del server MySQL, è necessario associare tale area all'area del server applicazioni Jakarta EE per ridurre al minimo i ritardi di latenza.
Usare i valori nella tabella seguente per rispondere alle richieste interattive:
Elemento di input Valore Create new run configuration (Y/N) [Y]:YDefine value for OS [Linux]:LinuxDefine value for javaVersion [Java 17]:1: Java 17Define value for runtimeStack:3: Jbosseap 7Define value for pricingTier [P1v3]:P1v3Confirm (Y/N) [Y]:YL'output seguente è tipico:
[INFO] Saving configuration to pom. [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 03:00 min [INFO] Finished at: 2025-02-21T06:24:11+09:00 [INFO] ------------------------------------------------------------------------Dopo aver usato il comando Maven, il seguente esempio è un'aggiunta tipica al file Maven pom.xml:
<build> <finalName>ROOT</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.4.0</version> </plugin> <plugin> <groupId>com.microsoft.azure</groupId> <artifactId>azure-webapp-maven-plugin</artifactId> <version>2.13.0</version> <configuration> <schemaVersion>v2</schemaVersion> <resourceGroup>jakartaee-app-on-jboss-rg</resourceGroup> <appName>jakartaee-app-on-jboss</appName> <pricingTier>P1v3</pricingTier> <region>centralus</region> <runtime> <os>Linux</os> <javaVersion>Java 17</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>Controllare l'elemento
<region>nel file pom.xml . Se il valore non corrisponde al percorso di installazione di MySQL, modificarlo nello stesso percorso.Usare l'esempio seguente per modificare il valore
webContainernel file pom.xml inJbosseap 8per l'ambiente JBoss EAP 8 in Servizio app di Azure:Suggerimento
A partire da febbraio 2025, la versione più recente disponibile di JBoss EAP è la 8.0 Update 4.1.
<runtime> <os>Linux</os> <javaVersion>Java 17</javaVersion> <webContainer>Jbosseap 8</webContainer> <!-- Change this value --> </runtime>Aggiungere il codice XML seguente all'elemento
<resources>del file pom.xml . Questa configurazione viene usata per distribuire il file di avvio, che verrà aggiornato più avanti in questa unità.<resource> <type>startup</type> <directory>${project.basedir}/src/main/webapp/WEB-INF/</directory> <includes> <include>createMySQLDataSource.sh</include> </includes> </resource>Il valore della risorsa
<type>distartupdistribuisce lo script specificato come file di startup.sh per Linux o startup.cmd per Windows. Il percorso di distribuzione è /home/site/scripts/.Annotazioni
È possibile scegliere l'opzione di distribuzione e il percorso di distribuzione specificando
typein uno dei modi seguenti:type=wardistribuisce il file WAR in /home/site/wwwroot/app.war sepathnon è specificato.type=war&path=webapps/<appname>distribuisce il file WAR in /home/site/wwwroot/webapps/<appname>.type=jardistribuisce il file WAR in /home/site/wwwroot/app.jar. Il parametropathviene ignorato.type=eardistribuisce il file WAR in /home/site/wwwroot/app.ear. Il parametropathviene ignorato.type=libdistribuisce il file JAR in /home/site/libs. È necessario specificare ilpathparametro .type=staticdistribuisce lo script in /home/site/scripts. Specificare il parametropath.type=startupdistribuisce lo script come startup.sh in Linux o startup.cmd in Windows. Lo script viene distribuito in /home/site/scripts/. Il parametropathviene ignorato.type=zipdecomprime il file .zip in /home/site/wwwroot. Ilpathparametro è facoltativo.
Controllare i valori degli elementi
resourceGroupeappNamenel file pom.xml.Assegnare i valori per
resourceGroupeappNamealle variabili di ambiente usando i comandi seguenti:export RESOURCE_GROUP_NAME=<resource-group> export WEB_APP_NAME=<app-name>
Compilare e generare l'app Jakarta EE
Dopo aver configurato le impostazioni di distribuzione del servizio app di Azure, compilare e creare il pacchetto del codice sorgente usando il comando seguente:
./mvnw clean package
L'output seguente è tipico:
[INFO] --- war:3.4.0:war (default-war) @ jakartaee-app-on-jboss ---
[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] Building war: /private/tmp/mslearn-jakarta-ee-azure/target/ROOT.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.881 s
[INFO] Finished at: 2025-02-21T06:32:30+09:00
[INFO] ------------------------------------------------------------------------
Distribuire l'app Jakarta EE su JBoss EAP su Azure App Service
Dopo la compilazione e il pacchetto del codice, distribuire l'applicazione usando il comando seguente:
./mvnw azure-webapp:deploy
Verrà visualizzato l'output che include un messaggio di operazione riuscita e l'URL dell'applicazione distribuita. Assicurarsi di salvare l'URL per usarlo in un secondo momento.
Configurare una connessione di database
L'applicazione di esempio si connette al database MySQL e visualizza i dati. La configurazione del progetto Maven nel file pom.xml specifica il driver JDBC MySQL, come illustrato nell'esempio seguente:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-jdbc-driver}</version>
</dependency>
Di conseguenza, JBoss EAP installa automaticamente il driver ROOT.war_com.mysql.cj.jdbc.Driver_9_2 JDBC nel pacchetto di distribuzione ROOT.war.
Creare l'oggetto MySQL DataSource in JBoss EAP
Per accedere a Database di Azure per MySQL, è necessario configurare l'oggetto DataSource in JBoss EAP e specificare il nome Java Naming and Directory Interface (JNDI) nel codice sorgente. Per creare un oggetto MySQL DataSource in JBoss EAP, usare lo script della shell di avvio /WEB-INF/createMySQLDataSource.sh . L'esempio seguente mostra una versione non configurata dello script già nel servizio app di Azure:
#!/bin/bash
# In order to use the variables in 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=${AZURE_MYSQL_CONNECTIONSTRING}&characterEncoding=utf8&sslMode=REQUIRED&serverTimezone=UTC&authenticationPlugins=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin \
--driver-name=ROOT.war_com.mysql.cj.jdbc.Driver_9_2 \
--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
Annotazioni
Quando si crea l'origine dati, non si specifica una password per la connessione MySQL. La variabile AZURE_MYSQL_CONNECTIONSTRING di ambiente viene specificata nel --connection-url parametro . Questa variabile di ambiente viene impostata automaticamente quando viene creata la connessione al servizio in un secondo momento.
Il valore di connessione del servizio è impostato su jdbc:mysql://$MYSQL_SERVER_INSTANCE.mysql.database.azure.com:3306/world?serverTimezone=UTC&sslmode=required&user=aad_jbossapp, che usa il aad_jbossapp nome utente senza password.
Aggiungendo &authenticationPlugins=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin a questo URL, l'autenticazione ID Entra di Microsoft è abilitata per l'utente aad_jbossapp.
Configurare l'istanza del servizio app per richiamare lo script di avvio usando il comando seguente:
az webapp config set \
--resource-group ${RESOURCE_GROUP_NAME} \
--name ${WEB_APP_NAME} \
--startup-file '/home/site/scripts/startup.sh'
Dopo l'esecuzione dello script, il server applicazioni lo richiama ogni volta che il server applicazioni viene riavviato.
Annotazioni
Se l'artefatto di distribuzione non è ROOT.war, cambiare anche il valore --driver-name=YOUR_ARTIFACT.war_com.mysql.cj.jdbc.Driver_9_2.
Configurare la connessione al servizio per il server flessibile MySQL
Dopo aver configurato lo script di avvio, configurare il servizio app per l'uso di Service Connector per la connessione al server flessibile MySQL attenendosi alla procedura seguente:
Impostare le variabili di ambiente usando i comandi seguenti:
export PASSWORDLESS_USER_NAME_SUFFIX=jbossapp export SOURCE_WEB_APP_ID=$(az webapp list \ --resource-group $RESOURCE_GROUP_NAME \ --query "[0].id" \ --output tsv) export MYSQL_ID=$(az mysql flexible-server list \ --resource-group $RESOURCE_GROUP_NAME \ --query "[0].id" \ --output tsv) export TARGET_MYSQL_ID=$MYSQL_ID/databases/world export MANAGED_ID=$(az identity list \ --resource-group $RESOURCE_GROUP_NAME \ --query "[0].id" \ --output tsv)Le variabili di ambiente vengono usate per gli scopi seguenti:
PASSWORDLESS_USER_NAME_SUFFIXè il suffisso per il nome utente usato per connettersi al server flessibile MySQL. Il nome utente creato ha il prefissoaad_seguito dal suffisso specificato.SOURCE_WEB_APP_IDè l'ID dell'istanza del servizio app di Azure usata per connettersi al server flessibile MySQL.MYSQL_IDè l'ID del server flessibile MySQL.TARGET_MYSQL_IDspecifica il nome del database$MYSQL_ID/databases/worldper stabilire una connessione con un utente autorizzato ad accedere al databaseworld.MANAGED_IDè l'identità gestita usata per connettersi al server flessibile MySQL.
Aggiungere l'estensione per
serviceconnector-passwordlesse creare la connessione al servizio usando i comandi seguenti:az extension add \ --name serviceconnector-passwordless \ --upgrade az webapp connection create mysql-flexible \ --resource-group ${RESOURCE_GROUP_NAME} \ --connection $PASSWORDLESS_USER_NAME_SUFFIX \ --source-id $SOURCE_WEB_APP_ID \ --target-id $TARGET_MYSQL_ID \ --client-type java \ --system-identity mysql-identity-id=$MANAGED_IDAnnotazioni
se viene visualizzato un messaggio di errore come
Resource '********-****-****-****-************' does not exist or one of its queried reference-property objects are not present., eseguire di nuovo il comando dopo alcuni secondi.Al prompt di SQL controllare l'elenco degli utenti registrati in MySQL usando la query seguente:
SELECT user, host, plugin FROM mysql.user;L'output seguente è tipico:
+----------------------------------+-----------+-----------------------+ | user | host | plugin | +----------------------------------+-----------+-----------------------+ | aad_jbossapp | % | aad_auth | | azureuser | % | mysql_native_password | | $CURRENT_AZ_LOGIN_USER_NAME#EXT#@| % | aad_auth | | azure_superuser | 127.0.0.1 | mysql_native_password | | azure_superuser | localhost | mysql_native_password | | mysql.infoschema | localhost | caching_sha2_password | | mysql.session | localhost | caching_sha2_password | | mysql.sys | localhost | caching_sha2_password | +----------------------------------+-----------+-----------------------+ 8 rows in set (2.06 sec)Verrà visualizzato un
aad_jbossapputente che usa ilaad_authplug-in. Da JBoss EAP distribuito in Azure è possibile connettersi al server flessibile MySQL usando ilaad_jbossappnome utente senza password.
Verificare il riferimento a DataSource nel codice
Per accedere al database MySQL dall'applicazione, è necessario configurare il riferimento all'origine dati nel progetto dell'applicazione.
Il codice di accesso al database viene implementato usando l'API Java Persistence (JPA). La configurazione per il DataSource riferimento si trova nel file di configurazione JPA persistence.xml.
Per confermare il DataSource riferimento, seguire questa procedura:
Aprire il file src/main/resources/META-INF/persistence.xml e verificare se il
DataSourcenome corrisponde al nome usato nella configurazione. Lo script di avvio ha già creato il nome JNDI comejava:jboss/datasources/JPAWorldDataSource, come illustrato nell'esempio seguente:<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>Accedere al database MySQL nel nome dell'unità
PersistenceContext, come illustrato nell'esempio seguente:@Transactional(REQUIRED) @RequestScoped public class CityService { @PersistenceContext(unitName = "JPAWorldDatasourcePU") EntityManager em;
Accedere all'applicazione
L'applicazione di esempio implementa tre endpoint REST. Per accedere all'applicazione e recuperare i dati, seguire questa procedura:
Usare il browser per passare all'URL dell'applicazione, visualizzato nell'output quando è stata distribuita l'applicazione.
Per ottenere tutte le informazioni sui continenti in formato JSON, usa il metodo
GETsull'endpointarea.Per ottenere tutti i paesi e le aree geografiche in un continente specificato, usare il
GETmetodo nell'endpointareae specificare uncontinentparametro path.Per ottenere tutte le città con una popolazione maggiore di un milione all'interno del paese o dell'area geografica specificata, usare il
GETmetodo nell'endpointcountriese specificare un parametro dicountrycodepercorso.
Esercizio di riepilogo
In questa unità sono stati convalidati gli endpoint REST dell'applicazione e si è verificato che l'applicazione può ottenere dati dal database MySQL. Nell'unità successiva si esaminano i log del server.


