Lifting a Java EE application to Verrazzano

January 28, 2022 | 20 minute read
Rafael Benevides
Principal Product Manager
Text Size 100%:

After showing how to install a local Verrazzano cluster and explore how to deploy a Helidon MicroPropfile application to it, today we will see how to deploy a Java EE application that runs on Weblogic.  

Because we will assume that an existing application already runs outside Verrazano, it makes total sense to explore it locally before trying to deploy it to Verrazzano.
 

The repository https://github.com/rafabene/verrazzano-demo contains not only the existing Java EE application under the folder `weblogic-app`, but also the Helidon application in the folder `helidon-ms` that we deployed previously as a standalone microservice, and it's used by the Java EE application.

 

Make sure to clone it using the following command:

git clone https://github.com/rafabene/verrazzano-demo

The following diagram will help you to understand the overall architecture of the application that we will deploy. Note that it covers a brownfield application (existing Java EE application), a microservice (built with Helidon), and a Database (mySQL). This scenario shows the usual step to lift and shift an application toward a Cloud Native architecture. 


 


 

Given the existing diagram, let's first start both "services" (helidon-ms and mySQL) on which the `weblogic-app` depends.

  1. First let's start mySQL using the ease of containers:
docker run --name greetingsdb \
  -p 3306:3306 \
  -e MYSQL_USER=myuser \
  -e MYSQL_PASSWORD=12345678 \
  -e MYSQL_DATABASE=greetingsdb \
  -e MYSQL_ROOT_PASSWORD=admin123 \
  -d mysql:8
  1. Now, go to the folder where you git cloned the verrazzano-demo repository. Change the directory to the `helidon-ms` folder, compile, package and execute it:
cd helidon-ms

 mvn clean package

java -jar target/helidon-ms.jar
  1. Finally go to the Weblogic downloads page, and download the generic Weblogic version 14.x. Once that you have Weblogic installed, execute the following command, using another terminal tab or window (from Weblogic root path), to create a domain using the specification bellow:
./Middleware/Oracle_Home/oracle_common/common/bin/config.sh​​​​​​
  • Select  Create new Domain.
  • Specify the location: <oracle_home>/user_projects/domains/demodomain  (and Click Next).
  • Use the Basic WebLogic Server Domain [wlserver] (and click Next).
  • Enter the username and password for the administrative user (and click Next).
  • Domain mode: Development (Default).
  • JDK: – Select a JDK 11 folder (and click Next).
  • Select: Administration Server (and click Next).
  • Keep the default parameters for AdminServer screen (and click Next).
  • Click on Create
  1. Run the following command (from Weblogic root path) to start the demodomain that has been created.
./Middleware/Oracle_Home/user_projects/domains/demodomain/startWebLogic.sh
  1. Now, open the administrative console URL http://localhost:7001/console in your browser. We need to access the Administrative console to create the datasource and deploy the Java EE application.

Creating a datasource in the Weblogic "demo domain".

Once you login in the administrative console ( http://localhost:7001/console ) using the credentials provided during the creation of the domain, go to Services -> Data Sources. Select New -> Generic Data Source. Fill the page with the following data:

Click on the Next button. You can keep the default database driver, and the default transaction options by clicking on Next on these two screens.

Finally, configure the Connection properties using the following data:

  • Database name: greetingsdb (provided in the docker command above)
  • Host name: localhost
  • Port: 3306
  • Database User Name: myuser (provided in the docker command above)
  • Password: 12345678 (provided in the docker command above)

Click on the Next button. Hit the "Test Configuration" button to make sure that Weblogic will be able to communicate with MySQL running as a container. You should see a green message saying "Connection test succeeded".

If the test succeeded, DON'T HIT the "Finish" button yet. Click on the "Next" button, and select the "AdminServer" as the Target. Now you can click on the "Finish" button in this screen and we are done creating the datasource to be used by the application.

Deploying the Java EE application to Weblogic

Now it's time to prepare our application to execute it inside Weblogic. First we need to return to our previously cloned git repository and compile/package the application using the following commands:

cd weblogic-app/

mvn clean package

With our weblogic-app.war successfully built, we can return to Weblogic administrative console and select "Deployments" in the menu. Click on the "Install" button. Navigate to the folder where weblogic-app.war is located. Select it and click on the "Next" button.  Keep "Install this deployment as an application" selected and click on the "Next" button on the screen.

In the "Optional Settings" screen, keep the default values and click on the "Finish" button.You should see a green message saying "The deployment has been successfully installed".
 

Finally, open the URL http://localhost:7001/weblogic-app/ in your browser and you should see the Java EE application deployed. Make sure that the Helidon application is running locally at http://localhost:8080. Type your name, a message and hit the "Submit" button. You should see a greeting coming from the Helidon application, and your message stored in the database (table below).

 

Lifting and shifting Weblogic to Verrazzano

Now that we have our application locally, let's move it to Verrazzano. Remember that the steps described here can be used to deploy to a Verrazzano instance running on the Cloud.

To achieve this task, we will count on WDT (Weblogic Deploy Tooling). This  tool helps to automate the deployment of Weblogic, and also helps us to create Verrazzano OAM files that we will need to deploy Weblogic on Verrazzano.

Having said that, let's download and install WDT using the following commands:

curl -OL https://github.com/oracle/weblogic-deploy-tooling/releases/latest/download/weblogic-deploy.zip

unzip weblogic-deploy.zip

cd weblogic-deploy

export WDT_HOME=$(pwd)

After installing WDT, we can execute it using the parameters needed to read our existing Weblogic "demodomain", create the Verrazzano files (-target vz), and place them in the verrazzano_files folder. Below are the commands for this step. Note that you might need to adjust your path.

mkdir verrazzano_files/

$WDT_HOME/bin/discoverDomain.sh \
  -oracle_home ~/java/Oracle/Middleware/Oracle_Home \
  -domain_home ~/java/Oracle/Middleware/Oracle_Home/user_projects/domains/demodomain \
  -model_file ./verrazzano_files/wdt-model.yaml \
  -archive_file ./verrazzano_files/wdt-archive.zip \
  -target vz \
  -output_dir verrazzano_files/

To have an idea on how WDT helps in this process, we can recall the previous blog post where we deployed an Helidon application to Verrazzano and we needed to manually create the OAM Verrazzano files ( component.yaml and application-config.yaml). That made sense as it was a greenfield application. In this case, the Weblogic domain already exists and it is fully functional. What WDT did was to extract all the information (application, datasource, etc) from the "demodomain" and make them available in a OAM format to be deployed to Verrazzano. If you explore the verrazzano_files folder, you will find the following resources:

  • create_k8s_secrets.sh - A helper script with kubectl commands to apply the Kubernetes secrets needed for this domain like datasource credentials.
  • vz-application.yaml - Verrazzano application configuration and component file
  • vz_variable.properties - A set of properties extracted from the WDT domain model that contains the datasource information.
  • wdt-archive.zip - The WDT archive file containing the application WAR file
  • wdt-model.yaml - The WDT model of the WebLogic Server domain

Creating a container image

To execute the application in Verrazzano, we need that application to become available in a container format. To help simplify and automate the creation of container images for WebLogic Server, Oracle provides the open source WebLogic Image Tool (WIT).

WIT lets you create a new Linux based image, with installations of a JDK and WebLogic Server, and optionally, configure a WebLogic domain. So, just like we did with WDT, let's download this tools and install it using the following commands:

cd ..

curl -OL https://github.com/oracle/weblogic-image-tool/releases/latest/download/imagetool.zip

unzip imagetool.zip

cd imagetool/

export WIT_HOME=$(pwd)


Let's now use WIT to create the Docker image. Although WIT will download patches for you, it does not yet download installers. Until then, you must download the WebLogic Server and Java Development Kit installers manually and provide their location to the "imagetool cache addInstaller" command. One small note: Remember to download the JDK 11 (for Linux) as the container that we will create will be a Linux container, and Weblogic supports the version 11.  To execute the commands below, remember to adjust the paths to match the paths in your computer. 

cd $WDT_HOME/verrazzano_files

# Adds the JDK
$WIT_HOME/bin/imagetool.sh cache addInstaller \
  --path  ~/java/jdk-11.0.14_linux-x64_bin.tar.gz \
  --type jdk \
  --version 11u14

# Adds the installation of Weblogic
$WIT_HOME/bin/imagetool.sh cache addInstaller \
  --path ~/java/fmw_14.1.1.0.0_wls_lite_generic.jar \
  --type wls \
  --version 14.1.1.0.0

# Adds the WDT Installer
$WIT_HOME/bin/imagetool.sh cache addInstaller \
  --path ~/java/weblogic-deploy.zip \
  --type wdt \
  --version latest

# Creates the container image using JDK, Weblogic, WDT,
# and the Verrazzano files that has been created
$WIT_HOME/bin/imagetool.sh create \
  --tag myrepo/myuser/weblogic:1.0 \
  --version 14.1.1.0.0 \
  --jdkVersion 11u14 \
  --wdtModel ./wdt-model.yaml \
  --wdtArchive ./wdt-archive.zip \
  --wdtVariables ./vz_variable.properties \
  --resourceTemplates=./vz-application.yaml \
  --wdtModelOnly

 

Finally we have a container image locally. And just like we did previously when we deployed the Helidon application, we will load this image inside Kind to be used by Verrazzano. To load the image in kind type the following command:

kind load docker-image myrepo/myuser/weblogic:1.0

Deploying the application to Verrazzano

If you didn't follow the steps in the previous blog, make a pause. Open the previous blog post in another browser tab. Create the kubernetes namespace ( demo-application ), create the container image for the Helidon application, and deploy it. Tip: You can use the provided OAM files from the git repository https://github.com/rafabene/verrazzano-demo
 

If you have the Helidon application running inside Verrazzano, you can continue now with the steps below to deploy the Weblogic application to Verrazzano.

 

Creating a Kubernetes Secret

When we used the WDT tool to extract information from the Weblogic demodomain, all resources but its credentials were extracted. This is due to the fact that passwords inside Weblogic are strongly stored and cannot be discovered in any way. 

 

The solution is to provide those credentials again in the file verrazzano_files/create_k8s_secrets.sh. You can choose your favorite text editor, and look for the lines that run create_paired_k8s_secret, and update the credentials of weblogic and the jdbc-greetingsdb.  Just as a reminder, if you didn't change the password for MySQL, you should use `12345678` here.

Change also the NAMESPACE variable to match the one that we are using: demo-application

NAMESPACE=demo-application

Save the file and execute it: 

./create_k8s_secrets.sh

 

Point the application to the MySQL database and Helidon inside Verrazzano.

When we created the datasource in our "demodomain" in Weblogic, the database host used was localhost. Remember that we used docker command to execute MySQL in a local container? That's it! However, we need to forget about every local resource used, and start using those resources inside Verrazzano like MySQL and the Helidon application that is already deployed.

First of all, we need to deploy MySQL using the OAM format. For that, create a file called mysql-oam.yaml with the following content:

apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
 name: greetingsdb-mysql-service
spec:
 workload:
   apiVersion: v1
   kind: Service
   metadata:
     name: mysql
   spec:
     ports:
       - port: 3306
         name: mysql
     selector:
       app: mysql
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
 name: greetingsdb-mysql-deployment
spec:
 workload:
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: mysql
   spec:
     progressDeadlineSeconds: 600
     replicas: 1
     revisionHistoryLimit: 10
     selector:
       matchLabels:
         app: mysql
     strategy
       type: Recreate
     template:
       metadata:
         creationTimestamp: null
         labels:
           app: mysql
       spec:
         containers:
           - env:
               - name: MYSQL_ROOT_PASSWORD
                 valueFrom:
                   secretKeyRef:
                     name: demodomain-jdbc-greetingsdb
                     key: password
               - name: MYSQL_USER
                 valueFrom:
                   secretKeyRef:
                     name: demodomain-jdbc-greetingsdb
                     key: username
               - name: MYSQL_PASSWORD
                 valueFrom:
                   secretKeyRef:
                     name: demodomain-jdbc-greetingsdb
                     key: password
               - name: MYSQL_DATABASE
                 value: greetingsdb
             image: mysql:latest
             imagePullPolicy: IfNotPresent
             name: mysql
             ports:
               - containerPort: 3306
                 name: mysql
                 protocol: TCP
             resources: {}
             terminationMessagePath: /dev/termination-log
             terminationMessagePolicy: File
             volumeMounts:
               - mountPath: /docker-entrypoint-initdb.d
                 name: mysql-initdb
         dnsPolicy: ClusterFirst
         imagePullSecrets:
           - name: ocr
         restartPolicy: Always
         schedulerName: default-scheduler
         securityContext: {}
         terminationGracePeriodSeconds: 30
         volumes:
           - configMap:
               defaultMode: 420
               name: mysql-initdb-config
             name: mysql-initdb
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
 name: greetingsdb-mysql-configmap
spec:
 workload:
   apiVersion: v1
   kind: ConfigMap
   metadata:
     name: mysql-initdb-config
   data:
     initdb.sql: |
       CREATE TABLE Message (ID BIGINT NOT NULL, MESSAGE VARCHAR(255), TIMESTAMP DATETIME, USERNAME VARCHAR(255), PRIMARY KEY (ID));
       CREATE TABLE SEQUENCE (SEQ_NAME VARCHAR(50) NOT NULL, SEQ_COUNT DECIMAL(38), PRIMARY KEY (SEQ_NAME));
       INSERT INTO SEQUENCE( SEQ_NAME, SEQ_COUNT) VALUES ('SEQ_GEN', 0);
       INSERT INTO Message (ID, USERNAME, MESSAGE, TIMESTAMP) VALUES (99999, 'Benevides', 'Hello World', '2015-06-10 22:10:00');

 

Now execute the command below to deploy the MySQL on Verrazzano:

kubectl apply -n demo-application -f mysql-oam.yaml

Remember that Verrazzano won't deploy any resources until we deploy the ApplicationConfiguration file. 

 

Make the necessary changes to vz-application.yaml

So first, edit the vz-application.yaml file (the file generated by WDT), and change the JDBC URL to: 

jdbc:mysql://mysql.demo-application.svc.cluster.local:3306/greetingsdb 

Also add a reference to the MySQL OAM components that we deployed using the mysql-oam.yaml file:

- componentName: demodomain-configmap
- componentName: greetingsdb-mysql-service
- componentName: greetingsdb-mysql-deployment
- componentName: greetingsdb-mysql-configmap

Because we used DeltaSpike config to externalize the configuration of the application, we need also to just add an environment variable pointing to the internal address of the Helidon application:

- name: helidonURL
  value: "http://hello-helidon-deployment.demo-application.svc.cluster.local:8080"

 

 

We are not using images from a private container registry, so we can remove the reference to  imagePullSecrets: demodomain-registry-credentials

Finally, remove all references to namespaces as we will inform the proper namespace using the "kubectl -n" namespace command.
The altered file should be like this one:

# Copyright (c) 2020, 2021, Oracle and/or its affiliates.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
apiVersion: core.oam.dev/v1alpha2
kind: ApplicationConfiguration
metadata:
 name: demodomain-appconf
 annotations:
   version: v1.0.0
   description: "demodomain application configuration"
spec:
 components:
   - componentName: demodomain-domain
     traits:
       - trait:
           apiVersion: oam.verrazzano.io/v1alpha1
           kind: MetricsTrait
           spec:
             scraper: verrazzano-system/vmi-system-prometheus-0
       - trait:
           apiVersion: oam.verrazzano.io/v1alpha1
           kind: IngressTrait
           spec:
             rules:
               - paths:
                   # application weblogic-app
                   - path: "/weblogic-app"
                     pathType: Prefix
   - componentName: demodomain-configmap
   - componentName: greetingsdb-mysql-service
   - componentName: greetingsdb-mysql-deployment
   - componentName: greetingsdb-mysql-configmap
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
 name: demodomain-domain
spec:
 workload:
   apiVersion: oam.verrazzano.io/v1alpha1
   kind: VerrazzanoWebLogicWorkload
   spec:
     template:
       metadata:
         name: demodomain-domain
       spec:
         domainUID: demodomain
         # WebLogic Image Tool provides domainHome, domainHomeSourceType, and imageName
         domainHome: /u01/domains/base_domain
         domainHomeSourceType: FromModel
         image: myrepo/myuser/weblogic:1.0
         includeServerOutInPodLog: true
         webLogicCredentialsSecret:
           name: demodomain-weblogic-credentials
         configuration:
           introspectorJobActiveDeadlineSeconds: 900
           model:
             configMap: demodomain-configmap
             domainType: WLS
             # WebLogic Image Tool provides modelHome
             modelHome:
             # encryption for the WDT model and the SystemSerializedIni.data file.
             # used only for model-in-image deployment, can be removed for other types.
             runtimeEncryptionSecret: demodomain-runtime-encryption-secret
           secrets:
             - demodomain-jdbc-greetingsdb
         serverPod:
           env:
             - name: JAVA_OPTIONS
               value: "-Dweblogic.StdoutDebugEnabled=false"
             - name: USER_MEM_ARGS
               value: "-Djava.security.egd=file:/dev/./urandom -Xms64m -Xmx256m"
             - name: helidonURL
               value: "http://hello-helidon-deployment.demo-application.svc.cluster.local:8080"
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
 name: demodomain-configmap
spec:
 workload:
   apiVersion: v1
   kind: ConfigMap
   metadata:
     name: demodomain-configmap
     namespace: demodomain
   data:
     wdt_jdbc.yaml: |
       resources:
         JDBCSystemResource:
           'greetingsdb':
             JdbcResource:
               JDBCDriverParams:
                 # This is the URL of the database used by the WebLogic Server application
                 URL: "jdbc:mysql://mysql.demo-application.svc.cluster.local:3306/greetingsdb"

 

And now we can deploy it using the command:

kubectl -n demo-application apply -f vz-application.yaml

This will trigger the Weblogic operator to set up our Weblogic image  (with our pre-configured "demodomain") in Kubernetes, and also deploy the MySQL components (Deployment, Service, and ConfigMap) from mysql-oam.yaml file.

 

Before accessing the application, make sure it's ready by running the command:

kubectl wait -n demo-application pod \
  -l job-name=demodomain-introspector \
  --timeout=20m \
  --for=delete &&   \
kubectl -n demo-application wait \
  pod/demodomain-adminserver \
  --timeout=20m  \
  --for=condition=Ready

Allowing Weblogic to access the Helidon application

Because Verrazzano provides a high level of security enabled by default, the Weblogic application won't be able to reach the Helidon application endpoint. If you try to do it, the endpoint will reply with a 403 (forbidden) error and a message "RBAC: Permission denied".

To allow the Helidon application to receive requests from the Weblogic application, we need to modify Helidon's Authorization Policy to add the Security Account of Weblogic as a Principal. To modify the Authorization Policy of Helidon's application, run the following command:

kubectl patch -n demo-application \
  authorizationpolicy hello-helidon-appconf \
  --type=json \
  --patch '[{"op":"add", "path":"/spec/rules/0/from/0/source/principals/-", "value":"cluster.local/ns/demo-application/sa/demodomain-appconf"}]'

 

Access the application on Verrazzano

With the application deployed. We can use the command below to get the Host where the Weblogic application is running:

kubectl get gateway -n demo-application \
  demo-application-demodomain-appconf-gw \
  -o jsonpath='{.spec.servers[0].hosts[0]}'

If the demo-application-demodomain-appconf-gw was not found, it means that Verrazzano is still provisioning the required resources. Just wait a little bit more and try again. When it's done, It should reply with something like demodomain-appconf.demo-application.172.18.0.23X.nip.io. In this case, open HTTPS://demodomain-appconf.demo-application.172.18.0.23X.nip.io/weblogic-app/

Try it, and make sure that the application is communicating with MySQL and the Helidon microservice. 

 

 

For MacOS 

If you can't access this endpoint in the browser due to certificate issues, run the following commands in the MacOS terminal to import the certificate to your keystore.

kubectl get gateway -n demo-application \
  demo-application-demodomain-appconf-gw \
  -o jsonpath='{.spec.servers[0].hosts[0]}'

openssl s_client -connect 172.18.0.23?:443 -servername demodomain-appconf.demo-application.172.18.0.23?.nip.io -showcerts 2>/dev/null </dev/null |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/weblogic.pem

sudo security add-trusted-cert -d -r trustAsRoot -k /Library/Keychains/System.keychain ~/weblogic.pem

Conclusion

In this blog post we saw how it's easy to extract information from an existing Weblogic domain that accesses MySQL and Helidon services and  "lift-and-shift" all of them to Verrazzano using tools like WDT and WIT

Furthermore, we also have some security aspects of Verrazzano like using secrets to store credentials of MySQL and Weblogic, usage of SSL for the application endpoints, and finally how the application internal access is blocked until we allow it in the Authorization Policy. 

Check out more details about Verrazzano on its webpage: https://verrazzano.io  and https://www.oracle.com/java/verrazzano/  . At the Verrazzano's Youtube channel, you will see a Verrazzano tour video and much more. News about this project is shared on Verrazzano's Twitter profile. Verrazzano is a fast paced evolving open source project. You can follow, and also contribute to this awesome project on the Github project page

 

Rafael Benevides

Principal Product Manager

Rafael Benevides is a Principal Product Manager at Oracle. With many years of experience in several fields of the IT industry, he helps developers and companies all over the world to be more effective in software development. Rafael considers himself a problem solver who has a big love for sharing. He is a member of Apache DeltaSpike PMC - a Duke’s Choice Award winner project, and a speaker in conferences like JavaOne, Devoxx, TDC, DevNexus and many others.
Twitter | LinkedIn | rafabene.com


Previous Post

Accessing Autonomous Database with IAM token using Java

Nirmala Sundarappa | 5 min read

Next Post


Oracle sponsors this years’ FormulaAI Hackathon

Bo English-Wiczling | 2 min read