Tips and tricks for configuring WebLogic Resources on Docker boot

TL;DR I will show you that the MedRec sample application for WebLogic can be used for deploying Java artifacts and configuring WebLogic resources on first boot of a WebLogic Docker image. We can do this with a 5 line Dockerfile and a medrec.py script which customises the WebLogic domain. This example is available to play with on Github at this link.

In previous blogs, we showed how to run WebLogic with Java Applications on Docker both locally and on Oracle Container Cloud Service. We achieved this by extending the official WebLogic image from Oracle Container Registry either directly or by linking up the WebLogic autodeploy directory from another container to deploy our applications.

In this article we are going to:

  • Discuss what the official WebLogic image does on first-boot followed by options for configuring custom WebLogic resources in a WebLogic Docker Container at the first-boot stage.
  • Show an end-to-end example of Application Deployment and WebLogic Configuration using the MedRec Sample Application running on WebLogic in a Docker container
  • Discuss the drawbacks of data that is managed outside of containers. We will show that we can specifically seed the data for the MedRec application outside Docker and discuss how it could be improved to better suit the Docker deployment models.

What happens on first boot of the official WebLogic Docker image

An official WebLogic container actually ships without any WebLogic domain making it easy to extend an official WebLogic image with your own custom WebLogic domain. That said, if you do not override any defaults then on-boot the container will create an empty domain for you with some default settings. This is nice because it means you can simply run docker run -d -p 7001:7001 container-registry.oracle.com/middleware/weblogic:12.2.1.2 and then you'll immediately have a working WebLogic domain with an admin console that you can login to at http://localhost:7001/console.

You can perform basic customisations when using the official image by specifying environment variables. For example:

docker run -d -p 8001:8001 \  
  -e DOMAIN_NAME=acme_domain \
  -e DOMAIN_HOME=/u01/oracle/user_projects/domains/acme_domain \
  -e ADMIN_PORT=8001 \
  container-registry.oracle.com/middleware/weblogic:12.2.1.2

Customising WebLogic on Docker first-boot

Now what if you wanted to do some serious customisation, like adding a JDBC Data Source or some JMS Queues or Topics? How would you best achieve that with this setup?

One way to achieve this is to write some custom WLST; another way is to use MyST. Shortly, we'll look at all these options in detail but first let's dive a bit deeper into what happens on the first boot of a WebLogic Docker Container based off the official WebLogic image.

The official WebLogic image contains two key files:

On boot of the official WebLogic image it will always run createAndStartEmptyDomain.sh (as long as you don't override the ENTRYPOINT to something else). This script will automatically create an empty domain from scratch by calling out to create-wls-domain.py then it will start the Admin Console automatically. For subsequent boots, the script sees that the domain already exist so precedes to simply starting that without re-creating it again.

Option 1: Customising using WLST

Any WebLogic domain can be configured in Online or Offline mode using the WebLogic Scripting Tool (WLST) which is a Jython based interpreter for running automated WebLogic commands. Online mode assumes the server is running and Offline mode assumes it is not. The majority of common WebLogic resources such as JDBC and JMS can be configured in Offline mode.

For the WebLogic boot on Docker, the offline mode of WLST is very handy because it means we can configure WebLogic resources at the same time that the domain is automatically created before we start it up. That means that when the WebLogic domain boots up, it will automatically have our custom WebLogic resources added such as JDBC, JMS, Workmanagers and so on.

So how do we do it? One simple way is to take a copy of create-wls-domain.py and then add our custom WLST offline at the end of the file. Specifically, we can add out custom WLST code after closeTemplate but before exit().

If we extend the official image by copying in our customised create-wls-domain.py then it will get used instead of the default one. To do this we can have a simple Dockerfile like this:

FROM container-registry.oracle.com/middleware/weblogic:12.2.1.2  
COPY create-wls-domain.py /u01/oracle/  

When we build any image based on the above Dockerfile it will create a WebLogic domain on first boot with all of the customisations that we want. Pretty neat right?

Option 2: Using MyST for Docker container configuration automation

The previous option we showed requires some degree of low-level scripting knowledge. If you want to avoid this altogether another option is to use MyST where you can declaratively define the configuration to be included in your WebLogic Docker Container using the MyST Studio web-console. You can learn more about this approach in our Continuous Configuration Automation video series.

MedRec - An end-to-end example

As we showed in a previous blog, you can easily deploy WebLogic Applications on first-boot by including them in the autodeploy directory of the domain home. After the domain is created at the domain home directory it will see WebLogic Applications existing in the autodeploy directory and automatically deploy them on first-boot. Let's use the MedRec monolithic application to build on that concept and extend it to also configure the Derby Data Source required for the MedRec database.

Consider we have the following files in a local directory:

├── Dockerfile
├── medrec.ear
├── medrec.py
├── physician.ear
└── seed
    ├── medrec-data-import.jar
    └── medrec-domain.jar

We can find copies of these files in a typical WebLogic Server installation with the sample apps included (it's an option at install time). These sample apps do not exist in the WebLogic installation that ships with Docker because it is intentionally kept light. You can obtain these files from a WebLogic installation containing sample apps and copy them to our directory where our Dockerfile exists.

cp $ORACLE_HOME/wlserver/samples/server/medrec/dist/standalone/medrec.ear .  
cp $ORACLE_HOME/wlserver/samples/server/medrec/dist/standalone/physician.ear .  
cp $ORACLE_HOME/wlserver/samples/server/medrec/dist/modules/medrec-data-import.jar seed/.  
cp $ORACLE_HOME/wlserver/samples/server/medrec/dist/modules/medrec-domain.jar seed/.  

Our medrec.py contains our WLST Offline changes to add the MedRec data source. We will reference this from our Dockerfile, let's dig into that file.

FROM container-registry.oracle.com/middleware/weblogic:12.2.1.2  
COPY medrec.ear physician.ear $DOMAIN_HOME/autodeploy/  
COPY medrec.py /u01/oracle/  
COPY seed /u01/oracle/seed  
RUN sed -i -e "66r /u01/oracle/medrec.py" /u01/oracle/create-wls-domain.py  

Let's look at this line by line:

  • 1: We pull down the official WebLogic Image. For this to work make sure you have logged into the Oracle Container Registry and accepted the terms in the last 24 hours. Details on this are described here.
  • 2: We copy the medrec.ear and physican.ear to the $DOMAIN_HOME/autodeploy/ directory so they will be automatically deployed
  • 3: We copy our medrec.py which has our WLST offline automation script for creating the MedRec data source into the container at /u01/oracle/
  • 4: We add the seed directory which contains medrec-domain.jar and medrec-data-import.jar to our container at /u01/oracle/seed/. We are going to use these jars later to seed the data for the MedRec application.
  • 5: This is a bit of a hack, but it works nicely! Because I know that create-wls-domain.py already exists in the official image then I can use this line of code to inject the contents from medrec.py to line 66 to the existing file. Bear in mind for different version of the official image the line to inject at may change. Of course, if you want to follow the previous approach we showed where you have a create-wls-domain.py with your WLST customisations already included you can simply do COPY create-wls-domain.py /u01/oracle/create-wls-domain.py and that will work just as well. In that case, you wouldn't need line 3 and 5 just the additional COPY.

So what are we waiting for, let's build our image and start it up!

docker build -t craigbarrau/medrec-monolith .  
docker run -d -p 7001:7001 craigbarrau/medrec-monolith  

After a few minutes we should be able to access our application at http://localhost:7001/medrec.

But we can't really interact with that yet - it doesn't have any data seeded! For instance, if you try to login you will get this error:

Error 500--Internal Server Error

javax.faces.el.EvaluationException: javax.ejb.EJBException: EJB Exception: : javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.4.v20160829-44060b6): org.eclipse.persistence.exceptions.DatabaseException  
Internal Exception: java.sql.SQLSyntaxErrorException: Schema 'MEDREC' does not exist  

A note on managing data in containers

A great pattern for managing data required by web applications running in containers, is to have the required data seeding be handled by the application itself. This can significantly simplify the deployment process because it will allow the application to be in control of seeding missing data. We will discuss this approach in more detail in a later blog where we look at the benefits of Liquidbase for automated database change management and how it can be used from a web application to bring any state of the database into alignment with the version of the application that is being deployed.

As we do not have such a facility for our MedRec application or rather it hasn't been built in a way to seed the data on boot, we will have to do this manually. If you recall, in our Dockerfile we included some jars into /u01/app/seed. We are going to connect into our Docker container using docker exec and use these jars to seed our data to the in-memory derby database that runs by default on the WebLogic docker container.

docker exec -ti medrec-monolith /bin/bash -c "java -classpath \$ORACLE_HOME/seed/medrec-data-import.jar:\$ORACLE_HOME/seed/medrec-domain.jar:\$ORACLE_HOME/wlserver/common/derby/lib/derbyclient.jar:\$ORACLE_HOME/wlserver/server/lib/weblogic.jar com.oracle.medrec.util.DataImporter"  

After we have ran this, from MedRec app we can click on Login in the top right corner then under Patient we can Login with fred@golf.com and password of weblogic. If we logged in successfully we should see a screen similar to the one below and then we will know that the data is seeded correctly.

I hope you have found this post useful! Stay tuned for future posts where we break this monolithic MedRec application into Polyglot Microservices.

Come see us at Oracle Code

If you're in Sydney on Tuesday the 18th of July, you may be interested in the free Oracle Code event. I am doing a session with Arun Pareek titled Make your Microservices Sing! The important role of Containers and DevOps. We will be talking specifically about the MedRec application and using it as an example demonstrating good practises for breaking down a Monolith into a Microservice. In addition, Rubicon Red will have an exhibit where we will be demoing a Microservice-based IOT solution for health based on the Oracle Cloud. If you're there, do come along and say hi, it's always great to chat Docker, Microservices and WebLogic Automation with like-minded people!

Craig Barr

I am a Software Engineer with a decade of experience empowering Enterprises in Banking, Logistics, Manufacturing with Service-Oriented Architecture, Microservices and Cloud Computing.

Brisbane, Australia https://twitter.com/craigbarrau

Subscribe to Oracle PaaS, Oracle Middleware and DevOps

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!