Creating a minimal Docker image with Glassfish

docker-logoI have been using Docker to run Glassfish in a container and I noticed some news about using Alpine Linux.Apparently, you create much smaller containers with Alpine Linux. This article from Atlassian (https://developer.atlassian.com/blog/2015/08/minimal-java-docker-containers/) mentioned a minimal base image with OpenJDK.

Since I prefer to use the Oracle JDK with Glassfish 4.1, I ran a few tests myself to compare a phusion baseimage with Alpine Linux.

My Phusion based container produced an image 1130 MB large, while the Alpine Linux based image was only 392 MB. To produce a working application, I used the Primefaces showcase WAR.

I am surprised about the size differences, see the resulting images:

Phusion baseimage + Java 8 + Glassfish 4.1

phusion/baseimage         305 MB
ubuntu-oracle-jdk8        892 MB
koert/glassfish-4.1       1130 MB
koert/glassfish-showcase  1156 MB

Alpine Linux + Java 8 + Glassfish 4.1

frolvlad/alpine-oraclejdk8       170.8 MB
koert/alpine-glassfish-4.1       391.8 MB
koert/alpine-glassfish-showcase  417.8 MB

My examples at Github

 

Web application development with Docker and Glassfish

Although Docker is often used to deploy/run applications in a defined environment, you can also use Docker in your development environment. To make this productive, you need an easy way to deploy and debug your web application. In the Glassfish image (see https://github.com/koert/docker-glassfish) I can add deploy a web application and hook into the file system.

Glassfish provides an autodeploy directory – just copy a war or ear file to this directory and Glassfish will deploy this automatically. You can mount this directory to your host with the -v option:

docker run ... -v ~/tmp/glassfish/deploy:/opt/glassfish4/glassfish/domains/domain1/autodeploy ...

To view the logs directory you can add this:

docker run ... -v ~/tmp/glassfish/logs:/opt/glassfish4/glassfish/domains/domain1/logs ...

I cloned a copy of the Spring petclinic application (https://github.com/koert/spring-petclinic) to setup my development environment. Curiously, I needed to add “implements Serializable” to BaseEntity, to make it work on Glassfish 4.1. Normally, the petclinic application creates its own datasource, not a JEE datasource. I changed the configuration to use the Glassfish datasource.

The Glassfish server now needs a datasource configuration, including the database driver implementation for hsqldb. By adding the jar to /opt/app/extlib, the driver is copied to the Glassfish lib directory – this makes it available for datasources.

The configure-glassfish.sh (in /opt/app/bin) script creates the necessary datasource:

asadmin create-jdbc-connection-pool --restype=javax.sql.DataSource --datasourceclassname=org.hsqldb.jdbc.JDBCDataSource \
 --property "user=sa:password=sa:url=jdbc\:hsqldb\:hsql\:mem\:petclinic" \
 PetClinicPool
asadmin create-jdbc-resource --connectionpoolid PetClinicPool jdbc/petclinic

In the Dockerfile I add the hsqldb jar and the configure script:

ADD hsqldb-2.3.2.jar /opt/app/extlib/hsqldb-2.3.2.jar
ADD configure-glassfish.sh /opt/app/bin/configure-glassfish.sh

After building the Docker image, you can run Glassfish with the necessary configuration:

docker run --rm -it -v ~/tmp/glassfish/deploy:/opt/glassfish4/glassfish/domains/domain1/autodeploy \
 -v ~/tmp/glassfish/logs:/opt/glassfish4/glassfish/domains/domain1/logs \
 -p 4848:4848 -p 8080:8080 -p 9009:9009 \
 -e DEBUG="true" koert/glassfish-showcase

The “–rm” option instructs Docker not to keep the state of the started container, so you can start the image fresh every time. The “-it” option keeps the container running in the foreground – you can stop it with Ctrl-C.

While this is running, you can deploy your web application by copying its war or ear file to the ~/tmp/glassfish/deploy directory. You can debug the application by letting your IDE connect to port 9009.

This way you have a consist development environment with a well defined state.

Packaging a webapp with Docker and Glassfish

As I wrote in a previous article, you can run Glassfish in a Docker container.

The purpose of Docker is to package everything into a container so that you can run your application anywhere in a consistent state. To achieve this with a web application and Glassfish, you package the Java virtual machine (JDK 8), Glassfish 4.1 and your web application together.

I created an example of using my base Glassfish image with the Primefaces showcase war file:

FROM koert/glassfish-4.1
MAINTAINER Koert Zeilstra <koert.zeilstra@zencode.nl>

RUN wget http://repository.primefaces.org/org/primefaces/showcase/5.2/showcase-5.2.war -O /opt/app/deploy/showcase.war

This will download the war file and put it into the /opt/app/deploy directory – the startup script will copy this file into the Glassfish autodeploy directory. When Glassfish starts up, it will automatically deploy the war and you can access the applciation after starting with:

docker run -d -p 8080:8080 koert/glassfish-showcase

On my laptop it starts up in about 12 seconds, you can look at the application in your browser: http://localhost:8080/showcase

Look at my example on Github: https://github.com/koert/docker-glassfish-showcase