Community Features IntelliJ IDEA Java Livestreams Videos

Webinar Summary: Java, Containers and IntelliJ IDEA

On December 17, 2020, we hosted the live stream ‘Java, Containers and IntelliJ IDEA’ by the amazing Elder Moraes, RedHat Developer Advocate, Java Champion, Board member at Sou Java, and author of multiple books on Enterprise Java.

The code and presentation used in this live stream by the speaker can be accessed using this link. Elder’s presentation also includes a great comparison and summary of the tips that he demonstrated in his live demonstration.

Session details

In this live stream, Elder addressed four main issues – long build times for Docker images, large image sizes, maintainability issues, and resource allocation. To demonstrate this, he started by building a >660 MB Docker image and that he had reduced to ~95 MB by the end of the session.

How to lower build times for Docker images

Elder started his demonstration by addressing the concern of long build times. He mentioned that it is usual for developers to build hundreds or even thousands of Docker images. Often these images would be built on the CI/CD pipeline. So, any time saved on the build time of an image would make the overall process faster.

He used IntelliJ IDEA to show a Docker file and a Terminal Window to execute commands.

The Docker images included in Elder’s sample code (https://github.com/eldermoraes/java_and_containers) have Docker files with the prefix ‘DO’ or ‘DONT’. For each of these combinations, Elder demonstrated why you should choose one over the other.

By using two docker files with different sequences of commands, Elder demonstrated that commands that correspond to binaries that might change should be placed as late as possible in a Dockerfile. A Docker image is built in layers. When you rebuild an image, it tries to use the cache. However, if any command results in a changed binary, the command that follows it won’t be able to use the cache, resulting in longer build durations. For the following Docker file:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
FROM debian:stretch
COPY lib/* /deployment/lib/
COPY *-runner.jar /deployment/app.jar
RUN apt-get update
RUN apt-get -y install openjdk-8-jdk ssh vim
CMD ["java", "-jar", "/deployment/app.jar"]`
FROM debian:stretch COPY lib/* /deployment/lib/ COPY *-runner.jar /deployment/app.jar RUN apt-get update RUN apt-get -y install openjdk-8-jdk ssh vim CMD ["java", "-jar", "/deployment/app.jar"]`
FROM debian:stretch

COPY lib/* /deployment/lib/
COPY *-runner.jar /deployment/app.jar

RUN apt-get update
RUN apt-get -y install openjdk-8-jdk ssh vim

CMD ["java", "-jar", "/deployment/app.jar"]`

Elder modified the sequence of commands as follows (adding application libraries after JDK since the latter might change more frequently):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
FROM debian:stretch
RUN apt-get update
RUN apt-get -y install openjdk-8-jdk ssh vim
COPY lib/* /deployment/lib/
COPY *-runner.jar /deployment/app.jar
CMD ["java", "-jar", "/deployment/app.jar"]
FROM debian:stretch RUN apt-get update RUN apt-get -y install openjdk-8-jdk ssh vim COPY lib/* /deployment/lib/ COPY *-runner.jar /deployment/app.jar CMD ["java", "-jar", "/deployment/app.jar"]
FROM debian:stretch

RUN apt-get update
RUN apt-get -y install openjdk-8-jdk ssh vim

COPY lib/* /deployment/lib/
COPY *-runner.jar /deployment/app.jar

CMD ["java", "-jar", "/deployment/app.jar"]

Elder said that developers would do well to use specific file names instead of using . When use use , any changes in the folder can lead to cache invalidations. The following line in the preceding dockerfile:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
COPY *-runner.jar /deployment/app.jar
COPY *-runner.jar /deployment/app.jar
COPY *-runner.jar /deployment/app.jar

…was replaced with the following (so that any changes due to * in the path do not invalidate the cache):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
COPY quarkus-1.0.0-SNAPSHOT-runner.jar /deployment/app.jar
COPY quarkus-1.0.0-SNAPSHOT-runner.jar /deployment/app.jar
COPY quarkus-1.0.0-SNAPSHOT-runner.jar /deployment/app.jar

Another tip to decrease the build time for Docker images Elder demonstrated was how to create a group unit. He replaced the following commands:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
RUN apt-get update
RUN apt-get -y install openjdk-8-jdk ssh vim
RUN apt-get update RUN apt-get -y install openjdk-8-jdk ssh vim
RUN apt-get update
RUN apt-get -y install openjdk-8-jdk ssh vim

… with these:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
RUN apt-get update \
&& apt-get -y install \
openjdk-8-jdk ssh vim
RUN apt-get update \ && apt-get -y install \ openjdk-8-jdk ssh vim
RUN apt-get update \
&& apt-get -y install \
   openjdk-8-jdk ssh vim

In response to one of the follow-up questions by Jeff Duska, "Isn’t multistage builds better than grouping commands?", Elder accepted they are. He couldn’t show that in this stream because he could only cover the section on Docker in this session.

How to avoid large image sizes

Elder mentioned that one of the ways to reduce Docker images is to deny installation of any automatic recommendations. He suggested that developers shouldn’t include the features they don’t need and are not sure they will need in the future, such as ssh vim, for example. So instead of the following command in their Docker file:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
RUN apt-get update \
&& apt-get -y install \
openjdk-8-jdk ssh vim
RUN apt-get update \ && apt-get -y install \ openjdk-8-jdk ssh vim
RUN apt-get update \
&& apt-get -y install \
   openjdk-8-jdk ssh vim

…they should prefer the following:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
RUN apt-get update \
&& apt-get -y install --no-install-recommends\
openjdk-8-jdk
RUN apt-get update \ && apt-get -y install --no-install-recommends\ openjdk-8-jdk
RUN apt-get update \
&& apt-get -y install --no-install-recommends\
   openjdk-8-jdk

Elder showed how this step could result in reducing a Docker image by over 150 MB.

To reduce the size of the Docker image further, Elder suggested that developers should also consider removing the cache of their package manager, by modifying the group unit as follows:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
RUN apt-get update \
&& apt-get -y install --no-install-recommends\
openjdk-8-jdk \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update \ && apt-get -y install --no-install-recommends\ openjdk-8-jdk \ && rm -rf /var/lib/apt/lists/*
RUN apt-get update \
&& apt-get -y install --no-install-recommends\
   openjdk-8-jdk \
&& rm -rf /var/lib/apt/lists/*

Even though this step managed to reduce only 15 MB from the Docker image, this difference could mean a lot when developers are looking at not just one image or container, but hundreds or even thousands of them.

Elder also suggested using tools and frameworks like Quarkus and GraalVM.

Maintainability

Elder encouraged developers to think of their Docker files as entities that would need to be maintained as code. One of the ways to write maintainable Docker files is to use official images, rather than creating their own (which usually work in most cases, if not all). For example, the following snippet from the preceding Dockerfile:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
FROM debian:stretch
RUN apt-get update \
&& apt-get -y install --no-install-recommends\
openjdk-8-jdk \
&& rm -rf /var/lib/apt/lists/*
FROM debian:stretch RUN apt-get update \ && apt-get -y install --no-install-recommends\ openjdk-8-jdk \ && rm -rf /var/lib/apt/lists/*
FROM debian:stretch

RUN apt-get update \
&& apt-get -y install --no-install-recommends\
   openjdk-8-jdk \
&& rm -rf /var/lib/apt/lists/*

…сan be replaced with:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
FROM openjdk
FROM openjdk
FROM openjdk

Using tags to specify the OpenJDK version can go a long way for developers and even help prevent their applications from breaking. What if you didn’t specify a Java version and in absence of the version number, the Dockerfile pulled the latest Java version, with which your application might not be compatible? Elder replaced the following command:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
FROM openjdk
FROM openjdk
FROM openjdk

…with the following, using a tag to specify the Java version:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
FROM openjdk:8
FROM openjdk:8
FROM openjdk:8

In the next step, Elder replaced the preceding command with the following to be more specific than just specifying the Java version:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
FROM openjdk:8-jre-alpine
FROM openjdk:8-jre-alpine
FROM openjdk:8-jre-alpine

Managing Resource Allocation

Elder shared that Java 8u121 and its previous versions were neither aware of containers or cgroups. Elder shared a hack (a script) developed by fabric8 for developers who want to run Java 8u121 or its previous versions in a container (please refer to the speaker’s presentation for details). This script will sit inside a container and set limits for the JVM on the CPU, memory, disk space, and network it can use.

The later Java versions Java 8u131, Java 9, and beyond have improved their support for containers.

Webinar Summary

Elder summarized his live demonstration by stating that Java and containers get along. He also encouraged developers to be intentional when they are building their Dockerfiles, and recommended using Java 11 instead of Java 8.

Docker Support in IntelliJ IDEA

Please refer to IntelliJ IDEA’s Documentation to check out how IntelliJ IDEA can help you get started with Docker, manage images, run and interact with containers, and let you deploy your applications inside containers for testing code in an environment that is identical to production.

You can use this link to download IntelliJ IDEA today.

Our next live stream

We are in the process of planning our next set of webinars and live streams for 2021. Follow us on Twitter so you don’t miss the updates.

Happy developing!

image description