연습 - Azure App Service에서 JBoss EAP에 Jakarta EE 애플리케이션 배포

완료됨

이 단원에서는 Azure App Service의 JBoss EAP(Red Hat JBoss Enterprise Application Platform)에 Jakarta EE 애플리케이션을 배포합니다. Azure App Service용 Maven 플러그 인을 사용하여 프로젝트를 구성하고, 애플리케이션을 컴파일 및 배포하고, 데이터 원본을 구성합니다.

앱 구성

다음 단계를 사용하여 Azure App Service용 Maven 플러그 인을 사용하여 앱을 구성합니다.

  1. 다음 명령을 사용하여 대화형으로 Azure 플러그 인의 구성 목표를 실행합니다.

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

    중요합니다

    MySQL 서버의 지역을 변경하는 경우 대기 시간 지연을 최소화하기 위해 해당 지역을 Jakarta EE 애플리케이션 서버의 지역과 일치시켜야 합니다.

  2. 다음 표의 값을 사용하여 대화형 프롬프트에 응답합니다.

    입력 요소 가치
    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

    다음과 같은 출력이 일반적입니다.

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

    Maven 명령을 사용한 후 다음 예제는 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. <region> 요소를 pom.xml 파일에서 확인하십시오. 해당 값이 MySQL의 설치 위치와 일치하지 않는 경우 동일한 위치로 변경합니다.

  4. webContainer 파일의 값을 Jbosseap 8로 수정하기 위해, Azure App Service의 JBoss EAP 8 환경에 다음 예제를 사용하십시오.

    팁 (조언)

    2025년 2월 현재, 사용 가능한 최신 버전의 JBoss EAP는 8.0 업데이트 4.1입니다.

    <runtime>
        <os>Linux</os>
        <javaVersion>Java 17</javaVersion>
        <webContainer>Jbosseap 8</webContainer> <!-- Change this value -->
    </runtime>
    
  5. <resources> 파일의 요소에 다음 XML을 추가합니다. 이 구성은 시작 파일을 배포하는 데 사용되며, 이 파일은 이 단원의 뒷부분에서 업데이트합니다.

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

    리소스 <type>startup 은 지정된 스크립트를 Linux용 startup.sh 파일로 배포하거나 Windows용 startup.cmd 배포합니다. 배포 위치는 /home/site/scripts/입니다.

    비고

    다음 방법 중 하나를 지정하여 type 배포 옵션 및 배포 위치를 선택할 수 있습니다.

    • type=war가 지정되지 않으면 는 WAR 파일을 path에 배포합니다.
    • type=war&path=webapps/<appname> 는 WAR 파일을 /home/site/wwwroot/webapps/<appname>에 배포합니다.
    • type=jarWAR 파일을 /home/site/wwwroot/app.jar 배포합니다. path 매개 변수는 무시됩니다.
    • type=earWAR 파일을 /home/site/wwwroot/app.ear에 배포합니다. path 매개 변수는 무시됩니다.
    • type=libJAR을 /home/site/libs에 배포합니다. 매개 변수를 지정 path 해야 합니다.
    • type=static 는 /home/site/scripts에 스크립트를 배포합니다. 매개 변수를 path 지정해야 합니다.
    • type=startup 는 스크립트를 Linux에서 startup.sh 배포하거나 Windows에서 startup.cmd 배포합니다. 스크립트는 /home/site/scripts/에 배포됩니다. path 매개 변수는 무시됩니다.
    • type=zip .zip 파일의 압축을 /home/site/wwwroot로 압축 해제합니다. path 매개 변수는 선택 사항입니다.
  6. resourceGroup 파일의 appName 요소 및 값을 확인합니다.

  7. 다음 명령을 사용하여 환경 변수에 대한 resourceGroupappName 값을 할당합니다.

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

Jakarta EE 앱 컴파일 및 빌드

Azure App Service 배포 설정을 구성한 후 다음 명령을 사용하여 소스 코드를 컴파일하고 패키지합니다.

./mvnw clean package

다음과 같은 출력이 일반적입니다.

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

Azure App Service에서 JBoss EAP에 Jakarta EE 앱 배포

코드를 컴파일하고 패키지한 후 다음 명령을 사용하여 애플리케이션을 배포합니다.

./mvnw azure-webapp:deploy

성공 메시지와 배포된 애플리케이션의 URL을 포함하는 출력이 표시됩니다. 나중에 사용할 수 있도록 URL을 따로 저장해야 합니다.

데이터베이스 연결 구성

샘플 애플리케이션은 MySQL 데이터베이스에 연결하고 데이터를 표시합니다. pom.xml 파일의 Maven 프로젝트 구성은 다음 예제와 같이 MySQL JDBC 드라이버를 지정합니다.

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

결과적으로 JBoss EAP는 배포 패키지 ROOT.war_com.mysql.cj.jdbc.Driver_9_2에 JDBC 드라이버를 자동으로 설치합니다.

JBoss EAP에서 MySQL DataSource 개체 만들기

Azure Database for MySQL에 액세스하려면 JBoss EAP에서 개체를 구성 DataSource 하고 소스 코드에서 JNDI(Java Naming and Directory Interface) 이름을 지정해야 합니다. JBoss EAP에서 MySQL DataSource 개체를 만들려면 /WEB-INF/createMySQLDataSource.sh 시작 셸 스크립트를 사용합니다. 다음 예제에서는 Azure App Service에 이미 구성되지 않은 스크립트 버전을 보여줍니다.

#!/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

비고

데이터 원본을 만들 때 MySQL 연결에 대한 암호를 지정하지 않습니다. 환경 변수 AZURE_MYSQL_CONNECTIONSTRING--connection-url 매개 변수로 지정됩니다. 이 환경 변수는 서비스 연결이 나중에 만들어지면 자동으로 설정됩니다.

서비스 연결 값은 암호 없이 사용자 이름을 사용하는 jdbc:mysql://$MYSQL_SERVER_INSTANCE.mysql.database.azure.com:3306/world?serverTimezone=UTC&sslmode=required&user=aad_jbossapp 값으로 설정aad_jbossapp됩니다. 이 URL에 &authenticationPlugins=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin을(를) 추가하면, aad_jbossapp 사용자의 Microsoft Entra ID 인증이 활성화됩니다.

다음 명령을 사용하여 시작 스크립트를 호출하도록 App Service 인스턴스를 구성합니다.

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

스크립트가 실행되면 애플리케이션 서버는 애플리케이션 서버를 다시 시작할 때마다 호출합니다.

비고

배포 아티팩트가 ROOT.war이 아니면 --driver-name=YOUR_ARTIFACT.war_com.mysql.cj.jdbc.Driver_9_2 값을 바꾸세요.

MySQL 유연한 서버에 대한 서비스 연결 구성

시작 스크립트를 구성한 후 다음 단계를 사용하여 MySQL 유연한 서버 연결에 Service Connector를 사용하도록 App Service를 구성합니다.

  1. 다음 명령을 사용하여 환경 변수를 설정합니다.

    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)
    

    환경 변수는 다음과 같은 용도로 사용됩니다.

    • PASSWORDLESS_USER_NAME_SUFFIX 는 MySQL 유연한 서버에 연결하는 데 사용되는 사용자 이름의 접미사입니다. 만든 사용자 이름에는 접두 aad_ 사 뒤에 지정된 접미사가 있습니다.
    • SOURCE_WEB_APP_ID 는 MySQL 유연한 서버에 연결하는 데 사용되는 Azure App Service 인스턴스의 ID입니다.
    • MYSQL_ID 는 MySQL 유연한 서버의 ID입니다.
    • TARGET_MYSQL_ID$MYSQL_ID/databases/world를 데이터베이스 이름으로 지정하여 world 데이터베이스에 접근 권한이 있는 사용자와의 연결을 설정합니다.
    • MANAGED_ID 는 MySQL 유연한 서버에 연결하는 데 사용되는 관리 ID입니다.
  2. 다음 명령을 사용하여 확장 serviceconnector-passwordless 명을 추가하고 서비스 연결을 만듭니다.

    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
    

    비고

    다음과 같은 Resource '********-****-****-****-************' does not exist or one of its queried reference-property objects are not present.오류 메시지가 표시되면 몇 초 후에 명령을 다시 실행합니다.

  3. SQL 프롬프트에서 다음 쿼리를 사용하여 MySQL에 등록된 사용자 목록을 확인합니다.

    SELECT user, host, plugin FROM mysql.user;
    

    다음과 같은 출력이 일반적입니다.

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

    aad_jbossapp 사용자가 aad_auth 플러그 인을 사용하는 것이 표시됩니다. Azure에 배포된 JBoss EAP에서 암호 없이 사용자 이름을 사용하여 aad_jbossapp MySQL 유연한 서버에 연결할 수 있습니다.

코드에서 DataSource 참조 확인

애플리케이션에서 MySQL 데이터베이스에 액세스하려면 애플리케이션 프로젝트에서 데이터 원본 참조를 구성해야 합니다.

데이터베이스 액세스 코드는 JPA(Java Persistence API)를 사용하여 구현됩니다. 참조 구성은 JPA 구성 파일 DataSource에 있습니다.

다음 단계를 사용하여 참조를 확인합니다: DataSource.

  1. src/main/resources/META-INF/persistence.xml 파일을 열고 이름이 구성에 사용된 이름과 일치하는지 DataSource 확인합니다. 시작 스크립트는 다음 예제와 같이 java:jboss/datasources/JPAWorldDataSourceJNDI 이름을 이미 만들었습니다.

    <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. 다음 예제와 PersistenceContext 같이 단위 이름으로 MySQL 데이터베이스에 액세스합니다.

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

애플리케이션 액세스

샘플 애플리케이션은 세 개의 REST 엔드포인트를 구현합니다. 애플리케이션에 액세스하고 데이터를 검색하려면 다음 단계를 사용합니다.

  1. 브라우저를 사용하여 애플리케이션을 배포할 때 출력에 표시된 애플리케이션 URL로 이동합니다.

  2. JSON 형식의 모든 대륙 정보를 얻으려면 엔드포인트에서 GET 메서드를 area 사용합니다.

    영역 엔드포인트의 스크린샷.

  3. 지정된 대륙의 모든 국가 및 지역을 얻으려면 엔드포인트에서 GET 메서드를 area 사용하고 경로 매개 변수를 continent 지정합니다.

    대륙 경로 매개 변수가 있는 영역 엔드포인트의 스크린샷

  4. 지정된 국가 또는 지역 내에서 100만 명 이상의 인구가 있는 모든 도시를 얻으려면 엔드포인트에서 메서드를 GET 사용하고 countries 경로 매개 변수를 countrycode 지정합니다.

    countrycode 경로 매개 변수가 있는 국가 엔드포인트의 스크린샷

연습 요약

이 단원에서는 애플리케이션 REST 엔드포인트의 유효성을 검사하고 애플리케이션이 MySQL 데이터베이스에서 데이터를 가져올 수 있는지 확인했습니다. 다음 단원에서는 서버 로그를 검사합니다.