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
- Table of Contents
- 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
- Add PostgreSQL Profile
- Set environment variables for binding secrets at runtime
- Create and Configure Petstore DB in Azure Database for PostgreSQL
- Configure PostgreSQL Data Source
- Build PetStore to interact with Azure Database for PostgreSQL
- Deploy to App Service Linux
- Open Pet Store running on App Service Linux and interacting with Azure Database for PostgreSQL
- Log into Azure Database for PostgreSQL and Validate Tables were Created and Populated
- Trouble Shoot Petstore on Azure by Viewing Logs
- Build and Deploy Pet Store Powered Using Azure Database for MySQL
- Add MySQL Profile
- Set environment variables for binding secrets at runtime
- Create and Configure MySQL DB in Azure Database for MySQL
- Configure MySQL Data Source
- Build PetStore to interact with Azure Database for MySQL
- Deploy to App Service Linux
- Open Pet Store running on App Service Linux and interacting with Azure Database for MySQL
- Log into Azure Database for MySQL and Validate Tables were Created and Populated
- Trouble Shoot Petstore on Azure by Viewing Logs
- Build and Deploy Pet Store Powered Using Azure SQL Database
- Add SQL Database Profile
- Set environment variables for binding secrets at runtime
- Create and Configure SQL DB in Azure SQL Database
- Configure SQL Database Data Source
- Build PetStore to interact with Azure SQL Database
- Deploy to App Service Linux
- Open Pet Store running on App Service Linux and interacting with Azure SQL Database
- Log into Azure SQL Database and Validate Tables were Created and Populated
- Trouble Shoot Petstore on Azure by Viewing Logs
- 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 |
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 WildFly directory in
the local machine. Then, set environment variables:
source .scripts/set-env-variables.sh
Add Maven Plugin for Azure App Service configuration to POM.xml and deploy Pet Store to WildFly in App Service Linux:
<plugins>
<!--*************************************************-->
<!-- Deploy to WildFly in App Service Linux -->
<!--*************************************************-->
<plugin>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-webapp-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<!-- Web App information -->
<resourceGroup>${RESOURCEGROUP_NAME}</resourceGroup>
<appServicePlanName>${WEBAPP_PLAN_NAME}</appServicePlanName>
<appName>${WEBAPP_NAME}</appName>
<region>${REGION}</region>
<!-- Java Runtime Stack for Web App on Linux-->
<linuxRuntime>wildfly 14-jre8</linuxRuntime>
</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.6.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}/src/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 <resource-group> -n <webapp>
{ ... ... "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
```bash
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_Gen4_2 --version 9.6
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
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 Wildfly 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 WildFly 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"
}
]
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 remote-connection create --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#
#========= open a vi window to edit startup.sh ============
c315a18b39d2:/home# vi startup.sh
# ======== vi window =====================
#!/usr/bin/env bash^M
/opt/jboss/wildfly/bin/jboss-cli.sh -c --file=/home/site/deployments/tools/postgresql-datasource-commands.cli^M
~
remove those '^M' end of line characters and save the file
# ======== run JBoss/WildFly CLI commands to configure a data source ===========
c315a18b39d2:/home# /opt/jboss/wildfly/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]
}
Use Azure CLI to restart the remote WildFly 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 WildFly 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.6.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}
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
...
...
2018-12-22T00:41:47.124232726Z ***Copying /home/site/wwwroot/webapps/ROOT to /opt/jboss/wildfly/standalone/deployments/ROOT.war
2018-12-22T00:41:48.193646648Z ***Creating marker file /opt/jboss/wildfly/standalone/deployments/ROOT.war.dodeploy
...
...
2018-12-22T00:41:52.895075005Z 00:41:52,770 INFO [org.jboss.modules] (main) JBoss Modules version 1.8.6.Final
2018-12-22T00:41:55.713960188Z 00:41:55,704 INFO [org.jboss.msc] (main) JBoss MSC version 1.4.3.Final
2018-12-22T00:41:55.817008239Z 00:41:55,816 INFO [org.jboss.threads] (main) JBoss Threads version 2.3.2.Final
2018-12-22T00:41:57.201980849Z 00:41:57,201 INFO [org.jboss.as] (MSC service thread 1-2) WFLYSRV0049: WildFly Full 14.0.1.Final (WildFly Core 6.0.2.Final) starting
...
...
2018-12-22T00:42:19.043814396Z 00:42:19,043 INFO [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 41) WFLYJCA0005: Deploying non-JDBC-compliant driver class org.postgresql.Driver (version 42.2)
2018-12-22T00:42:19.050046930Z 00:42:19,042 INFO [org.jboss.as.security] (MSC service thread 1-2) WFLYSEC0001: Current PicketBox version=5.0.3.Final
2018-12-22T00:42:19.086580525Z 00:42:19,086 INFO [org.wildfly.extension.undertow] (MSC service thread 1-1) WFLYUT0003: Undertow 2.0.13.Final starting
2018-12-22T00:42:19.155234792Z 00:42:19,155 INFO [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-2) WFLYJCA0018: Started Driver service with driver-name = h2
2018-12-22T00:42:19.173958592Z 00:42:19,173 INFO [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-2) WFLYJCA0018: Started Driver service with driver-name = postgres
...
...
2018-12-22T00:42:40.634081365Z 00:42:40,633 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 14.0.1.Final (WildFly Core 6.0.2.Final) started in 22695ms - Started 801 of 972 services (328 services are lazy, passive or on-demand)
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}/src/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, WildFly 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> quit
Bye
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 Wildfly 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 WildFly 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 remote-connection create --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#
#========= open a vi window to edit startup.sh ============
c315a18b39d2:/home# vi startup.sh
# ======= vi window second time ==========
#!/usr/bin/env bash^M
/opt/jboss/wildfly/bin/jboss-cli.sh -c --file=/home/site/deployments/tools/postgresql-datasource-commands.cli^M
/opt/jboss/wildfly/bin/jboss-cli.sh -c --file=/home/site/deployments/tools/mysql-datasource-commands.cli^M
~
remove those '^M' end of line characters and save the file
# ======== run JBoss/WildFly CLI commands to configure a data source ===========
c315a18b39d2:/home# /opt/jboss/wildfly/bin/jboss-cli.sh --connect
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]
}
Use Azure CLI to restart the remote WildFly 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 WildFly 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.6.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}
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
...
...
2018-12-22T00:41:47.124232726Z ***Copying /home/site/wwwroot/webapps/ROOT to /opt/jboss/wildfly/standalone/deployments/ROOT.war
2018-12-22T00:41:48.193646648Z ***Creating marker file /opt/jboss/wildfly/standalone/deployments/ROOT.war.dodeploy
...
...
2018-12-22T00:41:52.895075005Z 00:41:52,770 INFO [org.jboss.modules] (main) JBoss Modules version 1.8.6.Final
2018-12-22T00:41:55.713960188Z 00:41:55,704 INFO [org.jboss.msc] (main) JBoss MSC version 1.4.3.Final
2018-12-22T00:41:55.817008239Z 00:41:55,816 INFO [org.jboss.threads] (main) JBoss Threads version 2.3.2.Final
2018-12-22T00:41:57.201980849Z 00:41:57,201 INFO [org.jboss.as] (MSC service thread 1-2) WFLYSRV0049: WildFly Full 14.0.1.Final (WildFly Core 6.0.2.Final) starting
...
...
2018-12-22T00:42:19.043814396Z 00:42:19,043 INFO [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 41) WFLYJCA0005: Deploying non-JDBC-compliant driver class com.mysql.cj.jdbc.Driver (version 8.0)
2018-12-22T00:42:19.050046930Z 00:42:19,042 INFO [org.jboss.as.security] (MSC service thread 1-2) WFLYSEC0001: Current PicketBox version=5.0.3.Final
2018-12-22T00:42:19.086580525Z 00:42:19,086 INFO [org.wildfly.extension.undertow] (MSC service thread 1-1) WFLYUT0003: Undertow 2.0.13.Final starting
2018-12-22T00:42:19.155234792Z 00:42:19,155 INFO [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-2) WFLYJCA0018: Started Driver service with driver-name = h2
2018-12-22T00:42:19.173958592Z 00:42:19,173 INFO [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-2) WFLYJCA0018: Started Driver service with driver-name = mysql
2018-12-22T00:42:19.173958592Z 00:42:19,187 INFO [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-1) WFLYJCA0018: Started Driver service with driver-name = postgres
...
...
2018-12-22T00:42:40.634081365Z 00:42:40,633 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 14.0.1.Final (WildFly Core 6.0.2.Final) started in 22695ms - Started 801 of 972 services (328 services are lazy, passive or on-demand)
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}/src/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, WildFly 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 up --resource-group ${RESOURCEGROUP_NAME} \
--server-name ${SQL_SERVER_NAME} \
--database-name ${SQL_DATABASE_NAME} --admin-user ${SQL_SERVER_ADMIN_LOGIN_NAME} \
--admin-password ${SQL_SERVER_ADMIN_PASSWORD} \
--location ${REGION}
Creating SQL Server 'petstore-sql-0601' in group 'e2e-java-ee'...
Configuring server firewall rule, 'azure-access', to accept connections from all Azure resources...
Creating SQL database 'sqldb'...
Checking your ip address...
Configuring server firewall rule, 'devbox', to allow for your ip address: 98.225.36.126
If SQL server declines your IP address, please create a new firewall rule using:
`az sql server firewall-rule create -g e2e-java-ee -s petstore-sql-0601 -n {rule_name} --start-ip-address {ip_address} --end-ip-address {ip_address}`
Successfully Connected to SQL Database.
Ran Database Query: `CREATE USER root WITH PASSWORD = "======= MASKED ======="
Ran Database Query: `GRANT ALL TO root`
...
...
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 Wildfly 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 WildFly 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 remote-connection create --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/jboss/wildfly/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 WildFly 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 WildFly 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.6.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 opencode@microsoft.com with any additional questions or comments.