Introduction
The Jenkins project is committed to delivering a world-class platform experience for end users and developers alike. At the core of this experience is Java, an object-oriented programming language with a cross-platform runtime in the form of the Java virtual machine (JVM). Since its inception, the Jenkins project has been a major consumer of Java, distributing over 1,800 plugins to an installed base of over 300,000 controllers, and Jenkins regularly appears on lists of the top Java applications of all time.
Beginning with Jenkins 2.357 (released on June 28, 2022) and the forthcoming September LTS release, Jenkins requires Java 11. Additionally, beginning with Jenkins 2.355 (released on June 14, 2022) and Jenkins 2.346.1 LTS (released on June 22, 2022), Jenkins supports Java 17. Plugins have already been prepared in JENKINS-68446. Use the Plugin Manager to upgrade all plugins before and after upgrading to Jenkins 2.357.
Long-time Jenkins users and Java developers may recall previous migrations to Java 7 and Java 8. While these migrations were not trivial, they pale in comparison to the magnitude of the migration to Java 9 and beyond. Java 9 represents a sea change in the Java ecosystem across many dimensions. Not only are there changes to licensing policies, versioning schemes, release cadences, and long-term support (LTS) cycles, but also there are a number of significant technical changes to the language and runtime (e.g., Project Jigsaw), not all of them retaining the high levels of compatibility that characterized previous releases. Although these evolutionary changes are likely to be in the best interests of the Java community in the long term, it is nevertheless incumbent on the community to be aware of the impact and to plan accordingly.
In this blog post, we will discuss the Jenkins project’s migration to Java 11 and Java 17, reflecting on it in the context of previous Java migrations within the Jenkins project and the Java community more broadly. We will summarize the benefits and risks and describe the upgrade process. Finally, we will share a glimpse at what is coming in future releases.
History
Since its inception in 2005, the Jenkins (then Hudson) project has gone through a number of Java migrations. To a large degree, the present migration is consistent with historical precedent within the Jenkins project. For years the Jenkins project has published anonymous usage statistics, as described in a piece by R. Tyler Croy and recently revised by Andrew Bayer, which enable us to quantify past and present trends.
Analysis
The above data reveals that the lifecycle of each major Java version is clearly a Gaussian function. Each major version of Java is released by the vendor, begins a phase of rapidly growing adoption, reaches a usage peak, loses support from the Jenkins project, begins a decline in usage, declines in usage to a terminal state, and finally reaches vendor end-of-life (EOL), in roughly that order.
Java 6 | Java 7 | Java 8 | Java 11 | |
---|---|---|---|---|
Vendor release date |
December 11, 2006 |
July 7, 2011 |
March 18, 2014 |
September 25, 2018 |
Rapid adoption |
October 2009 |
February 2013 |
February 2015 |
November 2019 |
Peak usage |
March 2013 |
June 2015 |
February 2021 |
N/A |
Jenkins weeklies require next major version |
May 2015 |
April 2017 |
June 2022 |
N/A |
Terminal decline in usage |
May 2016 |
March 2019 |
N/A |
N/A |
Vendor End of Life (EOL) |
December 31, 2015 |
July 31, 2019 |
Extrapolating further, one can observe the following trends:
-
It takes at least a year for Jenkins users to begin to adopt a new release of Java.
-
Once Jenkins users begin to adopt a new version of Java, usage of the preceding Java version eventually reaches a peak and begins to decline.
-
The Jenkins project has historically started requiring a new Java version roughly halfway through the period of decline of the preceding Java version.
-
Once Jenkins requires a given Java version, usage of the preceding Java version continues to decline until it reaches a terminal stage of decline.
-
The abovementioned terminal stage of decline typically correlates with the end of active support from the Java vendor.
Conclusion
Critically, the Jenkins project has never required a given version of Java until the preceding version is clearly declining in usage. This reduces risk by ensuring that the majority of users are successfully running the new version in production. Conversely, the requirement of a new Java version for Jenkins users incentivizes the remaining users to upgrade and prevents users who are reluctant to upgrade from putting the project at risk by continuing to rely on a version that is reaching vendor end-of-life (EOL).
The requirement for Java 11 is consistent with historical precedent. Usage of Java 8 peaked in February 2021 and has been declining since then. Meanwhile, adoption of Java 11 has been increasing rapidly since November 2019 but has not yet reached a peak. The time is right to require Java 11.
A new era for Java
The release of Java 9 heralded a new era in the evolution of the Java Platform. In addition to new features (e.g., Project Jigsaw), it introduced a new versioning scheme and release cadence. Originally, there was a new major version released every few years. After Java 9, the release schedule changed to a new major version every six (6) months, with a Long Term Support (LTS) release of Java selected every few major versions.
Java 8, Forever & Always?
Members of the Jenkins community, spearheaded by Oleg Nenashev, began working on Java 11 support in 2018. At the time, Java 9, 10, and 11 had not yet achieved significant levels of adoption. In a piece on LinkedIn’s journey to Java 11, Jesse Jie provides the following anecdote:
As an anecdote, some sessions at the Oracle Code One conference in late 2019 asked attendees if their products were using Java 9 or higher to which only about 20% of the room said that they were; few major companies had adopted Java 11 either.
These observations match our own experience in the Jenkins project. Many users are choosing to stay on Java 8, and Java vendors are responding in turn by extending support for Java 8: to May 2026 (in the case of Adoptium, Amazon Corretto, and IBM Semeru) and to December 2030 (in the case of Azul and Oracle). This is an unprecedented level of support for a version of Java originally released in 2014.
While the Jenkins project could remain on Java 8 for the foreseeable future, this would be imprudent for several reasons. First, many key third-party libraries consumed by the Jenkins project (e.g., Jetty, JGit, Spring Framework, and Spring Security) are beginning to require newer versions of Java, and staying on Java 8 puts the Jenkins project at risk of eventually not being able to receive security updates from upstream projects.
Furthermore, significant runtime improvements have been made to the Java Platform in recent years. For example, LinkedIn saw drastic performance improvements when migrating to Java 11, and Adoptium saw significant memory usage improvements when migrating to Java 11 (on Jenkins, no less!). Recent Java runtimes provide a number of improvements to garbage collection, among other areas.
Finally, Jenkins takes pride in its strong development community, and staying on a current version of Java helps attract and retain developers. As one developer put it in a 2015 mailing list post:
In the context of recruiting (OSS) developers, I think Java moves slowly enough (especially cf. C#) to damage its mindshare without additionally making it all less fun by making everyone act like a corporate IT developer stuck on an obsolete platform. That just drives people to work on CI systems that don’t have that constraint.
Trouble with JAXB
Prior to Java 11, Java Architecture for XML Binding (JAXB) was part of the Java Platform, and one could use it without adding a third-party dependency. Beginning with Java 11, JAXB is no longer a part of the Java Platform and requires adding a third-party dependency. Thanks to work done several years ago by Baptiste Mathus and others, a JAXB Jenkins plugin is available, which provides the JAXB library to Jenkins plugins in the form of a plugin-to-plugin dependency.
The vast majority of plugins have already been prepared to support Java 11 via the JAXB plugin in JENKINS-68446.
Jenkins users need only upgrade plugins to compatible versions as documented in the Released As field in Jira.
It is critical to use the Plugin Manager to upgrade all plugins before and after upgrading to Jenkins 2.357.
Failure to upgrade plugins to compatible versions may result in ClassNotFoundException
, NoClassDefFoundError
, or other low-level Java errors.
Dr. OpenJDK or: How I Learned to Stop Worrying and Love Java 9 and Beyond
The world of Java development was shaken in 2019 when Oracle changed the licensing policy for Java 8. Recent years have seen the proliferation of a number of different Java vendors:
Yes, even Microsoft now has a build of OpenJDK.
The presence of so many options can be initially daunting. In recent years, the Jenkins project has been using and recommending Adoptium/Eclipse Temurin, which is the Java vendor used in the official Jenkins Docker images and the Java vendor used to power the Jenkins project’s infrastructure. Reciprocally, we are also pleased to note that Adoptium builds are done with Jenkins.
Java 11 vs. Java 17
At the center of the vast majority of the abovementioned Java distributions is the OpenJDK project, which brings us to our final point. Throughout the development of this project, we repeatedly encountered issues that were resolved in Java 17 but not yet backported to Java 11. As good citizens of the open source community, we contributed backports where applicable for the benefit of Jenkins users and the broader Java community.
Java 17 support in Jenkins is brand new, and it has not yet reached a stage of rapid adoption within the Jenkins community. Nevertheless, our experience has been that Java 17 is usually a more reliable choice than Java 11. We enthusiastically invite the Jenkins community to begin adopting Java 17, and we can say with confidence that the migration from Java 11 to Java 17 will not be nearly as painful as the migration from Java 8 to Java 11.
Upgrading to Java 11 or 17
Docker images
The official Jenkins Docker images have been based on Java 11 for many months, with Java 8 available as a fallback and Java 17 available in preview mode. Beginning with Jenkins 2.357, the Java 8 images will be retired and the Java 17 images will transition from preview to general availability (GA). Users of the official Jenkins Docker images need not install or configure Java on their own, as it comes preinstalled in the image.
OS packages
Users of the official Jenkins OS packages for Debian, Red Hat, and SUSE Linux distributions should note that these packages are agnostic to the Java vendor. In other words, you must bring your own Java package. One straightforward way to do this is to install Java 11 from your Linux distribution, as described on the package download site:
By virtue of not requiring any custom repositories, this is certainly the simplest method (and the one used by the Jenkins project’s packaging tests), but it does not give the user a high degree of control over the Java runtime environment. As mentioned previously, the official Jenkins Docker images use Adoptium/Eclipse Temurin (as does the Jenkins infrastructure project). Enthusiastic users may wish to install Java from Adoptium or another vendor. Adoptium recently began providing Linux installation packages, as described in a piece by George Adams. Ultimately, the choice of which Java vendor to use is your own, as long as that vendor provides Java 11 or Java 17. Refer to your chosen Java vendor for installation instructions.
Once you have installed a suitable version of Java, configure Jenkins to use that Java runtime. The most straightforward way is to configure that version of Java as the default version of Java at the operating system (OS) level:
Alternatively, users who do not wish to change the default version of Java can customize the JAVA_HOME
or JENKINS_JAVA_CMD
environment variable as part of the Jenkins systemd(1)
service unit.
Refer to the Managing systemd services section of the Jenkins documentation for more information.
Garbage collection options
Users who have customized Java garbage collection options should note that these options have changed in recent versions of Java. Refer to the following CloudBees Support article for the recommended garbage collection options for Java 11:
-XX:+AlwaysPreTouch
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=${PATH}
-XX:+UseG1GC
-XX:+UseStringDeduplication
-XX:+ParallelRefProcEnabled
-XX:+DisableExplicitGC
-XX:+UnlockDiagnosticVMOptions
-XX:+UnlockExperimentalVMOptions
-Xlog:gc*=info,gc+heap=debug,gc+ref*=debug,gc+ergo*=trace,gc+age*=trace:file=${PATH}/gc.log:utctime,pid,level,tags:filecount=2,filesize=100M
-XX:ErrorFile=${PATH}/hs_err_%p.log
-XX:+LogVMOutput
-XX:LogFile=${PATH}/jvm.log
These options are explained in-depth in the Oracle Java documentation as well as the CloudBees Jenkins JVM guide. |
Agents
For best results, it is recommended to run agents with the same version of Java as the version used on the controller. Use the Versions Node Monitors plugin to verify that agents are running a compatible version of Java.
Running the Jenkins remoting process on an agent with Java 11 or 17 does not imply that you need to run your builds with the same version of Java. You can continue to use any desired version of Java for individual builds. |
Reporting issues
If you find a regression in a plugin, please file a bug report in Jira:
When reporting an issue, include the following information:
-
Use the JENKINS-67688 epic.
-
Provide the output of
java -version
(e.g., OpenJDK 64-Bit Server VM build 11.0.15+10-Ubuntu-0ubuntu0.22.04.1) -
Provide the name, version, and architecture of the operating system you are using (e.g., Ubuntu 20.04.4 LTS x86_64).
-
Provide the complete list of installed plugins as suggested in the bug reporting guidelines.
-
Provide the complete stack trace, if relevant.
-
Provide steps to reproduce the issue from scratch on a minimal Jenkins installation; the scenario should fail on Jenkins 2.356 or earlier when the steps are followed on Java 11 or Java 17 and pass when the steps are followed on Java 8.
Future work
We expect to see usage of Java 11 continue to grow until it reaches a peak. We expect to see usage of Java 8 continue to decline until it reaches a terminal state, as was the case for Java 7 and Java 6. We expect to see usage of Java 17 transition from minimal levels to significant levels. To reach our goal of Java 17 as the recommended Java version, we need cooperation from both Jenkins users and contributors alike. The development work for Java 17 support is tracked in the following Jira epics:
If you have made it this far through this post, you are clearly enthusiastic about the Jenkins platform experience. If you have never contributed, why not? We would love to work with you. Join one of our Platform Special Interest Group (SIG) meetings to learn more.
Conclusion
We expect to see a bit of disruption from these changes but hope that in the long term they will be in the best interests of the Jenkins community. Please reach out on the developers' list with any questions or suggestions.
Acknowledgments
As noted above, members of the Jenkins community began working on Java 11 support in 2018, well before the present author’s involvement in the project and well beyond the present author’s ability to identify and name everyone who was involved in the effort. In addition to the many plugin maintainers who merged and released JAXB fixes in a timely fashion, we would like to thank the following regular contributors for their recent efforts:
-
Adrien Lecharpentier
-
Alexander Brandes
-
Alex Earl
-
Andrew Bayer
-
Baptiste Mathus
-
Carroll Chiou
-
Damien Duportal
-
Daniel Beck
-
Devin Nusbaum
-
Dr. Ullrich Hafner
-
Jesse Glick
-
Kevin Martens
-
Mark Waite
-
Oleg Nenashev
-
Olivier Lamy
-
Tim Jacomb
-
Vincent Latombe
Thank you! It would not have been possible without you.