Reading Time: 4 minutes

Sometimes I need to be hit in the head with an axe to find a solution to a problem that has been bugging me forever. A minimal Java container has been on my wish list since I found out about Docker and I’ve been writing about running Java in Docker for sometime already.

Official Java images have historically been mastodontic – cue picture above – I just tried “ docker pull java ” and I got an image of 816.4MB . A colleague of mine few days ago mentioned Alpine Linux, a minimalistic Linux distribution based on musl libc and BusyBox that comes with a nice package manager. And the base image is … 5Mb ?! Where have I been hiding? Why didn’t I know about this?! Anyway here’s my chance to make things right. The objective: to have a minimal Java container for my (and your) applications. Let’s dream together.

If OpenJDK 7 is good enough

If you are still using JDK7 and you don’t have a strong requirement to have the Oracle version, the easiest and leaner image I found is very simple to setup with this Dockerfile :

FROM alpine:3.2 RUN apk --update add openjdk7-jre CMD ["/usr/bin/java", "-version"]

Build it with:

docker build -t yourname/minimal-java .

Or if you are lazy just:

docker pull durdn/minimal-java

Now you can test that java is installed with:

docker run -t durdn/minimal-java

Which outputs:

java version "1.7.0_79" OpenJDK Runtime Environment (IcedTea 2.5.5) (Alpine 7.79.2.5.5-r0) OpenJDK 64-Bit Server VM (build 24.79-b02, mixed mode)

The result is a Java 7 runtime environment, ready for your Java 7 applications in only 123MB instead than 800+MB . NICE!

What about Oracle JRE/JDK 8?

For many applications teams prefer or require the Oracle JDK. In this case we can’t use Alpine package manager (yet), we have to wrangle the installation ourselves from the official Oracle packages. Do you want to see how that’s done? This is the list of steps:

Install curl , tar , and ca-certificates on the base alpine image.

, , and on the base image. Install glibc-2.21 which is a hard dependency of Java 8.

which is a hard dependency of Java 8. Download the Oracle JRE/JDK using tricks in this SO article.

Remove spurious folders not needed (like jdk/jre/lib/desktop and others…).

and others…). Set the proper environment variables.

The whole process is well laid out amongst others in a clean Dockerfile by anapsix which I list here for completeness:

# AlpineLinux with a glibc-2.21 and Oracle Java 8 FROM alpine:3.2 MAINTAINER Anastas Dancha [...] # Install cURL RUN apk --update add curl ca-certificates tar && curl -Ls https://circle-artifacts.com/gh/andyshinn/alpine-pkg-glibc/6/artifacts/0/home/ubuntu/alpine-pkg-glibc/packages/x86_64/glibc-2.21-r2.apk > /tmp/glibc-2.21-r2.apk && apk add --allow-untrusted /tmp/glibc-2.21-r2.apk # Java Version ENV JAVA_VERSION_MAJOR 8 ENV JAVA_VERSION_MINOR 45 ENV JAVA_VERSION_BUILD 14 ENV JAVA_PACKAGE jdk # Download and unarchive Java RUN mkdir /opt && curl -jksSLH "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/${JAVA_VERSION_MAJOR}u${JAVA_VERSION_MINOR}-b${JAVA_VERSION_BUILD}/${JAVA_PACKAGE}-${JAVA_VERSION_MAJOR}u${JAVA_VERSION_MINOR}-linux-x64.tar.gz | tar -xzf - -C /opt && ln -s /opt/jdk1.${JAVA_VERSION_MAJOR}.0_${JAVA_VERSION_MINOR} /opt/jdk && rm -rf /opt/jdk/*src.zip /opt/jdk/lib/missioncontrol /opt/jdk/lib/visualvm /opt/jdk/lib/*javafx* /opt/jdk/jre/lib/plugin.jar /opt/jdk/jre/lib/ext/jfxrt.jar /opt/jdk/jre/bin/javaws /opt/jdk/jre/lib/javaws.jar /opt/jdk/jre/lib/desktop /opt/jdk/jre/plugin /opt/jdk/jre/lib/deploy* /opt/jdk/jre/lib/*javafx* /opt/jdk/jre/lib/*jfx* /opt/jdk/jre/lib/amd64/libdecora_sse.so /opt/jdk/jre/lib/amd64/libprism_*.so /opt/jdk/jre/lib/amd64/libfxplugins.so /opt/jdk/jre/lib/amd64/libglass.so /opt/jdk/jre/lib/amd64/libgstreamer-lite.so /opt/jdk/jre/lib/amd64/libjavafx*.so /opt/jdk/jre/lib/amd64/libjfx*.so # Set environment ENV JAVA_HOME /opt/jdk ENV PATH ${PATH}:${JAVA_HOME}/bin

The result of building this image or pulling from anapsix/alpine-java is a fully functional Oracle Java 8 image weighing only 173Mb . Impressive!

Running Atlassian Stash on it

The whole point of the exercise above was for me to run a leaner container with Stash – our enterprise Git server – trying to shave space off from our official image. The task was a success – if not a smashing one. The final Stash image I produced weighs 368MB which adds up to a ~30% reduction over the official image. Here how I had to tweak the Dockerfile :

FROM durdn/minimal-java8:stripped MAINTAINER Atlassian Stash Team ENV DOWNLOAD_URL https://downloads.atlassian.com/software/stash/downloads/atlassian-stash- ENV STASH_HOME /var/atlassian/application-data/stash RUN apk --update add git tar bash # Install Atlassian Stash to the following location ENV STASH_INST_DIR /opt/atlassian/stash ENV STASH_VERSION 3.11.1 RUN mkdir -p ${STASH_INST_DIR} && curl -LO --silent ${DOWNLOAD_URL}${STASH_VERSION}.tar.gz && tar -xf atlassian-stash-${STASH_VERSION}.tar.gz -C ${STASH_INST_DIR} --strip-components 1 && rm atlassian-stash-${STASH_VERSION}.tar.gz && mkdir -p ${STASH_INST_DIR}/conf/Catalina && chmod -R 700 ${STASH_INST_DIR}/conf/Catalina && chmod -R 700 ${STASH_INST_DIR}/logs && chmod -R 700 ${STASH_INST_DIR}/temp && chmod -R 700 ${STASH_INST_DIR}/work VOLUME ["${STASH_INST_DIR}"] # HTTP Port EXPOSE 7990 # SSH Port EXPOSE 7999 WORKDIR $STASH_INST_DIR # Run in foreground CMD ["./bin/start-stash.sh", "-fg"]

Bonus trick: How to strip an image

I love the layering ability of Docker images but for base images upon which I’ll build my stacks often I’d like them to consist of a single layer. It’s a mental thing more than anything so excuse my weirdness if you can.

Many times the extra layers in your base images will not be re-used. For those situations it can be helpful to strip an image of all its layers and flatten it. The technique to accomplish that is the following:

First run it so that you have a container to refer to:

docker run -t durdn/minimal-java /bin/true

Then export it and re-import it:

docker export `docker ps -q -n=1` | docker import - durdn/minimal-java:stripped

Verify that the new image only has one layer with:

docker history durdn/minimal-java:stripped IMAGE CREATED CREATED BY SIZE COMMENT 8eb82b59dee6 31 seconds ago 172.9 MB Imported from - docker run -ti durdn/minimal-java8:stripped /opt/jdk/bin/java -version java version "1.8.0_45" Java(TM) SE Runtime Environment (build 1.8.0_45-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

Conclusions

That’s it for my discoveries today. Pings, likes, comments, love or hate gladly received here in the comments, at @durdn or at my awesome team @atlassiandev.

(Credit for the epic alot picture goes to Hyperbole and a half).

You might also enjoy our ebook, “Hello World! A new grad’s guide to coding as a team” – a collection of essays designed to help new programmers succeed in a team setting. Grab it for yourself, your team, or the new computer science graduate in your life. Even seasoned coders might learn a thing or two.

Read it online now

Click here to download for your Kindle