연습 - Azure App Service의 JBoss EAP에 Java EE(Jakarta EE) 애플리케이션 배포
이 연습에서는 Azure App Service의 JBoss EAP에 Java EE(Jakarta EE) 애플리케이션을 배포합니다. 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 -->
참고
XML에 배포할 다음 리소스를 지정할 수 있습니다.
type=<war|jar|ear|lib|startup|static|zip>
type=war
은path
가 지정되지 않은 경우 war 파일을/home/site/wwwroot/app.war
에 배포합니다.- /home/site/wwwroot/webapps/<appname>에 앱의 압축을 풀면
type=war&path=webapps/<appname>\
은 wardeploy와 똑같이 작동합니다. type=jar
은 war 파일을/home/site/wwwroot/app.jar
에 배포합니다.path
매개 변수는 무시됩니다.type=ear
은 war 파일을/home/site/wwwroot/app.ear
에 배포합니다.path
매개 변수는 무시됩니다.type=lib
는 /home/site/libs에 jar을 배포합니다.path
매개 변수를 지정해야 합니다.type=static
은 스크립트를/home/site/scripts
에 배포합니다.path
매개 변수를 지정해야 합니다.type=startup
은startup.sh
(Linux) 또는startup.cmd
(Windows)로 스크립트를/home/site/scripts/
에 배포합니다.path
매개 변수는 무시됩니다.type=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] ------------------------------------------------------------------------
Azure App Service의 JBoss EAP에 Java EE 앱 배포
코드를 컴파일하고 패키지한 후 애플리케이션을 배포합니다.
./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>
따라서 JBoss EAP는 배포 패키지(ROOT.war
)에 JDBC 드라이버를 자동으로 설치합니다. 다음과 같이 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
입니다.
참고
스크립트에서 JBoss CLI 명령을 사용하여 MySQL DataSource를 바인딩합니다. 연결 문자열, 사용자 이름 및 암호는 환경 변수 MYSQL_CONNECTION_URL
, MYSQL_USER
및 MYSQL_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}
스크립트가 실행된 후 애플리케이션 서버가 다시 시작될 때마다 호출됩니다.
참고
배포 아티팩트가 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_URL
, MYSQL_USER
및 MYSQL_PASSWORD
의 값은 이전 단원에서 설정되었습니다.
코드에서 DataSource 참조를 확인합니다.
애플리케이션에서 MySQL 데이터베이스에 액세스하려면 애플리케이션 프로젝트에서 데이터 원본 참조를 구성해야 합니다. JPA(Java Persistence API)를 사용하여 데이터베이스 액세스 코드를 구현했습니다.
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;
애플리케이션 액세스
애플리케이션 예제에서 세 개의 REST 엔드포인트를 구현했습니다. 웹 브라우저나 curl
명령을 사용하여 애플리케이션에 액세스하고 해당 엔드포인트의 유효성을 검사할 수 있습니다.
애플리케이션에 액세스하려면 이전 섹션에서 가져온 애플리케이션 URL을 참조해야 합니다.
[INFO] Successfully deployed the artifact to
https://jakartaee-app-on-jboss-1606464084546.azurewebsites.net
다음 명령을 실행하여 JSON 형식의 모든 대륙 정보를 가져옵니다.
$ curl https://${WEBAPP_NAME}.azurewebsites.net/area
["North America","Asia","Africa","Europe","South America","Oceania","Antarctica"]$
URL에서 대륙을 지정하는 경우 지정된 대륙의 모든 국가/지역을 가져올 수 있습니다.
$ 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만 명을 초과하는 모든 도시를 가져올 수 있습니다.
$ 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 데이터베이스에서 데이터를 가져올 수 있는지 테스트했습니다.
다음 단원에서는 서버 로그를 검사합니다.