Exercício – Implantar um aplicativo Jakarta EE no JBoss EAP no Serviço de Aplicativo do Azure

Concluído

Nesta unidade, você implantará um aplicativo Jakarta EE no Red Hat JBoss Enterprise Application Platform (JBoss EAP) no Serviço de Aplicativo do Azure. Use o Plug-in do Maven para o Serviço de Aplicativo do Azure para configurar o projeto, compilar e implantar o aplicativo e configurar uma fonte de dados.

Configurar o aplicativo

Configure o aplicativo com o Plug-in do Maven para o Serviço de Aplicativo do Azure usando as seguintes etapas:

  1. Execute a meta de configuração do plug-in do Azure interativamente usando o seguinte comando:

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

    Importante

    Se você alterar a região do servidor MySQL, deverá corresponder essa região à região do servidor de aplicativos Jakarta EE para minimizar os atrasos de latência.

  2. Use os valores na tabela a seguir para responder aos prompts interativos:

    Elemento de entrada Valor
    Create new run configuration (Y/N) [Y]: Y
    Define value for OS [Linux]: Linux
    Define value for javaVersion [Java 17]: 1: Java 17
    Define value for runtimeStack: 3: Jbosseap 7
    Define value for pricingTier [P1v3]: P1v3
    Confirm (Y/N) [Y]: Y

    A saída a seguir é típica:

    [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] ------------------------------------------------------------------------
    

    Depois de usar o comando Maven, o exemplo a seguir é uma adição típica ao seu arquivo 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>
    
  3. Verifique o <region> elemento no seu arquivo pom.xml. Se o valor não corresponder ao local de instalação do MySQL, altere-o para o mesmo local.

  4. Use o exemplo a seguir para modificar o valor do webContainer no seu arquivo pom.xml para Jbosseap 8 no ambiente JBoss EAP 8 no Serviço de Aplicativo do Azure.

    Dica

    A partir de fevereiro de 2025, a versão mais recente disponível do JBoss EAP é a Atualização 4.1 do 8.0.

    <runtime>
        <os>Linux</os>
        <javaVersion>Java 17</javaVersion>
        <webContainer>Jbosseap 8</webContainer> <!-- Change this value -->
    </runtime>
    
  5. Adicione o XML a seguir ao elemento <resources> do arquivo pom.xml. Essa configuração é usada para implantar o arquivo de inicialização, que você atualizará posteriormente nesta unidade.

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

    O valor do recurso <type> de startup implanta o script especificado como o arquivo startup.sh para Linux ou startup.cmd para Windows. O local da implantação é /home/site/scripts/.

    Observação

    Você pode escolher a opção de implantação e o local de implantação especificando type uma das seguintes maneiras:

    • type=war implanta o arquivo WAR em /home/site/wwwroot/app.war se path não for especificado.
    • type=war&path=webapps/<appname> implanta o arquivo WAR em /home/site/wwwroot/webapps/<appname>.
    • type=jar implanta o arquivo WAR em /home/site/wwwroot/app.jar. O parâmetro path é ignorado.
    • type=ear implanta o arquivo WAR em /home/site/wwwroot/app.ear. O parâmetro path é ignorado.
    • type=lib implanta o JAR em /home/site/libs. Você deve especificar o path parâmetro.
    • type=static implanta o script em /home/site/scripts. Você deve especificar o path parâmetro.
    • type=startup implanta o script como startup.sh no Linux ou startup.cmd no Windows. O script é implantado em /home/site/scripts/. O parâmetro path é ignorado.
    • type=zip descompacta o arquivo .zip para /home/site/wwwroot. O path parâmetro é opcional.
  6. Verifique os valores dos elementos resourceGroup e appName no arquivo pom.xml.

  7. Atribua os valores para resourceGroup e appName para variáveis de ambiente usando os seguintes comandos:

    export RESOURCE_GROUP_NAME=<resource-group>
    export WEB_APP_NAME=<app-name>
    

Compilar e criar o aplicativo Jakarta EE

Depois de definir as configurações de implantação do Serviço de Aplicativo do Azure, compile e empacote o código-fonte usando o seguinte comando:

./mvnw clean package

A saída a seguir é típica:

[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] ------------------------------------------------------------------------

Implantar o aplicativo Jakarta EE no JBoss EAP no Serviço de Aplicativo do Azure

Depois de compilar e empacotar o código, implante o aplicativo usando o seguinte comando:

./mvnw azure-webapp:deploy

Você deverá ver a saída que inclui uma mensagem de êxito e a URL do aplicativo implantado. Certifique-se de salvar a URL para uso posterior.

Configurar uma conexão de banco de dados

O aplicativo de exemplo se conecta ao banco de dados MySQL e exibe dados. A configuração do projeto Maven no arquivo pom.xml especifica o driver JDBC do MySQL, conforme mostrado no exemplo a seguir:

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

Como resultado, o JBoss EAP instala automaticamente o driver ROOT.war_com.mysql.cj.jdbc.Driver_9_2 JDBC no pacote de implantação ROOT.war.

Criar o objeto MySQL DataSource no JBoss EAP

Para acessar o Banco de Dados do Azure para MySQL, você precisa configurar o DataSource objeto no JBoss EAP e especificar o nome JNDI (Java Naming and Directory Interface) no código-fonte. Para criar um objeto MySQL DataSource no JBoss EAP, use o script de shell de inicialização /WEB-INF/createMySQLDataSource.sh . O exemplo a seguir mostra uma versão não configurada do script já no Serviço de Aplicativo do 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

Observação

Ao criar a fonte de dados, você não especifica uma senha para a conexão MySQL. A variável AZURE_MYSQL_CONNECTIONSTRING de ambiente é especificada no --connection-url parâmetro. Essa variável de ambiente é definida automaticamente quando a conexão de serviço é criada posteriormente.

O valor da conexão de serviço é definido como jdbc:mysql://$MYSQL_SERVER_INSTANCE.mysql.database.azure.com:3306/world?serverTimezone=UTC&sslmode=required&user=aad_jbossapp, que usa o aad_jbossapp nome de usuário sem uma senha. Ao acrescentar &authenticationPlugins=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin a essa URL, a autenticação da ID do Microsoft Entra está habilitada para o aad_jbossapp usuário.

Configure sua instância do Serviço de Aplicativo para invocar o script de inicialização usando o seguinte comando:

az webapp config set \
    --resource-group ${RESOURCE_GROUP_NAME} \
    --name ${WEB_APP_NAME} \
    --startup-file '/home/site/scripts/startup.sh'

Depois que o script é executado, o servidor de aplicativos o invoca sempre que o servidor de aplicativos é reiniciado.

Observação

Se o artefato de implantação não estiver ROOT.war, altere o valor --driver-name=YOUR_ARTIFACT.war_com.mysql.cj.jdbc.Driver_9_2 também.

Configurar a conexão de serviço para o servidor flexível do MySQL

Depois de configurar o script de inicialização, configure o Serviço de Aplicativo para usar o Service Connector para a conexão de servidor flexível do MySQL usando as seguintes etapas:

  1. Defina variáveis de ambiente usando os seguintes comandos:

    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)
    

    As variáveis de ambiente são usadas para as seguintes finalidades:

    • PASSWORDLESS_USER_NAME_SUFFIX é o sufixo para o nome de usuário usado para se conectar ao servidor flexível MySQL. O nome de usuário criado tem o prefixo aad_ seguido pelo sufixo especificado.
    • SOURCE_WEB_APP_ID é a ID da instância do Serviço de Aplicativo do Azure usada para se conectar ao servidor flexível MySQL.
    • MYSQL_ID é a ID do servidor flexível MySQL.
    • TARGET_MYSQL_ID especifica o nome $MYSQL_ID/databases/world do banco de dados para estabelecer uma conexão com um usuário que tenha permissão para acessar o world banco de dados.
    • MANAGED_ID é a identidade gerenciada usada para se conectar ao servidor flexível MySQL.
  2. Adicione a extensão para serviceconnector-passwordless e crie a conexão de serviço usando os seguintes comandos:

    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_ID
    

    Observação

    se você receber uma mensagem de erro como Resource '********-****-****-****-************' does not exist or one of its queried reference-property objects are not present.executar novamente o comando após alguns segundos.

  3. No prompt do SQL, verifique a lista de usuários registrados no MySQL usando a seguinte consulta:

    SELECT user, host, plugin FROM mysql.user;
    

    A saída a seguir é típica:

    +----------------------------------+-----------+-----------------------+
    | 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)
    

    Você deve ver o usuário aad_jbossapp que usa o plugin aad_auth. No JBoss EAP implantado no Azure, você pode se conectar ao servidor flexível MySQL usando o aad_jbossapp nome de usuário sem senha.

Confirmar a referência do DataSource no código

Para acessar o banco de dados MySQL do seu aplicativo, você precisa configurar a referência da fonte de dados em seu projeto de aplicativo.

O código de acesso do banco de dados é implementado usando a JPA (API de Persistência java). A configuração da DataSource referência está no arquivo de configuração JPA persistence.xml.

Use as seguintes etapas para confirmar a DataSource referência:

  1. Abra o arquivo src/main/resources/META-INF/persistence.xml e verifique se o DataSource nome corresponde ao nome usado na configuração. O script de inicialização já criou o nome JNDI como java:jboss/datasources/JPAWorldDataSource, conforme mostrado no exemplo a seguir:

    <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>
    
  2. Acesse o banco de dados MySQL no nome da PersistenceContext unidade, conforme mostrado no exemplo a seguir:

    @Transactional(REQUIRED)
    @RequestScoped
    public class CityService {
    
        @PersistenceContext(unitName = "JPAWorldDatasourcePU")
        EntityManager em;
    

Acessar o aplicativo

O aplicativo de exemplo implementa três endpoints REST. Para acessar o aplicativo e recuperar dados, use as seguintes etapas:

  1. Use o navegador para navegar até a URL do aplicativo, que foi mostrada na saída quando você implantou o aplicativo.

  2. Para obter todas as informações do continente no formato JSON, use o método GET no endpoint area.

    Captura de tela do ponto de extremidade da área.

  3. Para obter todos os países e regiões em um continente especificado, use o GET método no area ponto de extremidade e especifique um continent parâmetro de caminho.

    Captura de tela do endpoint de área com parâmetro de caminho de continente.

  4. Para obter todas as cidades que têm uma população maior que um milhão dentro do país ou região especificada, use o GET método no countries ponto de extremidade e especifique um countrycode parâmetro de caminho.

    Captura de tela do ponto de extremidade de países com o parâmetro de caminho countrycode.

Resumo do exercício

Nesta unidade, você validou os pontos de extremidade REST do aplicativo e confirmou que seu aplicativo pode obter dados do banco de dados MySQL. Na próxima unidade, você examinará os logs do servidor.