Supercharge the value of your Java investments with WebLogic Server on Docker

TL;DR WebLogic Applications can be deployed to Oracle Container Cloud using a separate application image and volume mapping to the official WebLogic image for Docker at runtime as shown in this 2 minute video.

The Oracle Container Cloud Service is an easy way to start running Docker containers on the Cloud. When combined with the Oracle Container Registry, we can pull down official pre-built images for platforms such as WebLogic Server, Coherence, Tuxedo and of course the Oracle Database. In a few minutes, they'll be running out-the-box.

But have we delivered any real value pushing an empty containerised WebLogic Server or Oracle Database instance to the Cloud. Yes, it may excite the inner nerd in some of us, but it's also a bit like manufacturing a school bus that never delivers children to the school. What we really need to deliver is valuable running applications, not just an empty chassis.

So how can we create a WebLogic Docker image with Java Enterprise Edition (JEE) applications and resources?

  • Should we bake our own image from scratch including the apps?
  • Should we extend the official image to include the apps?
  • Or, should we volume map our apps at deploy-time?

All of the above are viable options each with their own Pros and Cons.

Let's explore them.

Bake our own 😟

Building new images in Docker is not difficult for those comfortable with Shell Scripting. We can create a Dockerfile FROM an existing image such as oraclelinux:7-slim, indicate the files we want to COPY into our image, set some ENV variables, RUN the various shell commands we need to configure it and finally define the ENTRYPOINT for our container when it is booted.

Consider we have the following files in a local directory:

├── configure.py
├── Dockerfile
├── fmw_12.2.1.0.0_infrastructure.jar
├── sample.war
└── weblogic.rsp
  • fmw_12.2.1.0.0_generic.jar is the WebLogic installer
  • weblogic.rsp is the silent installation response file
  • Dockerfile is our Docker image definition
FROM oracle/serverjre:8  
ARG version=12.2.1.2.0  
COPY weblogic.rsp /tmp  
COPY fmw_${version}_wls.jar /tmp  
COPY configure.py /u01/oracle  
RUN java -jar /tmp/fmw_${version}_generic.jar \  
    -silent -responseFile /tmp/weblogic.rsp && \
    rm -f /tmp/fmw_${VERSION}_infrastructure.jar
ENV DOMAIN_NAME base_domain  
ENV DOMAIN_HOME /u01/oracle/user_projects/domains/${DOMAIN_NAME}  
COPY sample.war $DOMAIN_HOME/autodeploy/sample.war  
RUN ADMIN_PASSWORD=$(date| md5sum | fold -w 8 | head -n 1) && \  
    echo "      ----> 'weblogic' admin password: $ADMIN_PASSWORD" && \
    sed -i -e "s|temporarypass|$ADMIN_PASSWORD|g" /u01/oracle/configure.py
RUN wlst.sh /u01/oracle/configure.py  
ENTRYPOINT ${DOMAIN_HOME}/startWebLogic.sh  
  • And finally, configure.py is the python script we run from within the Dockerfile to create our WebLogic domain:
domain_name  = os.environ.get("DOMAIN_NAME")  
readTemplate("/u01/oracle/wlserver/common/templates/wls/wls.jar")  
set('Name', domain_name)  
cd('/Servers/AdminServer')  
cd('/Security/%s/User/weblogic' % domain_name)  
cmo.setPassword('temporarypass')  
setOption('OverwriteDomain', 'true')  
setOption('ServerStartMode', 'prod')  
writeDomain(os.environ.get("DOMAIN_HOME"))  
closeTemplate()  
exit()  

We can build our image with
docker build -t oracle/weblogic .

And then boot the image locally with:
docker run -d -p 7001:7001 oracle/weblogic

When our container is booted our sample.war will be automatically discovered in the autodeploy directory and deployed so that we can access it from http://localhost:7001/sample

Now that's not so hard to bake your own image in this way, but you do need to know a bit about the inner workings of automating Oracle WebLogic installation and that's just a simple example. What about running in Production Mode and using the WebLogic Node Manager or configuring WebLogic resources? If you know what you're doing you are free to bake your image any way you please, but then again, if someone's already solved your problem do you need to reinvent the wheel?

Extend the official image 😐

Oracle provide a Container Registry from where you can download official WebLogic Docker images. Once you have authenticated and accepted the terms, you can use the image as the basis for building derivative images containing your applications and resources.

Let's look at an example.

├── Dockerfile
└── sample.war

Our Dockerfile can be nice and lean. Simply we copy our sample.war to the autodeploy directory of the DOMAIN_HOME. That's it.

FROM container-registry.oracle.com/middleware/weblogic:12.2.1.2  
COPY sample.war $DOMAIN_HOME/autodeploy/sample.war  

As you can see, just by using the official image, there are less files required to get up and running with a WebLogic Docker image containing your application(s). There is no need to have an installer or response file or even a configure script because that's already done in the official image.

Again, we can build and run our image in the same way we did when we baked our own.

docker build -t oracle/weblogic .  
docker run -d -p 7001:7001 oracle/weblogic  

Distributing our images 😲

When it comes to distributing our images to the Oracle Container Cloud Server we cannot rely on any Oracle Container Registry as it is read only and not for accepting custom-built images. Instead we must push these images to a public writable Container Registry such as Docker Hub or Amazon ECR. That's when the baking and extending approaches start to hurt a little.

Consider we push either the baked or extended image to the Docker Hub. In either case, we're going to need to push the whole image (including WebLogic Server) to the Registry. That's at least 1.22 Gb. This may leave you thinking:

"Why don't I just pull down the container from Oracle Container Registry and deploy my application to it using the Admin Console or a WLST script after it has been booted?"

And there is the trap, the temptation to return to the "old way" is strong. But you don't have to do it this way...

The power of the Docker layered file system 🙂

Docker images are made up of a number of file system layers with each change building on top of the previous one. In fact, every command of our Dockerfile builds a unique image layer. This provides an amazing capability for image reuse. If we have two images based off an official Oracle WebLogic image (or even another custom image) we can be guaranteed that it will reuse the same image in both derivative images. This means that not only do we reduce the download required to run the containers based off a common base image, but we reduce the upload effort as we only ever need to upload an image once to a container registry such as Docker Hub or our own private registry.

What if we could ship our application changes as increments to the Oracle Container Cloud without needing to push the WebLogic Server image to our personal Container Registry? You can...

Lightning fast deployments 😀

Did you know you can create a Docker image that contains only your Java Application(s) and then map it at deploy-time to the WebLogic Server image?

This is a super useful way to deploy Java Applications to the cloud in seconds. You can deliver any application while avoiding a dreaded push of the whole WebLogic Server instance for each change. With the volume mapping approach, any lightweight data container can can reuse the publicly available Oracle WebLogic image at deploy-time without having to be bundled with it.

Let's create a new Dockerfile to build an image that contains nothing more than our JEE application(s).

FROM scratch  
ENV DOMAIN_HOME /u01/oracle/user_projects/domains/base_domain  
ENV DEPLOY_DIR $DOMAIN_HOME/autodeploy  
COPY sample.war $DEPLOY_DIR/sample.war  
VOLUME $DEPLOY_DIR  

Notice we are building our image FROM scratch meaning that we aren't basing it from any other image and that we are creating a VOLUME for our autodeploy directory. This will allow us to map it to another WebLogic Server image provided the DOMAIN_HOME matches up with that in our application image.

Let's build that image.

docker build -t rubiconred/wls-sample-app .  

Once the image is built we can use docker-compose to test it out locally before we try it on the Oracle Container Cloud Service. Let's create a docker-compose.yml file as below:

version: '2'  
services:  
  server:
    image: 'container-registry.oracle.com/middleware/weblogic:12.2.1.1'
    ports:
      - '7001:7001/tcp'
    volumes_from:
      - app
  app:
    image: rubiconred/wls-sample-app

Let's run our stack with the following:

docker-compose up -d  

After a few minutes our image will be downloaded from the Oracle Container Registry (provided we accepted the terms and did a docker login prior to running docker-compose. This process is documented in detail here).

Data Container Benefits

Data containers as demonstrated in the previous example are a great way to ship small applications when the alternative of bundling a whole application with the stack that runs it is not feasible. This can be the case when you have no private Docker Registry available, when you are concerned about breaching the EULA by distributing your application with WebLogic Server or when you want to avoid a redundant push of data that is already available in the official image anyway. Fortunately, you don't need to worry about any of these concerns when you are using data containers and dynamically linking them to an official WebLogic Docker image at deploy-time.

Data Container Limitations

You will have seen in the previous example that I built the Application Docker Image FROM scratch and it worked nicely with docker-compose. To dig a bit into what happened under the covers, the data container started and the volume was mapped to the WebLogic Server container. After this, the data container shutdown because it had no command or entrypoint defined that would substantiate it's need to keep running. That's fine though as we don't need it to be running once the data volume has mapped to the underlying WebLogic Server instance.

Unfortunately, it will not necessarily work the same in all Container Cloud solutions. That is because production solutions may see a container shutting down immediately after a start as problematic and attempt to restart that. This is known as 'Flapping Containers'.

The thing with data containers is that it is expected for them to shutdown immediately as part of the happy path. At the time of writing the Oracle Container Cloud Service does not appear to specifically support this scenario but there is a pretty neat workaround that you can do to get this going. We can add command to our docker-compose.yml and execute sleep so the data container stays running and Oracle Container Cloud Service is happy. So, let's make two adjustments to get our stack working on the Oracle Container Cloud Service.

First, we will update our Application Image to be based FROM busybox instead of scratch. This will ensure that the sleep command will be available at runtime. Busybox is a tiny operating system so our image will still be very small.

FROM busybox  
ENV DOMAIN_HOME /u01/oracle/user_projects/domains/base_domain  
ENV DEPLOY_DIR $DOMAIN_HOME/autodeploy  
COPY sample.war $DEPLOY_DIR/sample.war  
VOLUME $DEPLOY_DIR  

Then, let's update our docker-compose.yml with the sleep instruction.

version: '2'  
services:  
  server:
    image: 'container-registry.oracle.com/middleware/weblogic:12.2.1.2'
    ports:
      - '7001:7001/tcp'
    volumes_from:
      - app
  app:
    image: rubiconred/wls-sample-app
    command: sh -c 'while sleep 3600; do :; done'

Setting up our Registry in Container Cloud

We're almost ready to run our WebLogic Application Stack on the Oracle Container Cloud Service (OCCS). Let's jump over to the Registries section and enter our details for the Oracle Container Registry. This will allow OCCS to be able to pull down the official Oracle WebLogic Image at deploy-time. If we are hosting our Application Image on the public Docker Hub, we don't need to do anything else for that to be pulled down, but if we are instead using a private registry for our Application Image, we will also want to add this private registry and our credentials under Registries as well. For more detailed instructions on setting up the registries in OCCS you may be interested in my previous blog on the subject.

Up and Running on the Cloud in 2 Minutes 😍

Now that our OCCS instance is able to easily pull down the official WebLogic image and our Application image, we can simply copy and paste the stack definition from docker-compose.yml into the Advanced section of our stack. Let's click Deploy and voilà!

We have pushed our locally tested WebLogic Java Application(s) to the Oracle Container Cloud Service in a few minutes. We are running the exact same containers as we tested on our local workstation in the cloud, pretty neat?

Want to see that in action?

I recently delivered a 2 minute tech tip for the OTNArchBeat where I step through the details using a Java application for Medical Records. I hope you find it useful.

Happy shipping!

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!