services | platforms | author |
---|---|---|
app-service, PostgreSQL, MySQL |
java |
selvasingh, sadigopu |
This guide walks you through the process of migrating an existing Java EE workload to Azure, aka:
- Java EE app to App Service Linux and
- App's data to Azure Database for PostgreSQL, MySQL and or SQL Database.
- Migrate Java EE App to Azure
- What you will migrate to cloud
- What you will need
- Getting Started
- Build and Deploy Pet Store Powered Using H2
- Build and Deploy Pet Store Powered Using Azure Database for PostgreSQL
- Build and Deploy Pet Store Powered Using Azure Database for MySQL
- Build and Deploy Pet Store Powered Using Azure SQL Database
- Scale out the Pet Store app
- Congratulations!
- Resources
You will migrate the famous Sun's 2003 Java EE Blue Print sample app. The most recent incarnation of the sample uses:
- Java SE 8
- Java EE 7
- JSR 338 Java Persistence API (JPA 2.2)
- JSR 346 Context and Dependency Injection (CDI 1.1)
- JSR 345 Enterprise Java Beans 3.2 (EJB 3.2)
- JSR 344 Java Server Faces (JSF 2.2)
- JSR 339 Java API for RESTful Web Services (JAX-RS 2.0)
- Twitter Bootstrap (Bootstrap 3.x, JQuery 2.x, PrimeFaces 6.x)
Upon migration, you will power the app using Azure Database for PostgreSQL, MySQL and or SQL Database.
In order to deploy a Java Web app to cloud, you need an Azure subscription. If you do not already have an Azure subscription, you can activate your MSDN subscriber benefits or sign up for a free Azure account.
In addition, you will need the following:
| Azure CLI | Java 8 | Maven 3 | Git | PostgreSQL CLI | MySQL CLI | SQLCMD CLI |
You can start from scratch and complete each step, or you can bypass basic setup steps that you are already familiar with. Either way, you will end up with working code.
When you are finished, you can check your results against YOUR code in migrate-Java-EE-app-to-azure/complete.
You can start from migrate-Java-EE-app-to-azure/initial-h2. Or, you can clone from agoncal-application-petstore-ee7
git clone --recurse-submodules https://github.com/Azure-Samples/migrate-Java-EE-app-to-azure.git
cd migrate-Java-EE-app-to-azure
yes | cp -rf .prep/* .
Open the initial-h2/agoncal-application-petstore-ee7 sample app in your favorite IDE - IntelliJ | Eclipse | VS Code.
cd initial-h2/agoncal-application-petstore-ee7
bash-3.2$ mvn package -Dmaven.test.skip=true
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Petstore application using Java EE 7 7.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ petstoreee7 ---
...
...
[INFO] --- maven-war-plugin:3.1.0:war (default-war) @ petstoreee7 ---
[INFO] Packaging webapp
[INFO] Assembling webapp [petstoreee7] in [/Users/selvasingh/migrate-Java-EE-app-to-azure/initial-h2/agoncal-application-petstore-ee7/target/applicationPetstore]
[INFO] Processing war project
[INFO] Copying webapp resources [/Users/selvasingh/migrate-Java-EE-app-to-azure/initial-h2/agoncal-application-petstore-ee7/src/main/webapp]
[INFO] Webapp assembled in [440 msecs]
[INFO] Building war: /Users/selvasingh/migrate-Java-EE-app-to-azure/initial-h2/agoncal-application-petstore-ee7/target/applicationPetstore.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.340 s
[INFO] Finished at: 2018-12-21T14:46:35-08:00
[INFO] Final Memory: 33M/326M
[INFO] ------------------------------------------------------------------------
Login to Azure by using the 'az login' command and follow the instructions that give a device code to be entered in browser
az login
Set environment variables for binding secrets at runtime, particularly Azure resource group and Web app names. You can export them to your local environment, say using the supplied Bash shell script template.
mkdir .scripts
cp set-env-variables-template.sh .scripts/set-env-variables.sh
Modify .scripts/set-env-variables.sh
and set Azure Resource Group name,
App Service Web App Name, Azure Region and JBoss EAP directory in
the local machine. Then, set environment variables:
source .scripts/set-env-variables.sh
az account set -s ${SUBSCRIPTION}
Add Maven Plugin for Azure App Service configuration to POM.xml and deploy Pet Store to JBoss EAP in App Service Linux:
<plugins>
<!--*************************************************-->
<!-- Deploy to JBoss EAP in App Service Linux -->
<!--*************************************************-->
<plugin>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-webapp-maven-plugin</artifactId>
<version>1.12.0</version>
<configuration>
<schemaVersion>v2</schemaVersion>
<subscriptionId>${SUBSCRIPTION}</subscriptionId>
<resourceGroup>${RESOURCEGROUP_NAME}</resourceGroup>
<appName>${WEBAPP_NAME}</appName>
<pricingTier>P1v2</pricingTier>
<region>${REGION}</region>
<runtime>
<os>Linux</os>
<javaVersion>Java 8</javaVersion>
<webContainer>Jbosseap 7.2</webContainer>
</runtime>
<deployment>
<resources>
<resource>
<directory>${project.basedir}/target</directory>
<includes>
<include>*.war</include>
</includes>
</resource>
</resources>
</deployment>
</configuration>
</plugin>
...
</plugins>
Deploy to App Service Linux:
mvn azure-webapp:deploy
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Petstore application using Java EE 7 7.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- azure-webapp-maven-plugin:1.12.0:deploy (default-cli) @ petstoreee7 ---
[INFO] Authenticate with Azure CLI 2.0
[INFO] Target Web App doesn't exist. Creating a new one...
[INFO] Creating App Service Plan 'petstore-java-ee-appservice-plan'...
[INFO] Successfully created App Service Plan.
[INFO] Successfully created Web App.
[INFO] Trying to deploy artifact to petstore-java-ee...
[INFO] Deploying the war file...
[INFO] Successfully deployed the artifact to https://petstore-java-ee.azurewebsites.net
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:19 min
[INFO] Finished at: 2018-12-21T14:51:08-08:00
[INFO] Final Memory: 61M/628M
[INFO] ------------------------------------------------------------------------
open https://petstore-java-ee.azurewebsites.net
When you are finished, you can check your results against YOUR code in migrate-Java-EE-app-to-azure/initial-postgresql.
Start your next leg of your journey ... change directory:
cd ../../initial-postgresql/agoncal-application-petstore-ee7
Add a new profile for PostgreSQL in pom.xml
:
<profile>
<id>postgresql</id>
<activation>
<property>
<name>db</name>
<value>postgresql</value>
</property>
</activation>
<build>
<plugins>
<!-- copy the correct persistence.xml file -->
<plugin>
<groupId>com.coderplus.maven.plugins</groupId>
<artifactId>copy-rename-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>copy-file</id>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<sourceFile>${project.basedir}/main/resources/META-INF/persistence-postgresql.xml</sourceFile>
<destinationFile>${project.basedir}/src/main/resources/META-INF/persistence.xml</destinationFile>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
cp set-env-variables-template.sh .scripts/set-env-variables.sh
Modify .scripts/set-env-variables.sh
and set Azure Resource Group name,
App Service Web App Name, Azure Region, FTP details in
the local machine and PostgreSQL server info. Make sure to pick a password that adheres to the following rules :
Your password must be at least 8 characters in length.
Your password must contain characters from three of the following categories โ English uppercase letters, English lowercase letters, numbers (0-9), and non-alphanumeric characters (!, $, #, %, etc.)
Your password can not contain all or part of the username ( 3 or more consecutive alphanumeric characters)
Get the FTP details by using the webapp and resource group created in the previous H2-based lab, with the following command, which displays profile values
az webapp deployment list-publishing-profiles -g ${RESOURCEGROUP_NAME} -n ${WEBAPP_NAME}
{
...
...
"profileName": "petstore-java-ee - FTP",
"publishMethod": "FTP",
"publishUrl": "ftp://waws-prod-bay-063.ftp.azurewebsites.windows.net/site/wwwroot",
"userName": "petstore-java-ee\\$petstore-java-ee",
"userPWD": "============MASKED===========================================",
"webSystem": "WebSites"
}
Store FTP host name, say waws-prod-bay-063.ftp.azurewebsites.windows.net
, user name and user password in .scripts/set-env-variables.sh file.
Note the ip of the local machine
curl ifconfig.me
Then, set environment variables:
source .scripts/set-env-variables.sh
Create a Petstore DB using Azure CLI and PostgreSQL CLI:
az postgres server create --resource-group ${RESOURCEGROUP_NAME} \
--name ${POSTGRES_SERVER_NAME} \
--location ${REGION} \
--admin-user ${POSTGRES_SERVER_ADMIN_LOGIN_NAME} \
--admin-password ${POSTGRES_SERVER_ADMIN_PASSWORD} \
--sku-name GP_Gen5_2
az postgres server firewall-rule create \
--resource-group ${RESOURCEGROUP_NAME} \
--server ${POSTGRES_SERVER_NAME} --name allAzureIPs \
--start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0
curl ifconfig.me
az postgres server firewall-rule create \
--resource-group ${RESOURCEGROUP_NAME} \
--server ${POSTGRES_SERVER_NAME} --name myDevBox \
--start-ip-address ${DEVBOX_IP_ADDRESS} --end-ip-address ${DEVBOX_IP_ADDRESS}
psql --host=${POSTGRES_SERVER_FULL_NAME} --port=5432 \
--username=${POSTGRES_SERVER_ADMIN_FULL_NAME} \
--dbname=${POSTGRES_DATABASE_NAME} --set=sslmode=require
Password for user postgres@petstore-db:
psql (11.1, server 9.6.10)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-SHA384, bits: 256, compression: off)
Type "help" for help.
postgres=> \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-------------------+-----------------+----------+----------------------------+----------------------------+-------------------------------------
azure_maintenance | azure_superuser | UTF8 | English_United States.1252 | English_United States.1252 | azure_superuser=CTc/azure_superuser
azure_sys | azure_superuser | UTF8 | English_United States.1252 | English_United States.1252 |
postgres | azure_superuser | UTF8 | English_United States.1252 | English_United States.1252 |
template0 | azure_superuser | UTF8 | English_United States.1252 | English_United States.1252 | =c/azure_superuser +
| | | | | azure_superuser=CTc/azure_superuser
template1 | azure_superuser | UTF8 | English_United States.1252 | English_United States.1252 | =c/azure_superuser +
| | | | | azure_superuser=CTc/azure_superuser
(5 rows)
postgres=> \q
Note - you can install psql
command line tool using brew reinstall postgresql
.
When you migrate Java workloads to cloud, you will be considering moving data to cloud. To accelerate your transition to cloud, Azure offers plenty of options to migrate your data to cloud.
Also, for your convenience, there is a cheat sheet for PostgreSQL CLI.
There are 5 steps to configure a data source. These steps are similar to configuring data sources in any on premise Java EE app servers:
In App Service, each instance of an app server is stateless. Therefore, each instance must be
configured on startup to support a JBoss EAP configuration needed by your application. You can configure at
startup by supplying a startup Bash script that calls JBoss/WildFly CLI commands to setup data sources, messaging
providers and any other dependencies. We will create a startup.sh script and place it in the /home
directory of the Web app. The script will:
Install a JBoss EAP module:
# where resources point to JDBC driver for PostgreSQL
# and module xml points to module description, see below
module add --name=org.postgres --resources=/home/site/deployments/tools/postgresql-42.2.5.jar --module-xml=/home/site/deployments/tools/postgresql-module.xml
Where postgresql-module.xml
describes the module:
<?xml version="1.0" ?>
<module xmlns="urn:jboss:module:1.1" name="org.postgres">
<resources>
<!-- ***** IMPORTANT : PATH should point to PostgreSQL Java driver on App Service Linux *******-->
<resource-root path="/home/site/deployments/tools/postgresql-42.2.5.jar" />
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
Add a JDBC driver for PostgreSQL:
/subsystem=datasources/jdbc-driver=postgres:add(driver-name="postgres",driver-module-name="org.postgres",driver-class-name=org.postgresql.Driver,driver-xa-datasource-class-name=org.postgresql.xa.PGXADataSource)
Install a data source by using the data-source shortcut command:
data-source add --name=postgresDS --driver-name=postgres --jndi-name=java:jboss/datasources/postgresDS --connection-url=${POSTGRES_CONNECTION_URL,env.POSTGRES_CONNECTION_URL:jdbc:postgresql://db:5432/postgres} --user-name=${POSTGRES_SERVER_ADMIN_FULL_NAME,env.POSTGRES_SERVER_ADMIN_FULL_NAME:postgres} --password=${POSTGRES_SERVER_ADMIN_PASSWORD,env.POSTGRES_SERVER_ADMIN_PASSWORD:example} --use-ccm=true --max-pool-size=5 --blocking-timeout-wait-millis=5000 --enabled=true --driver-class=org.postgresql.Driver --exception-sorter-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter --jta=true --use-java-context=true --valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker
A server reload may be required for the changes to take effect:
reload --use-current-server-config=true
These JBoss CLI commands, JDBC driver for PostgreSQL and module XML are available in initial-postgresql/agoncal-application-petstore-ee7/.scripts
Also, you can directly download the latest version of JDBC driver for PostgreSQL
Open an FTP connection to App Service Linux to upload data source artifacts:
pwd
/Users/selvasingh/migrate-Java-EE-app-to-azure/initial-postgresql/agoncal-application-petstore-ee7
cd .scripts
ftp
ftp> open waws-prod-bay-063.drip.azurewebsites.windows.net
Trying 23.99.84.148...
Connected to waws-prod-bay-063.drip.azurewebsites.windows.net.
220 Microsoft FTP Service
Name (waws-prod-bay-063.drip.azurewebsites.windows.net:selvasingh):
331 Password required
Password:
230 User logged in.
Remote system type is Windows_NT.
ftp> ascii
200 Type set to A.
ftp> passive
# Upload startup.sh to /home directory
ftp> put startup.sh
local: startup.sh remote: startup.sh
229 Entering Extended Passive Mode (|||10204|)
125 Data connection already open; Transfer starting.
100% |************************************************| 236 39.33 KiB/s --:-- ETA
226 Transfer complete.
236 bytes sent in 00:00 (5.01 KiB/s)
# Upload CLI Commands, Module XML and JDBC Driver for PostgreSQL to /home/site/deployments/tools
ftp> cd site/deployments/tools
250 CWD command successful.
ftp> put postgresql-datasource-commands.cli
local: postgresql-datasource-commands.cli remote: postgresql-datasource-commands.cli
229 Entering Extended Passive Mode (|||10205|)
125 Data connection already open; Transfer starting.
100% |************************************************| 1444 234.94 KiB/s --:-- ETA
226 Transfer complete.
1444 bytes sent in 00:00 (32.31 KiB/s)
ftp> put postgresql-module.xml
local: postgresql-module.xml remote: postgresql-module.xml
229 Entering Extended Passive Mode (|||10206|)
125 Data connection already open; Transfer starting.
100% |************************************************| 404 192.17 KiB/s --:-- ETA
226 Transfer complete.
404 bytes sent in 00:00 (5.86 KiB/s)
ftp> binary
200 Type set to I.
ftp> put postgresql-42.2.5.jar
local: postgresql-42.2.5.jar remote: postgresql-42.2.5.jar
229 Entering Extended Passive Mode (|||10207|)
125 Data connection already open; Transfer starting.
100% |************************************************| 806 KiB 506.52 KiB/s 00:00 ETA
226 Transfer complete.
825943 bytes sent in 00:01 (469.59 KiB/s)
ftp> bye
221 Goodbye.
Use Azure CLI to set database connection info:
az webapp config appsettings set \
--resource-group ${RESOURCEGROUP_NAME} --name ${WEBAPP_NAME} \
--settings \
POSTGRES_CONNECTION_URL=${POSTGRES_CONNECTION_URL} \
POSTGRES_SERVER_ADMIN_PASSWORD=${POSTGRES_SERVER_ADMIN_PASSWORD} \
POSTGRES_SERVER_ADMIN_FULL_NAME=${POSTGRES_SERVER_ADMIN_FULL_NAME}
[
{
"name": "WEBSITE_HTTPLOGGING_RETENTION_DAYS",
"slotSetting": false,
"value": "3"
},
{
"name": "POSTGRES_CONNECTION_URL",
"slotSetting": false,
"value": "jdbc:postgresql://petstore-db.postgres.database.azure.com:5432/postgres?ssl=true"
},
{
"name": "POSTGRES_SERVER_ADMIN_PASSWORD",
"slotSetting": false,
"value": "======= MASKED ======="
},
{
"name": "POSTGRES_SERVER_ADMIN_FULL_NAME",
"slotSetting": false,
"value": "postgres@petstore-db"
}
]
az webapp config set --startup-file /home/startup.sh \
--resource-group ${RESOURCEGROUP_NAME} --name ${WEBAPP_NAME}
You can test Bash script for configuring data source by running them on App Service Linux by opening an SSH connection from your development machine:
# ======== first terminal window =========
az webapp create-remote-connection --resource-group ${RESOURCEGROUP_NAME} --name ${WEBAPP_NAME} &
[18] 7422
bash-3.2$ Auto-selecting port: 60029
SSH is available { username: root, password: Docker! }
Start your favorite client and connect to port 60029
Websocket tracing disabled, use --verbose flag to enable
Successfully connected to local server..
# ======== second terminal window ========
ssh root@localhost -p 60029
The authenticity of host '[localhost]:60029 ([127.0.0.1]:60029)' can't be established.
ECDSA key fingerprint is SHA256:Lys3Kd4sNJc7X8LVMRP89GKbOzlOGp03tGYj+mY4Kic.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:60029' (ECDSA) to the list of known hosts.
root@localhost's password:
_____
/ _ \ __________ _________ ____
/ /_\ \___ / | \_ __ \_/ __ \
/ | \/ /| | /| | \/\ ___/
\____|__ /_____ \____/ |__| \___ >
\/ \/ \/
A P P S E R V I C E O N L I N U X
Documentation: http://aka.ms/webapp-linux
c315a18b39d2:/home#
# ======== run JBoss/WildFly CLI commands to configure a data source ===========
c315a18b39d2:/home# /opt/eap/bin/jboss-cli.sh --connect
Picked up _JAVA_OPTIONS: -Djava.net.preferIPv4Stack=true
[standalone@localhost:9990 /] module add --name=org.postgres --resources=/home/site/deployments/tools/postgresql-42.2.5.jar --module-xml=/home/site/deployments/tools/postgresql-module.xml
[standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=postgres:add(driver-name="postgres",driver-module-name="org.postgres",driver-class-name=org.postgresql.Driver,driver-xa-datasource-class-name=org.postgresql.xa.PGXADataSource)
{"outcome" => "success"}
[standalone@localhost:9990 /] data-source add --name=postgresDS --driver-name=postgres --jndi-name=java:jboss/datasources/postgresDS --connection-url=${POSTGRES_CONNECTION_URL,env.POSTGRES_CONNECTION_URL:jdbc:postgresql://db:5432/postgres} --user-name=${POSTGRES_SERVER_ADMIN_FULL_NAME,env.POSTGRES_SERVER_ADMIN_FULL_NAME:postgres} --password=${POSTGRES_SERVER_ADMIN_PASSWORD,env.POSTGRES_SERVER_ADMIN_PASSWORD:example} --use-ccm=true --max-pool-size=5 --blocking-timeout-wait-millis=5000 --enabled=true --driver-class=org.postgresql.Driver --exception-sorter-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter --jta=true --use-java-context=true --valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker
[standalone@localhost:9990 /] /subsystem=datasources/data-source=postgresDS:test-connection-in-pool()
{
"outcome" => "success",
"result" => [true]
}
# ====== run JBoss/WildFly CLI commands to undo data source configuration ========
/subsystem=datasources:read-resource
/subsystem=datasources:installed-drivers-list
module remove --name=org.postgres # --name=com.mysql --name=com.microsoft
data-source remove --name=postgresDS # --name=mysqlDS --name=sqlDS
reload --use-current-server-config=true
/subsystem=datasources/jdbc-driver=postgres:remove # jdbc-driver=mysql jdbc-driver-sqlserver
Use Azure CLI to restart the remote JBoss EAP app server:
az webapp stop -g ${RESOURCEGROUP_NAME} -n ${WEBAPP_NAME}
az webapp start -g ${RESOURCEGROUP_NAME} -n ${WEBAPP_NAME}
For additional info, please refer to:
- JBoss Data Source Management.
- JBoss/WildFly CLI Guide
- Open SSH session from your development machine to App Service Linux
# Use the Maven profile for PostgreSQL to build
mvn package -Dmaven.test.skip=true -Ddb=postgresql
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Petstore application using Java EE 7 7.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- copy-rename-maven-plugin:1.0:copy (copy-file) @ petstoreee7 ---
[INFO] Copied /Users/selvasingh/migrate-Java-EE-app-to-azure/initial-postgresql/agoncal-application-petstore-ee7/src/main/resources/META-INF/persistence-postgresql.xml to /Users/selvasingh/migrate-Java-EE-app-to-azure/initial-postgresql/agoncal-application-petstore-ee7/src/main/resources/META-INF/persistence.xml
...
...
[INFO] --- maven-war-plugin:3.1.0:war (default-war) @ petstoreee7 ---
[INFO] Packaging webapp
[INFO] Assembling webapp [petstoreee7] in [/Users/selvasingh/migrate-Java-EE-app-to-azure/initial-postgresql/agoncal-application-petstore-ee7/target/applicationPetstore]
[INFO] Processing war project
[INFO] Copying webapp resources [/Users/selvasingh/migrate-Java-EE-app-to-azure/initial-postgresql/agoncal-application-petstore-ee7/src/main/webapp]
[INFO] Webapp assembled in [243 msecs]
[INFO] Building war: /Users/selvasingh/migrate-Java-EE-app-to-azure/initial-postgresql/agoncal-application-petstore-ee7/target/applicationPetstore.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.161 s
[INFO] Finished at: 2018-12-21T16:27:42-08:00
[INFO] Final Memory: 31M/513M
[INFO] ------------------------------------------------------------------------
Deploy to JBoss EAP in App Service Linux:
mvn azure-webapp:deploy
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Petstore application using Java EE 7 7.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- azure-webapp-maven-plugin:1.12.0:deploy (default-cli) @ petstoreee7 ---
[INFO] Authenticate with Azure CLI 2.0
[INFO] Updating target Web App...
[INFO] Successfully updated Web App.
[INFO] Trying to deploy artifact to petstore-java-ee...
[INFO] Deploying the war file...
[INFO] Successfully deployed the artifact to https://petstore-java-ee.azurewebsites.net
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 04:07 min
[INFO] Finished at: 2018-12-21T16:45:12-08:00
[INFO] Final Memory: 60M/631M
[INFO] ------------------------------------------------------------------------
open https://petstore-java-ee.azurewebsites.net
psql --host=${POSTGRES_SERVER_FULL_NAME} --port=5432 \
--username=${POSTGRES_SERVER_ADMIN_FULL_NAME} \
--dbname=${POSTGRES_DATABASE_NAME} --set=sslmode=require
Password for user postgres@petstore-db:
psql (11.1, server 9.6.10)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-SHA384, bits: 256, compression: off)
Type "help" for help.
postgres=> \l
postgres=> \dt
List of relations
Schema | Name | Type | Owner
--------+--------------------+-------+----------
public | category | table | postgres
public | country | table | postgres
public | customer | table | postgres
public | item | table | postgres
public | order_line | table | postgres
public | product | table | postgres
public | purchase_order | table | postgres
public | t_order_order_line | table | postgres
(8 rows)
postgres=> select name from category;
name
----------
Fish
Dogs
Reptiles
Cats
Birds
(5 rows)
postgres=> \q
bash-3.2$
Configure logs for the deployed Java Web app in App Service Linux:
az webapp log config --name ${WEBAPP_NAME} \
--resource-group ${RESOURCEGROUP_NAME} \
--web-server-logging filesystem
Open Java Web app remote log stream from a local machine:
az webapp log tail --name ${WEBAPP_NAME} \
--resource-group ${RESOURCEGROUP_NAME}
When you are finished, you can check your results against YOUR code in migrate-Java-EE-app-to-azure/initial-mysql.
Start your next leg of your journey ... change directory:
cd ../../initial-mysql/agoncal-application-petstore-ee7
Add a new profile for MySQL in pom.xml
:
<profile>
<id>mysql</id>
<activation>
<property>
<name>db</name>
<value>mysql</value>
</property>
</activation>
<build>
<plugins>
<!-- copy the MySQL persistence.xml file -->
<plugin>
<groupId>com.coderplus.maven.plugins</groupId>
<artifactId>copy-rename-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>copy-file</id>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<sourceFile>${project.basedir}/main/resources/META-INF/persistence-mysql.xml</sourceFile>
<destinationFile>${project.basedir}/src/main/resources/META-INF/persistence.xml</destinationFile>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
cp set-env-variables-template.sh .scripts/set-env-variables.sh
Modify .scripts/set-env-variables.sh
and set Azure Resource Group name,
App Service Web App Name, Azure Region, JBoss EAP directory in
the local machine, FTP deployment credentials and MySQL server info.
Then, set environment variables:
source .scripts/set-env-variables.sh
Create a Petstore DB using Azure CLI and MySQL CLI:
az mysql server create --resource-group ${RESOURCEGROUP_NAME} \
--name ${MYSQL_SERVER_NAME} --location westus2 \
--admin-user ${MYSQL_SERVER_ADMIN_LOGIN_NAME} \
--admin-password ${MYSQL_SERVER_ADMIN_PASSWORD} \
--sku-name GP_Gen5_32 \
--ssl-enforcement Disabled \
--version 5.7
// allow access from Azure resources
az mysql server firewall-rule create --name allAzureIPs \
--server ${MYSQL_SERVER_NAME} \
--resource-group ${RESOURCEGROUP_NAME} \
--start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0
// allow access from your dev machine for testing
az mysql server firewall-rule create --name myDevBox \
--server ${MYSQL_SERVER_NAME} \
--resource-group ${RESOURCEGROUP_NAME} \
--start-ip-address ${DEVBOX_IP_ADDRESS} --end-ip-address ${DEVBOX_IP_ADDRESS}
// increase connection timeout
az mysql server configuration set --name wait_timeout \
--resource-group ${RESOURCEGROUP_NAME} \
--server ${MYSQL_SERVER_NAME} --value 2147483
// log into mysql
mysql -u ${MYSQL_SERVER_ADMIN_FULL_NAME} -h ${MYSQL_SERVER_FULL_NAME} -P 3306 -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 64096
Server version: 5.6.39.0 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> CREATE DATABASE petstore;
Query OK, 1 row affected (0.05 sec)
mysql> CREATE USER 'root' IDENTIFIED BY 'petstore';
Query OK, 0 rows affected (0.04 sec)
mysql> GRANT ALL PRIVILEGES ON petstore.* TO 'root';
Query OK, 0 rows affected (0.05 sec)
mysql> CALL mysql.az_load_timezone();
Query OK, 3179 rows affected, 1 warning (6.34 sec)
mysql> SELECT name FROM mysql.time_zone_name;
...
mysql> quit
Bye
az mysql server configuration set --name time_zone \
--resource-group ${RESOURCEGROUP_NAME} \
--server ${MYSQL_SERVER_NAME} --value "US/Pacific"
When you migrate Java workloads to cloud, you will be considering moving data to cloud. To accelerate your transition to cloud, Azure offers plenty of options to migrate your data to cloud.
Also, for your convenience, there is a cheat sheet for MySQL CLI.
There are 5 steps to configure a data source. These steps are similar to configuring data sources in any on premise Java EE app servers:
In App Service, each instance of an app server is stateless. Therefore, each instance must be
configured on startup to support a JBoss EAP configuration needed by your application. You can configure at
startup by supplying a startup Bash script that calls JBoss/WildFly CLI commands to setup data sources, messaging
providers and any other dependencies. We will create a startup.sh script and place it in the /home
directory of the Web app. The script will:
Install a JBoss EAP module:
# where resources point to JDBC driver for MySQL
# and module xml points to module description, see below
module add --name=com.mysql --resources=/home/site/deployments/tools/mysql-connector-java-8.0.13.jar --module-xml=/home/site/deployments/tools/mysql-module.xml
Where mysql-module.xml
describes the module:
<?xml version="1.0" ?>
<module xmlns="urn:jboss:module:1.1" name="com.mysql">
<resources>
<!-- ***** IMPORTANT : REPLACE THIS PLACEHOLDER *******-->
<resource-root path="/home/site/deployments/tools/mysql-connector-java-8.0.13.jar" />
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
Add a JDBC driver for MySQL:
/subsystem=datasources/jdbc-driver=mysql:add(driver-name=mysql,driver-module-name=com.mysql,driver-class-name=com.mysql.cj.jdbc.Driver)
Install a data source by using the data-source shortcut command:
data-source add --name=mysqlDS --jndi-name=java:jboss/datasources/mysqlDS --connection-url=${MYSQL_CONNECTION_URL,env.MYSQL_CONNECTION_URL:jdbc:mysql://db:3306/petstore} --driver-name=mysql --user-name=${MYSQL_SERVER_ADMIN_FULL_NAME,env.MYSQL_SERVER_ADMIN_FULL_NAME:mysql} --password=${MYSQL_SERVER_ADMIN_PASSWORD,env.MYSQL_SERVER_ADMIN_PASSWORD:example} --use-ccm=true --max-pool-size=5 --blocking-timeout-wait-millis=5000 --enabled=true --driver-class=com.mysql.cj.jdbc.Driver --jta=true --use-java-context=true --exception-sorter-class-name=com.mysql.cj.jdbc.integration.jboss.ExtendedMysqlExceptionSorter
A server reload may be required for the changes to take effect:
reload --use-current-server-config=true
These JBoss CLI commands, JDBC driver for MySQL and module XML are available in initial-mysql/agoncal-application-petstore-ee7/.scripts
Also, you can directly download JDBC driver for MySQL. For example:
wget -q "http://search.maven.org/remotecontent?filepath=mysql/mysql-connector-java/8.0.13/mysql-connector-java-8.0.13.jar" -O mysql-connector-java-8.0.13.jar
Open an FTP connection to App Service Linux to upload data source artifacts:
pwd
/Users/selvasingh/migrate-Java-EE-app-to-azure/initial-mysql/agoncal-application-petstore-ee7
cd .scripts
ftp
ftp> open waws-prod-bay-063.drip.azurewebsites.windows.net
Trying 23.99.84.148...
Connected to waws-prod-bay-063.drip.azurewebsites.windows.net.
220 Microsoft FTP Service
Name (waws-prod-bay-063.drip.azurewebsites.windows.net:selvasingh): petstore-java-ee\\$petstore-java-ee
331 Password required
Password:
230 User logged in.
Remote system type is Windows_NT.
ftp> ascii
200 Type set to A.
ftp> put startup.sh
local: startup.sh remote: startup.sh
229 Entering Extended Passive Mode (|||10208|)
125 Data connection already open; Transfer starting.
100% |************************************************| 236 40.58 KiB/s --:-- ETA
226 Transfer complete.
236 bytes sent in 00:00 (5.18 KiB/s)
ftp> cd site/deployments/tools
250 CWD command successful.
ftp> put mysql-datasource-commands.cli
local: mysql-datasource-commands.cli remote: mysql-datasource-commands.cli
229 Entering Extended Passive Mode (|||10209|)
125 Data connection already open; Transfer starting.
100% |************************************************| 1375 226.39 KiB/s --:-- ETA
226 Transfer complete.
1375 bytes sent in 00:00 (30.81 KiB/s)
ftp> put mysql-module.xml
local: mysql-module.xml remote: mysql-module.xml
229 Entering Extended Passive Mode (|||10210|)
125 Data connection already open; Transfer starting.
100% |************************************************| 411 1.29 MiB/s --:-- ETA
226 Transfer complete.
411 bytes sent in 00:00 (9.34 KiB/s)
ftp> binary
200 Type set to I.
ftp> put mysql-connector-java-8.0.13.jar
local: mysql-connector-java-8.0.13.jar remote: mysql-connector-java-8.0.13.jar
229 Entering Extended Passive Mode (|||10211|)
125 Data connection already open; Transfer starting.
100% |************************************************| 2082 KiB 622.64 KiB/s 00:00 ETA
226 Transfer complete.
2132635 bytes sent in 00:03 (597.54 KiB/s)
ftp> bye
221 Goodbye.
Use Azure CLI to set database connection info:
az webapp config appsettings set \
--resource-group ${RESOURCEGROUP_NAME} --name ${WEBAPP_NAME} \
--settings \
MYSQL_CONNECTION_URL=${MYSQL_CONNECTION_URL} \
MYSQL_SERVER_ADMIN_PASSWORD=${MYSQL_SERVER_ADMIN_PASSWORD} \
MYSQL_SERVER_ADMIN_FULL_NAME=${MYSQL_SERVER_ADMIN_FULL_NAME}
[
{
"name": "WEBSITE_HTTPLOGGING_RETENTION_DAYS",
"slotSetting": false,
"value": "3"
},
{
"name": "MYSQL_CONNECTION_URL",
"slotSetting": false,
"value": "jdbc:mysql://petstore-db1221.mysql.database.azure.com:3306/petstore?ssl=true"
},
{
"name": "MYSQL_SERVER_ADMIN_PASSWORD",
"slotSetting": false,
"value": "======= MASKED ======="
},
{
"name": "MYSQL_SERVER_ADMIN_FULL_NAME",
"slotSetting": false,
"value": "selvasingh@petstore-db1221"
}
]
You can test Bash script for configuring data source by running them on App Service Linux by opening an SSH connection from your development machine:
# ======== first terminal window =========
az webapp create-remote-connection --resource-group ${RESOURCEGROUP_NAME} --name ${WEBAPP_NAME} &
[18] 7422
bash-3.2$ Auto-selecting port: 60029
SSH is available { username: root, password: Docker! }
Start your favorite client and connect to port 60029
Websocket tracing disabled, use --verbose flag to enable
Successfully connected to local server..
# ======== second terminal window ========
ssh root@localhost -p 60029
The authenticity of host '[localhost]:60029 ([127.0.0.1]:60029)' can't be established.
ECDSA key fingerprint is SHA256:Lys3Kd4sNJc7X8LVMRP89GKbOzlOGp03tGYj+mY4Kic.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:60029' (ECDSA) to the list of known hosts.
root@localhost's password:
_____
/ _ \ __________ _________ ____
/ /_\ \___ / | \_ __ \_/ __ \
/ | \/ /| | /| | \/\ ___/
\____|__ /_____ \____/ |__| \___ >
\/ \/ \/
A P P S E R V I C E O N L I N U X
Documentation: http://aka.ms/webapp-linux
c315a18b39d2:/home#
# ======== run JBoss/WildFly CLI commands to configure a data source ===========
c315a18b39d2:/home# /opt/eap/bin/jboss-cli.sh -c
Picked up _JAVA_OPTIONS: -Djava.net.preferIPv4Stack=true
[standalone@localhost:9990 /] module add --name=com.mysql --resources=/home/site/deployments/tools/mysql-connector-java-8.0.13.jar --module-xml=/home/site/deployments/tools/mysql-module.xml
[standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=mysql:add(driver-name=mysql,driver-module-name=com.mysql,driver-class-name=com.mysql.cj.jdbc.Driver)
{"outcome" => "success"}
[standalone@localhost:9990 /] data-source add --name=mysqlDS --jndi-name=java:jboss/datasources/mysqlDS --connection-url=${MYSQL_CONNECTION_URL,env.MYSQL_CONNECTION_URL:jdbc:mysql://db:3306/petstore} --driver-name=mysql --user-name=${MYSQL_SERVER_ADMIN_FULL_NAME,env.MYSQL_SERVER_ADMIN_FULL_NAME:mysql} --password=${MYSQL_SERVER_ADMIN_PASSWORD,env.MYSQL_SERVER_ADMIN_PASSWORD:example} --use-ccm=true --max-pool-size=5 --blocking-timeout-wait-millis=5000 --enabled=true --driver-class=com.mysql.cj.jdbc.Driver --jta=true --use-java-context=true --exception-sorter-class-name=com.mysql.cj.jdbc.integration.jboss.ExtendedMysqlExceptionSorter
[standalone@localhost:9990 /] /subsystem=datasources/data-source=mysqlDS:test-connection-in-pool()
{
"outcome" => "success",
"result" => [true]
}
# ======== run JBoss/WildFly CLI commands to undo the datasource configuration =========
/subsystem=datasources:read-resource
/subsystem=datasources:installed-drivers-list
module remove --name=com.mysql # --name=org.postgres --name=com.microsoft
data-source remove --name=mysqlDS # --name=postgresDS --name=sqlDS
reload --use-current-server-config=true
/subsystem=datasources/jdbc-driver=mysql:remove # jdbc-driver=postgres jdbc-driver-sqlserver
Use Azure CLI to restart the remote JBoss EAP app server:
az webapp stop -g ${RESOURCEGROUP_NAME} -n ${WEBAPP_NAME}
az webapp start -g ${RESOURCEGROUP_NAME} -n ${WEBAPP_NAME}
For additional info, please refer to:
- JBoss Data Source Management.
- JBoss/WildFly CLI Guide
- Open SSH session from your development machine to App Service Linux
# Use the Maven profile for MySQL to build
bash-3.2$ mvn package -Dmaven.test.skip=true -Ddb=mysql
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Petstore application using Java EE 7 7.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- copy-rename-maven-plugin:1.0:copy (copy-file) @ petstoreee7 ---
[INFO] Copied /Users/selvasingh/migrate-Java-EE-app-to-azure/initial-mysql/agoncal-application-petstore-ee7/src/main/resources/META-INF/persistence-mysql.xml to /Users/selvasingh/migrate-Java-EE-app-to-azure/initial-mysql/agoncal-application-petstore-ee7/src/main/resources/META-INF/persistence.xml
...
...
[INFO] --- maven-war-plugin:3.1.0:war (default-war) @ petstoreee7 ---
[INFO] Packaging webapp
[INFO] Assembling webapp [petstoreee7] in [/Users/selvasingh/migrate-Java-EE-app-to-azure/initial-mysql/agoncal-application-petstore-ee7/target/applicationPetstore]
[INFO] Processing war project
[INFO] Copying webapp resources [/Users/selvasingh/migrate-Java-EE-app-to-azure/initial-mysql/agoncal-application-petstore-ee7/src/main/webapp]
[INFO] Webapp assembled in [258 msecs]
[INFO] Building war: /Users/selvasingh/migrate-Java-EE-app-to-azure/initial-mysql/agoncal-application-petstore-ee7/target/applicationPetstore.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.199 s
[INFO] Finished at: 2018-12-22T10:47:23-08:00
[INFO] Final Memory: 26M/388M
[INFO] ------------------------------------------------------------------------
Deploy to JBoss EAP in App Service Linux:
mvn azure-webapp:deploy
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Petstore application using Java EE 7 7.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- azure-webapp-maven-plugin:1.12.0:deploy (default-cli) @ petstoreee7 ---
[INFO] Authenticate with Azure CLI 2.0
[INFO] Updating target Web App...
[INFO] Successfully updated Web App.
[INFO] Trying to deploy artifact to petstore-java-ee...
[INFO] Deploying the war file...
[INFO] Successfully deployed the artifact to https://petstore-java-ee.azurewebsites.net
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 56.128 s
[INFO] Finished at: 2018-12-22T10:51:13-08:00
[INFO] Final Memory: 60M/626M
[INFO] ------------------------------------------------------------------------
open https://petstore-java-ee.azurewebsites.net
mysql -u ${MYSQL_SERVER_ADMIN_FULL_NAME} -h ${MYSQL_SERVER_FULL_NAME} -P 3306 -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 64167
Server version: 5.6.39.0 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> use petstore;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+--------------------+
| Tables_in_petstore |
+--------------------+
| category |
| country |
| customer |
| hibernate_sequence |
| item |
| order_line |
| product |
| purchase_order |
| t_order_order_line |
+--------------------+
9 rows in set (0.03 sec)
mysql> select name from category;
+----------+
| name |
+----------+
| Fish |
| Dogs |
| Reptiles |
| Cats |
| Birds |
+----------+
5 rows in set (0.03 sec)
mysql> quit
Bye
Open Java Web app remote log stream from a local machine:
az webapp log tail --name ${WEBAPP_NAME} \
--resource-group ${RESOURCEGROUP_NAME}
Start your next leg of your journey ... change directory:
cd ../../initial-sql/agoncal-application-petstore-ee7
Add a new profile for sql in pom.xml
:
<profile>
<id>sql</id>
<activation>
<property>
<name>db</name>
<value>sql</value>
</property>
</activation>
<build>
<plugins>
<!-- copy the correct persistence.xml file -->
<plugin>
<groupId>com.coderplus.maven.plugins</groupId>
<artifactId>copy-rename-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>copy-file</id>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<sourceFile>${project.basedir}main/resources/META-INF/persistence-sql.xml</sourceFile>
<destinationFile>${project.basedir}/src/main/resources/META-INF/persistence.xml</destinationFile>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
cp set-env-variables-template.sh .scripts/set-env-variables.sh
Modify .scripts/set-env-variables.sh
and set Azure Resource Group name,
App Service Web App Name, Azure Region, JBoss EAP directory in
the local machine, FTP deployment credentials and SQL Database info.
Then, set environment variables:
source .scripts/set-env-variables.sh
Install the Azure CLI db-up
extension:
az extension add --name db-up
Create a Petstore DB using Azure CLI and SQL CLI:
az sql server create --admin-user ${SQL_SERVER_ADMIN_LOGIN_NAME} \
--admin-password ${SQL_SERVER_ADMIN_PASSWORD} \
--name ${SQL_SERVER_NAME} \
--resource-group ${RESOURCEGROUP_NAME}
az sql server firewall-rule create --server ${SQL_SERVER_NAME} \
--name allAzureIPs \
--start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0 \
--resource-group ${RESOURCEGROUP_NAME}
az sql server firewall-rule create --server ${SQL_SERVER_NAME} \
--name myDevBox \
--start-ip-address ${DEVBOX_IP_ADDRESS} --end-ip-address ${DEVBOX_IP_ADDRESS} \
--resource-group ${RESOURCEGROUP_NAME}
az sql db create --name ${SQL_DATABASE_NAME} \
--server ${SQL_SERVER_NAME} \
--resource-group ${RESOURCEGROUP_NAME}
When you migrate Java workloads to cloud, you will be considering moving data to cloud. To accelerate your transition to cloud, Azure offers plenty of options to migrate your data to cloud.
Also, for your convenience, there is a cheat sheet for sqlcmd CLI.
There are 5 steps to configure a data source. These steps are similar to configuring data sources in any on premise Java EE app servers:
In App Service, each instance of an app server is stateless. Therefore, each instance must be
configured on startup to support a JBoss EAP configuration needed by your application. You can configure at
startup by supplying a startup Bash script that calls JBoss/WildFly CLI commands to setup data sources, messaging
providers and any other dependencies. We will create a startup.sh script and place it in the /home
directory of the Web app. The script will:
Install a JBoss EAP module:
# where resources point to JDBC driver for SQL Database
# and module xml points to module description, see below
module add --name=com.microsoft --resources=/home/site/deployments/tools/mssql-jdbc-7.2.1.jre8.jar --module-xml=/home/site/deployments/tools/mssql-module.xml
Where mssql-module.xml
describes the module:
<?xml version="1.0" ?>
<module xmlns="urn:jboss:module:1.1" name="com.microsoft">
<resources>
<resource-root path="/home/site/deployments/tools/mssql-jdbc-7.2.1.jre8.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
Add a JDBC driver for SQL Database:
/subsystem=datasources/jdbc-driver=sqlserver:add(driver-name="sqlserver",driver-module-name="com.microsoft",driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver,driver-datasource-class-name=com.microsoft.sqlserver.jdbc.SQLServerDataSource)
Install a data source by using the data-source shortcut command:
data-source add --name=sqlDS --jndi-name=java:jboss/datasources/sqlDS --driver-name=sqlserver --connection-url=${SQL_CONNECTION_URL,env.SQL_CONNECTION_URL:example} --validate-on-match=true --background-validation=false --valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLValidConnectionChecker --exception-sorter-class-name=org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLExceptionSorter
A server reload may be required for the changes to take effect:
reload --use-current-server-config=true
These JBoss CLI commands, JDBC driver for SQL Database and module XML are available in initial-sql/agoncal-application-petstore-ee7/.scripts
Also, you can directly download JDBC driver for SQL Database. For example:
Open an FTP connection to App Service Linux to upload data source artifacts:
pwd
/Users/selvasingh/migrate-Java-EE-app-to-azure/initial-sql/agoncal-application-petstore-ee7
cd .scripts
ftp
ftp> open waws-prod-bay-063.ftp.azurewebsites.windows.net
Trying 23.99.87.125...
Connected to waws-prod-bay-063.drip.azurewebsites.windows.net.
220 Microsoft FTP Service
Name (waws-prod-bay-063.ftp.azurewebsites.windows.net:selvasingh):
331 Password required
Password:
230 User logged in.
Remote system type is Windows_NT.
ftp> pwd
Remote directory: /
ftp> ascii
200 Type set to A.
ftp> put startup.sh
local: startup.sh remote: startup.sh
229 Entering Extended Passive Mode (|||10199|)
125 Data connection already open; Transfer starting.
100% |*******************************************************| 125 21.36 KiB/s --:-- ETA
226 Transfer complete.
125 bytes sent in 00:00 (2.71 KiB/s)
ftp> cd site/deployments/tools
250 CWD command successful.
ftp> put mssql-datasource-commands.cli
local: mssql-datasource-commands.cli remote: mssql-datasource-commands.cli
229 Entering Extended Passive Mode (|||10200|)
125 Data connection already open; Transfer starting.
100% |*******************************************************| 1751 301.42 KiB/s --:-- ETA
226 Transfer complete.
1751 bytes sent in 00:00 (35.69 KiB/s)
ftp> put mssql-module.xml
local: mssql-module.xml remote: mssql-module.xml
229 Entering Extended Passive Mode (|||10201|)
125 Data connection already open; Transfer starting.
100% |*******************************************************| 305 51.39 KiB/s --:-- ETA
226 Transfer complete.
305 bytes sent in 00:00 (7.07 KiB/s)
ftp> bin
200 Type set to I.
ftp> put mssql-jdbc-7.2.1.jre8.jar
local: mssql-jdbc-7.2.1.jre8.jar remote: mssql-jdbc-7.2.1.jre8.jar
229 Entering Extended Passive Mode (|||10202|)
125 Data connection already open; Transfer starting.
100% |*******************************************************| 1135 KiB 1.62 MiB/s 00:00 ETA
226 Transfer complete.
1162710 bytes sent in 00:00 (1.48 MiB/s)
ftp> bye
221 Goodbye.
Use Azure CLI to set database connection info:
az webapp config appsettings set \
--resource-group ${RESOURCEGROUP_NAME} \
--name ${WEBAPP_NAME} \
--settings SQL_CONNECTION_URL=${SQL_CONNECTION_URL}
[
{
"name": "WEBSITE_HTTPLOGGING_RETENTION_DAYS",
"slotSetting": false,
"value": "3"
},
{
"name": "SQL_CONNECTION_URL",
"slotSetting": false,
"value": "======= MASKED ======="
}
]
You can test Bash script for configuring data source by running them on App Service Linux by opening an SSH connection from your development machine:
# ======== first terminal window =========
az webapp create-remote-connection --resource-group ${RESOURCEGROUP_NAME} --name ${WEBAPP_NAME} &
[1] 10851
bash-3.2$ Auto-selecting port: 54155
SSH is available { username: root, password: Docker! }
Start your favorite client and connect to port 54155
Websocket tracing disabled, use --verbose flag to enable
Successfully connected to local server..
ssh root@localhost -p 58386
The authenticity of host '[localhost]:58386 ([127.0.0.1]:58386)' can't be established.
ECDSA key fingerprint is SHA256:7EHlhnWmPC600borWmiBMP43SdXIHedlk4sKIfJKu3I.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:58386' (ECDSA) to the list of known hosts.
root@localhost's password:
_____
/ _ \ __________ _________ ____
/ /_\ \___ / | \_ __ \_/ __ \
/ | \/ /| | /| | \/\ ___/
\____|__ /_____ \____/ |__| \___ >
\/ \/ \/
A P P S E R V I C E O N L I N U X
Documentation: http://aka.ms/webapp-linux
ee72972be508:/home#
# ======== run JBoss/WildFly CLI commands to configure a data source ===========
ee72972be508:/home# source startup.sh
Picked up _JAVA_OPTIONS: -Djava.net.preferIPv4Stack=true
"Configuring sqlDS ==================="
"Installing MSSQL module"
"Installing MSSQL driver"
"Installing MSSQL datasource"
The batch executed successfully
ee72972be508:/home# /opt/eap/bin/jboss-cli.sh -c
Picked up _JAVA_OPTIONS: -Djava.net.preferIPv4Stack=true
[standalone@localhost:9990 /] /subsystem=datasources/data-source=sqlDS:test-connection-in-pool()
{
"outcome" => "success",
"result" => [true]
}
[standalone@localhost:9990 /] exit
Use Azure CLI to restart the remote JBoss EAP app server:
az webapp stop -g ${RESOURCEGROUP_NAME} -n ${WEBAPP_NAME}
az webapp start -g ${RESOURCEGROUP_NAME} -n ${WEBAPP_NAME}
For additional info, please refer to:
- JBoss Data Source Management.
- JBoss/WildFly CLI Guide
- Open SSH session from your development machine to App Service Linux
# Use the Maven profile for Azure SQL Database to build
mvn package -Dmaven.test.skip=true -Ddb=sql
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Petstore application using Java EE 7 7.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- copy-rename-maven-plugin:1.0:copy (copy-file) @ petstoreee7 ---
[INFO] Copied /Users/selvasingh/migrate-Java-EE-app-to-azure/initial-sql/agoncal-application-petstore-ee7/src/main/resources/META-INF/persistence-sql.xml to /Users/selvasingh/migrate-Java-EE-app-to-azure/initial-sql/agoncal-application-petstore-ee7/src/main/resources/META-INF/persistence.xml
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ petstoreee7 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 14 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ petstoreee7 ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- swagger-maven-plugin:3.1.6:generate (default) @ petstoreee7 ---
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ petstoreee7 ---
[INFO] Not copying test resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ petstoreee7 ---
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ petstoreee7 ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-war-plugin:3.1.0:war (default-war) @ petstoreee7 ---
[INFO] Packaging webapp
[INFO] Assembling webapp [petstoreee7] in [/Users/selvasingh/migrate-Java-EE-app-to-azure/initial-sql/agoncal-application-petstore-ee7/target/applicationPetstore]
[INFO] Processing war project
[INFO] Copying webapp resources [/Users/selvasingh/migrate-Java-EE-app-to-azure/initial-sql/agoncal-application-petstore-ee7/src/main/webapp]
[INFO] Webapp assembled in [394 msecs]
[INFO] Building war: /Users/selvasingh/migrate-Java-EE-app-to-azure/initial-sql/agoncal-application-petstore-ee7/target/applicationPetstore.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.850 s
[INFO] Finished at: 2019-06-01T17:47:53-07:00
[INFO] Final Memory: 22M/338M
[INFO] ------------------------------------------------------------------------
Deploy to JBoss EAP in App Service Linux:
mvn azure-webapp:deploy
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Petstore application using Java EE 7 7.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- azure-webapp-maven-plugin:1.12.0:deploy (default-cli) @ petstoreee7 ---
[INFO] Authenticate with Azure CLI 2.0
[INFO] Updating target Web App...
[INFO] Successfully updated Web App.
[INFO] Trying to deploy artifact to petstore-java-ee...
[INFO] Deploying the war file...
[INFO] Successfully deployed the artifact to https://petstore-java-ee.azurewebsites.net
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:25 min
[INFO] Finished at: 2019-06-01T17:54:14-07:00
[INFO] Final Memory: 50M/635M
[INFO] ------------------------------------------------------------------------
open https://petstore-java-ee.azurewebsites.net
# Show tables in SQL Database
sqlcmd -S ${SQL_SERVER_FULL_NAME} \
-d ${SQL_DATABASE_NAME} \
-U ${SQL_SERVER_ADMIN_FULL_NAME} \
-P ${SQL_SERVER_ADMIN_PASSWORD} \
-Q "SELECT name, id, crdate FROM SYSOBJECTS WHERE xtype = 'U'"
--------------------- ----------- -----------------------
Category 18099105 2019-05-31 14:41:52.280
Country 50099219 2019-05-31 14:41:52.320
Customer 82099333 2019-05-31 14:41:52.330
Item 114099447 2019-05-31 14:41:52.347
order_line 146099561 2019-05-31 14:41:52.373
Product 194099732 2019-05-31 14:41:52.390
purchase_order 226099846 2019-05-31 14:41:52.427
t_order_order_line 258099960 2019-05-31 14:41:52.483
(8 rows affected)
# Show contents in category table
sqlcmd -S ${SQL_SERVER_FULL_NAME} \
-d ${SQL_DATABASE_NAME} \
-U ${SQL_SERVER_ADMIN_FULL_NAME} \
-P ${SQL_SERVER_ADMIN_PASSWORD} \
-Q "select name from category"
name
------------------------------
Fish
Dogs
Reptiles
Cats
Birds
(5 rows affected)
Open Java Web app remote log stream from a local machine:
az webapp log tail --name ${WEBAPP_NAME} \
--resource-group ${RESOURCEGROUP_NAME}
2018-12-22T00:47:48 Welcome, you are now connected to log-streaming service.
2018-12-22T00:41:45.064280703Z _____
2018-12-22T00:41:45.064325203Z / _ \ __________ _________ ____
2018-12-22T00:41:45.064331403Z / /_\ \___ / | \_ __ \_/ __ \
2018-12-22T00:41:45.064335603Z / | \/ /| | /| | \/\ ___/
2018-12-22T00:41:45.064339403Z \____|__ /_____ \____/ |__| \___ >
2018-12-22T00:41:45.064343503Z \/ \/ \/
2018-12-22T00:41:45.064347403Z A P P S E R V I C E O N L I N U X
...
...
2019-06-02T00:55:35.520469647Z 00:55:35,520 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 14.0.1.Final (WildFly Core 6.0.2.Final) started in 9816ms - Started 81 of 93 services (31 services are lazy, passive or on-demand)
2019-06-02T00:55:38.548395649Z ***Admin server is ready
2019-06-02T00:55:38.555859867Z STARTUP_FILE=/home/startup.sh
2019-06-02T00:55:38.582558031Z STARTUP_COMMAND=
2019-06-02T00:55:38.587032142Z Copying /home/startup.sh to /tmp/startup.sh and fixing EOL characters in /tmp/startup.sh
2019-06-02T00:55:38.593801458Z Running STARTUP_FILE: /tmp/startup.sh
2019-06-02T00:55:38.628501142Z Picked up JAVA_TOOL_OPTIONS: -Djava.net.preferIPv4Stack=true
2019-06-02T00:55:42.206161168Z "Configuring sqlDS ==================="
2019-06-02T00:55:42.211727982Z "Installing MSSQL module"
2019-06-02T00:55:42.253643983Z "Installing MSSQL driver"
2019-06-02T00:55:42.284713558Z "Installing MSSQL datasource"
2019-06-02T00:55:42.490971355Z The batch executed successfully
2019-06-02T00:55:42.552288503Z 00:55:42,552 INFO [org.jboss.as] (MSC service thread 1-1) WFLYSRV0050: WildFly Full 14.0.1.Final (WildFly Core 6.0.2.Final) stopped in 47ms
2019-06-02T00:55:42.564687033Z 00:55:42,564 INFO [org.jboss.as] (MSC service thread 1-2) WFLYSRV0049: WildFly Full 14.0.1.Final (WildFly Core 6.0.2.Final) starting
...
...
2019-06-02T00:55:44.293778902Z 00:55:44,293 INFO [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 44) WFLYJCA0004: Deploying JDBC-compliant driver class com.microsoft.sqlserver.jdbc.SQLServerDriver (version 7.2)
2019-06-02T00:55:44.594576027Z 00:55:44,594 INFO [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-2) WFLYJCA0018: Started Driver service with driver-name = sqlserver
2019-06-02T00:55:44.607447158Z 00:55:44,601 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-2) WFLYJCA0010: Unbound data source [java:jboss/datasources/ExampleDS]
2019-06-02T00:55:44.610591266Z 00:55:44,610 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-2) WFLYJCA0010: Unbound data source [java:jboss/datasources/sqlDS]
...
...
019-06-02T00:55:56.153951398Z 00:55:56,152 INFO [org.jboss.as.jpa] (ServerService Thread Pool -- 79) WFLYJPA0010: Starting Persistence Unit (phase 2 of 2) Service 'ROOT.war#applicationPetstorePU'
2019-06-02T00:55:57.237113910Z 00:55:57,232 INFO [org.hibernate.dialect.Dialect] (ServerService Thread Pool -- 79) HHH000400: Using dialect: org.hibernate.dialect.SQLServer2012Dialect
When you are finished, you can check your results against YOUR code in migrate-Java-EE-app-to-azure/complete.
Scale out Java Web app using Azure CLI:
az appservice plan update --number-of-workers 2 \
--name ${WEBAPP_PLAN_NAME} \
--resource-group ${RESOURCEGROUP_NAME}
Congratulations!! You migrated an existing Java EE workload to Azure, aka app to App Service Linux and app's data to Azure Database for PostgreSQL, MySQL and or SQL Database.
- Java Enterprise Guide for App Service on Linux
- Maven Plugin for Azure App Service
- JBoss Data Source Management
- JBoss/WildFly CLI Guide
- JDBC driver for PostgreSQL
- PostgreSQL CLI Cheat Sheet
- JDBC driver for MySQL
- MySQL CLI Cheat Sheet
- Cheat sheet for sqlcmd CLI
- Opening an SSH connection from your development machine
- Azure for Java Developers
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.
Here are some useful JBoss CLI commands:
/opt/eap/bin/jboss-cli.sh -c
/subsystem=datasources:read-resource
/subsystem=datasources:installed-drivers-list
module remove --name=org.postgres # --name=com.mysql --name=com.microsoft
data-source remove --name=postgresDS # --name=mysqlDS --name=sqlDS
reload --use-current-server-config=true
/subsystem=datasources/jdbc-driver=postgres:remove # jdbc-driver=mysql jdbc-driver-sqlserver