Migrating from Oracle JDK to OpenJDK on Red Hat Enterprise Linux: What you need to know

Migrating from Oracle JDK to OpenJDK on Red Hat Enterprise Linux: What you need to know

Oracle has announced that the Oracle JDK 8 builds released after Jan 2019 cease to be free for commercial use. GPL + Classpath Exception licensed (free for any use, subject to that license) are current made available by Oracle through http://jdk.java.net/11/. (See also Oracle’s blog entry & licensing).
An alternative is to use OpenJDK and effort is underway to make them fully interchangeable. A number of companies who are currently using Oracle JDK in production are making the decision to switch to OpenJDK or have already done so.

Andrew Haley (Red Hat’s Java Platform Lead Engineer) recently wrote a great article on the direction of OpenJDK.

In this article, I’ll discuss: the technical and support implications of the migration, what developers and operations teams need to know, and solutions to potential challenges.

I’ll go over the Red Hat support model and technical details of how to install, update, and run different OpenJDK versions on Red Hat Enterprise Linux (RHEL) 6 and 7 systems. I’ll also discuss the operations of Java applications (such as Red Hat JBoss Enterprise Application Platform (JBoss EAP) and other servers) on top of OpenJDK.

While this article is about OpenJDK on RHEL, I should also point out that OpenJDK for Windows can also be downloaded from developers.redhat.com. This lets you use the same JDK for Linux and Windows.

Architectural overview

When it comes to running Oracle JDK on RHEL, a configuration that I’ve seen a number of times is to download Oracle JDK zip file, extract it to a particular folder and point the application to that JDK. Sometimes the application development team will ship their application together with the JDK to the deployment teams. Another approach is to download the rpm and install it.
(As a note, zip-file download method is harder to keep up to date and is thus generally not recommended. But I’ve seen this method used in production systems where the concern is OS changes breaking the application).

OpenJDK, on the other hand, is not available as zip file (at time of writing). Instead, it is installed via yum, dnf, or rpm, with yum being the recommended method. Multiple concurrent major versions on the same server are fully supported (see below).

For businesses, this generally means that maintenance and updates to OpenJDK are handled by the infrastructure team (or someone with root access) instead of by the development team.

You should also be mindful about OpenJDK updates. While multiple major versions are supported (1.7, 1.8), yum will generally update the system to the latest minor build of each major version. (1.8 b60 -> 1.8 b191) and, by default, only the latest minor build is left installed. If you need multiple minor (build) versions installed concurrently, see the section for minor versions below.

Migrating Oracle JDK to OpenJDK

Some customers currently have access to Oracle JDK SE via a content repository from Red Hat. This will no longer be the case after 30th of November, 2018. For OpenJDK installation instructions, see the instructions below

Develop using Red Hat's most valuable products

Your membership unlocks Red Hat products and technical training on enterprise cloud application development.

JOIN RED HAT DEVELOPER

Support options

Major LTS OpenJDK versions (7, 8,  and 11) on RHEL are fully supported by Red Hat and Red Hat is committed to providing code-level patches for bug fixes. Major versions are supported for at least 6 years. For instance, OpenJDK 1.8 is supported until June 2023. Red Hat OpenJDK builds have passed the relevant Java SE TCK version made available by Oracle and Red Hat tests and supports these with Java EE implementations (see OCTLA). For example Red Hat tests and supports Java EE implementations such as the JBoss Enterprise Application Platform running on OpenJDK.

For full details, see the OpenJDK Life Cycle and Support Policy.

How to install OpenJDK and which packages are relevant

OpenJDK comes with a number of rpm packages. Only the first three are relevant for RHEL production servers.

On RHEL7, they can be found in the rhel-7-server-rpms repo.

java-1.8.0-openjdk.x86_64          # To execute java applications.
java-1.8.0-openjdk-devel.x86_64    # For compilation of Java. javac etc.. 
java-1.8.0-openjdk-headless.x86_64 # no audio/video. Just SE. E.g for embedded systems

For developers running RHEL/Fedora, you may also want to install the following packages:

java-1.8.0-openjdk-javadoc.noarch  # Javadoc that can be included in your IDE.
java-1.8.0-openjdk-src.x86_64      # Java sources, to review api implementation.

The installation is business as usual. I generally install the development package (to be able to compile applications) and it’ll pull in the required dependencies. (See this article if you need to enable sudo.)

$ sudo yum install java-1.8.0-openjdk-devel.x86_64

Sometimes I use ssh to access a server and I want to know which JDK is installed and is in the PATH. To tell Oracle JDK and OpenJDK apart, OpenJDK has “openjdk” in the version output:

$ java -version
openjdk version "1.8.0_171 # OpenJDK

$ java -version
java version "1.8.0_171 # OracleJDK

How to install and use multiple “major” versions of OpenJDK

Major versions are 7, 8, and 11   (aka 1.7, 1.8…). Multiple major versions on the same system are fully supported (in the context that each major version is updated to the latest minor version).

Installation is business as usual:

# List installed and available packages:
$ sudo yum list *openjdk* 

# Install desired version(s):
$ sudo yum install java-1.7.0-openjdk-devel.x86_64
$ sudo yum install java-1.8.0-openjdk-devel.x86_64

Now, for selecting which one to use, you have the choice to

  1. Use alternatives to select the default Java version on your system.
    This is a good option if you want to be able to select the default Java version for your entire system.
  2. Hard-code the JAVA_HOME path manually to a symlink that points to the latest minor version.
    This is useful if you want to ensure an application always starts with a particular version of Java, independent of the default Java version on the system.

Option 1: Setting the default Java via alternatives

alternatives instructs the system which Java to use for the whole system.
You shouldn’t change this during the execution of Java to start another application with a different Java version. To do that, use option 2 below instead.

A common pitfall for developers is to set the default version of Java, but not to set the Java compiler (javac). If you’re compiling Java applications on the server, make sure to set both.

$ sudo alternatives --config java  # for running java applications.
$ sudo alternatives --config javac # for compiling java applications.
$ sudo alternatives --list # show available alternatives.

As a sanity check, I like to test with a mini “hello world” Java application that outputs the Java version.

 
$ cat jdkVersions.java 
   public class jdkVersions { 
      public static void main(String[] args) { 
        System.out.println("This app runs on: " + System.getProperty("java.version")); 
      } 
   } 
$ javac jdkVersions.java # this creates a jdkVersions.class 
$ java jdkVersions 
This app runs on: 1.8.0_191

For full details of alternatives and the support of major versions, see Can I install multiple versions of java on a Red Hat Enterprise Linux system?

Option 2:  Hard-coding the JAVA_HOME path

You can set the JAVA_HOME path as follows.

# Under '/usr/lib/jvm/' you can find symlinks that point to the latest java versions.
# You will find jre-1.8.0-openjdk and java-1.8.0-openjdk. The 'java' one is the one you need if you compile things. E.g:

$ export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk   # or 1.7 etc.. 
$ export PATH=$JAVA_HOME/bin:$PATH

# Validate via:
$ java -version
openjdk version "1.8.0_191"
$ javac -version
javac 1.8.0_191

How to install and use a particular or multiple “minor” versions of OpenJDK

In an ideal world, you would generally always update RHEL and you’d update OpenJDK to the latest minor version (for example, update 1.8 build 60 to 1.8 build 191).

But sometimes in your production environment, you run multiple Java applications and you’re unable to migrate them all to the latest version of OpenJDK at the same time or a build update breaks something. In such a case, you need to run your Java application on a particular build or you need to have multiple builds on the system.

As a warning, while this is technically possible, from a support point of view, generally Red Hat will support multiple LTS major versions, but only the latest minor version will be supported with patches if there are JVM crashes or other JVM issues. That is, Red Hat support will generally ask you if the issue can be reproduced with the latest minor build.

Another point to consider is that Java uses some underlying system libraries. When you update RHEL, the underlying libraries get updated, which may impact older minor builds. You should avoid the situation where you never update your JDK and the JDK becomes (for example) over a year behind the OS. That is, using an older minor build should only be a short-term situation while Dev or QA is validating the app against the newest build.

In other words, you should always aim to keep your applications on the newest minor build, similar to always waking up on time in the morning. If that’s simply not possible, run a particular build or run multiple minor builds, as described below.

Running a particular build and preventing updates

# List all versions:
$ sudo yum list available --showduplicates java-1.8.0-openjdk-devel.x86_64

Package name                    Versions
java-1.8.0-openjdk-devel.x86_64 1:1.8.0.31-2.b13.el7
java-1.8.0-openjdk-devel.x86_64 1:1.8.0.151-1.b12.el7_4
...

# Install the version you want by specifying (package name)-(version) where 'version' doesn't contain the '1:' prefix. E.g
$ sudo yum install java-1.8.0-openjdk-devel-1.8.0.191.b12-0.el7_5

# You can then exclude OpenJDK from yum updates either manually or by configuring /etc/yum.conf (see link below).
$ sudo yum update --exclude=java-1.8.0-openjdk*

See also exclude kernel or other packages from getting updated in RHEL.

Running multiple minor builds and preventing automatic removal of older packages

Typically when updating a package, the latest matching version is installed and any previous versions are removed. It is recommended to always run just the latest minor version that has the most up-to-date security and bug fixes.  However, there are times when you’d like to have multiple versions installed concurrently.  With RHEL 7, you can prevent yum from automatically removing the older versions.  (Note: In RHEL 6, this is not possible. I’ve tried; you get rpm version conflicts and the Red Hat development team confirmed that this is expected behavior.)

OpenJDK 1.7 and 1.8 are considered separate packages, because they are different major versions.

Finally, while running multiple minor versions is technically possible, only the latest minor version will be supported if there are JVM crashes or issues.

 

To get around this, you can instruct yum to keep old versions of particular packages, in our case, OpenJDK:

# edit /etc/yum.conf and append the following:
installonlypkgs=java-1.8.0-openjdk,java-1.8.0-openjdk-headless,java-1.8.0-openjdk-devel

# Now you can install Java packages per the instructions above and list installed versions via:
# rpm -qa | grep java-1.8.0-openjdk

# you should see multiple OpenJDK versions if you've installed multiple ones.

# Now you may wish to hard-code JAVA_HOME to a particular Java minor version. E.g:
$ export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.151-5.b12.el7_4.x86_64
$ export PATH=$JAVA_HOME/bin:$PATH

# Validate via:
$ java -version
openjdk version "1.8.0_151"
$ javac -version
javac 1.8.0_151

For details, please see How to install multiple minor versions of OpenJDK on a Red Hat Enterprise Linux system?

Are there known issues or incompatibilities, or does OpenJDK lack something that Oracle JDK has?

Oracle JDK 11 and OpenJDK 11 will be interchangeable.

There are some differences between Oracle JDK 1.8 and OpenJDK 1.8, although the gap is shrinking.

For example, Mission Control has been open sourced recently. I know a software engineer in our Toronto, Canada, office who recently started working on it. Java Flight Recorder was also open sourced and will be available in JDK 11. VisualVM has been open source for a while and as of JDK 9 it is no longer shipped with the JDK but is available as a separate open source project.

I’ve heard there are plans to make them available via rpm in the future as part of OpenJDK 11.

While Red Hat’s OpenJDK builds have passed the corresponding Java SE TCK as provided by Oracle, Oracle JDK has some additional features, which should be taken into account.

For example, JavaFX code may require some work. There is OpenFX, though.

I’ve been asked whether Java’s Cryptography/Security extension (JCE) is supported in OpenJDK. The answer is yes it is. As a note, in OpenJDK as of 8b161, unlimited cryptography policy is enabled by default (previously you had to download the unlimited strength files manually from Oracle).

Sometimes I get asked if monitoring agents are compatible with OpenJDK (for example, AppDynamics). In general, most tools are compatible, although you need to check if all features are compatible.

The general approach is to try to switch your application to OpenJDK (via JAVA_HOME), re-compile and see if there are any compile / test issues and go from there.

What about OpenShift?

Red Hat provides container images with OpenJDK as base images. See the article Getting Started with OpenShift Java S2I to learn more about source-to-image container builds.

 

I hope this article helps. If you have some other questions, please post a comment and I’ll try my best to answer.

Take advantage of your Red Hat Developers membership and download RHEL today at no cost.

Share