diff --git a/modules/jlink/artifacts/opt/jboss/container/java/jlink/generatejdkdeps.sh b/modules/jlink/artifacts/opt/jboss/container/java/jlink/generatejdkdeps.sh
new file mode 100755
index 00000000..c7a1fe40
--- /dev/null
+++ b/modules/jlink/artifacts/opt/jboss/container/java/jlink/generatejdkdeps.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+function generatejdkdeps() {
+ echo "Generating JDK deps"
+ $JAVA_HOME/bin/java --list-modules > $S2I_JLINK_TEMP_PATH/java-modules.txt
+ < $S2I_JLINK_TEMP_PATH/java-modules.txt sed "s/\\@.*//" > $S2I_JLINK_TEMP_PATH/modules.txt
+ grep -Fx -f $S2I_JLINK_TEMP_PATH/stripped-deps.txt $S2I_JLINK_TEMP_PATH/modules.txt | tr '\n' ',' | tr -d "[:space:]" > $S2I_JLINK_TEMP_PATH/module-deps.txt
+ echo "jdk.zipfs" >> $S2I_JLINK_TEMP_PATH/module-deps.txt
+}
\ No newline at end of file
diff --git a/modules/jlink/artifacts/opt/jboss/container/java/jlink/mkdeps.sh b/modules/jlink/artifacts/opt/jboss/container/java/jlink/mkdeps.sh
new file mode 100755
index 00000000..938e3db0
--- /dev/null
+++ b/modules/jlink/artifacts/opt/jboss/container/java/jlink/mkdeps.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+set -euo pipefail
+shopt -s globstar
+
+function generate_deps() {
+ # Create a temporary directory for a module path
+ # This works around "Module java.xml.bind not found, required by java.ws.rs"
+ mkdir dependencies
+
+ if [[ -v JAVA_LIB_DIR ]]; then
+ # Serially copy all library JARsinto a flat directory. Serially as we may
+ # have multiple libs with the same name; in which case, we clobber all but
+ # one rather than fail the script
+ find $JAVA_LIB_DIR -type f -name '*.jar' -exec cp -vt dependencies {} \;
+
+ echo "Working with: "
+ echo $JAVA_APP_JAR
+ echo $JAVA_LIB_DIR
+ # generate the dependency list
+ $JAVA_HOME/bin/jdeps --multi-release $JAVA_VERSION -R -s \
+ --module-path dependencies \
+ "$JAVA_APP_JAR" \
+ "$JAVA_LIB_DIR"/**/*.jar \
+ > $S2I_JLINK_TEMP_PATH/deps.txt
+ else
+ $JAVA_HOME/bin/jdeps --multi-release $JAVA_VERSION -R -s \
+ --module-path dependencies \
+ "$JAVA_APP_JAR" \
+ > $S2I_JLINK_TEMP_PATH/deps.txt
+ cat $S2I_JLINK_TEMP_PATH/deps.txt
+ fi
+}
diff --git a/modules/jlink/artifacts/opt/jboss/container/java/jlink/mkjreimage.sh b/modules/jlink/artifacts/opt/jboss/container/java/jlink/mkjreimage.sh
new file mode 100755
index 00000000..7063e4e8
--- /dev/null
+++ b/modules/jlink/artifacts/opt/jboss/container/java/jlink/mkjreimage.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# TODO: Still Needed?
+set -euo pipefail
+
+depsfile="$S2I_JLINK_TEMP_PATH/module-deps.txt"
+
+function generate_jre_image() {
+ test -f $depsfile
+ modules="$(cat $depsfile)"
+
+ $JAVA_HOME/bin/jlink --output "$S2I_JLINK_OUTPUT_PATH" \
+ --add-modules "$modules" \
+ --strip-debug --no-header-files --no-man-pages \
+ --compress=2
+}
diff --git a/modules/jlink/artifacts/opt/jboss/container/java/jlink/mkstrippeddeps.sh b/modules/jlink/artifacts/opt/jboss/container/java/jlink/mkstrippeddeps.sh
new file mode 100755
index 00000000..0f6c7e64
--- /dev/null
+++ b/modules/jlink/artifacts/opt/jboss/container/java/jlink/mkstrippeddeps.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+set -euo pipefail
+
+function mkstrippeddeps() {
+ if [ -f "$S2I_JLINK_TEMP_PATH/deps.txt" ]; then
+ echo "deps exists, filtering"
+ < $S2I_JLINK_TEMP_PATH/deps.txt \
+ grep 'java\|jdk\.' | # mostly removes target/, but also jdk8internals
+ sed -E "s/Warning: .*//" | #remove extraneous warnings
+ sed -E "s/.*-> //" | # remove src of src -> dep
+ sed -E "s/.*\.jar//" | # remove extraneous dependencies
+ sed "s#/.*##" | # delete anything after a slash. in practice target/..
+ sort | uniq |
+ tee $S2I_JLINK_TEMP_PATH/stripped-deps.txt
+ echo "Stripping dependencies complete"
+ else
+ echo "deps does not exist"
+ fi
+}
diff --git a/modules/jlink/artifacts/opt/jboss/container/java/jlink/preflight.sh b/modules/jlink/artifacts/opt/jboss/container/java/jlink/preflight.sh
new file mode 100644
index 00000000..67154d01
--- /dev/null
+++ b/modules/jlink/artifacts/opt/jboss/container/java/jlink/preflight.sh
@@ -0,0 +1,25 @@
+jlink_techpreview_warning()
+{
+ {
+ echo "WARNING WARNING WARNING"
+ echo " Jlink integration is a Tech Preview feature!"
+ echo " See "
+ echo " for more information."
+ echo "WARNING WARNING WARNING"
+ } >&2
+}
+
+jlink_preflight_check()
+{
+ # preflight check: do we have what we need?
+ if [ "$JAVA_VERSION" -lt 11 ]; then
+ echo "Jlink integration not available for JDK${JAVA_VERSION}!"
+ echo "Jlink integration is only supported for JDK versions 11 and newer."
+ exit 1
+ fi
+ if [ ! -d /usr/lib/jvm/java/jmods ]; then
+ echo "Jlink integration requires the jmods RPM to be installed in the builder image, e.g."
+ echo " microdnf install -y java-${JAVA_VERSION}-openjdk-jmods"
+ exit 1
+ fi
+}
diff --git a/modules/jlink/configure.sh b/modules/jlink/configure.sh
new file mode 100644
index 00000000..5b714662
--- /dev/null
+++ b/modules/jlink/configure.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Configure module
+set -e
+
+SCRIPT_DIR=$(dirname $0)
+ARTIFACTS_DIR=${SCRIPT_DIR}/artifacts
+
+chown -R default:root $SCRIPT_DIR
+chmod -R ug+rwX $SCRIPT_DIR
+chmod ug+x ${ARTIFACTS_DIR}/opt/jboss/container/java/jlink/*
+
+pushd ${ARTIFACTS_DIR}
+cp -pr * /
+popd
diff --git a/modules/jlink/module.yaml b/modules/jlink/module.yaml
new file mode 100644
index 00000000..518e0fe8
--- /dev/null
+++ b/modules/jlink/module.yaml
@@ -0,0 +1,32 @@
+schema_version: 1
+
+name: "jboss.container.java.jlink"
+version: "2.0"
+description: ^
+ "Provides support for building custom JREs with a slimmed
+ down set of modules by making use of Jdeps and Jlink"
+
+execute:
+- script: configure.sh
+
+envs:
+- name: JBOSS_CONTAINER_JAVA_JLINK_MODULE
+ value: /opt/jboss/container/java/jlink
+- name: S2I_JLINK_OUTPUT_PATH
+ value: /tmp/jre
+- name: S2I_JLINK_TEMP_PATH
+ value: /tmp/jlink
+- name: S2I_ENABLE_JLINK
+ description: ^
+ Enables the Jdeps/JLink workflow to minimize JRE size
+ example: "false"
+
+modules:
+ install:
+ - name: jboss.container.java.run
+ - name: jboss.container.util.pathfinder
+
+packages:
+ install:
+ - binutils # for objcopy
+ - java-21-openjdk-jmods
diff --git a/modules/jlink/tests/features/jlink.feature b/modules/jlink/tests/features/jlink.feature
new file mode 100644
index 00000000..1a60593e
--- /dev/null
+++ b/modules/jlink/tests/features/jlink.feature
@@ -0,0 +1,36 @@
+@openjdk-tech-preview/openjdk-21-jlink-rhel9
+Feature: Openshift OpenJDK S2I tests (jlink specific)
+
+ Scenario: tech preview warning is printed (OPENJDK-3038)
+ Given s2i build https://github.com/rh-openjdk/openjdk-container-test-applications from spring-boot-sample-simple/target using master
+ | variable | value |
+ | S2I_ENABLE_JLINK | true |
+ Then s2i build log should contain Jlink integration is a Tech Preview feature
+
+Scenario: Ensure S2I_ENABLE_JLINK is not set to true
+ Given s2i build https://github.com/rh-openjdk/openjdk-container-test-applications from spring-boot-sample-simple/target using master
+ Then s2i build log should not contain Jlink integration is a Tech Preview feature
+ And file /tmp/jre should not exist
+
+Scenario: Check that /tmp/jre/bin/java and /tmp/jre/lib/modules exist post s2i build if jlink is enabled.
+ Given s2i build https://github.com/rh-openjdk/openjdk-container-test-applications from quarkus-quickstarts/getting-started-3.9.2-uberjar
+ | variable | value |
+ | S2I_ENABLE_JLINK | true |
+ Then file /tmp/jre/bin/java should exist and be a file
+ And file /tmp/jre/lib/modules should exist and be a file
+
+Scenario: Check that /tmp/jlink is deleted when S2I_DELETE_SOURCE is set
+ Given s2i build https://github.com/rh-openjdk/openjdk-container-test-applications from quarkus-quickstarts/getting-started-3.9.2-uberjar
+ | variable | value |
+ | S2I_ENABLE_JLINK | true |
+ | S2I_DELETE_SOURCE | true |
+ Then s2i build log should contain Cleaning up temporary file directory /tmp/jlink
+ And file /tmp/jlink should not exist
+
+Scenario: Check that /tmp/jlink is not deleted when S2I_DELETE_SOURCE is set to false
+ Given s2i build https://github.com/rh-openjdk/openjdk-container-test-applications from quarkus-quickstarts/getting-started-3.9.2-uberjar
+ | variable | value |
+ | S2I_ENABLE_JLINK | true |
+ | S2I_DELETE_SOURCE | false |
+ Then s2i build log should not contain Cleaning up temporary file directory /tmp/jlink
+ And file /tmp/jlink should exist
\ No newline at end of file
diff --git a/modules/jvm/tests/features/memory.feature b/modules/jvm/tests/features/memory.feature
index 53cd373a..8b5f465d 100644
--- a/modules/jvm/tests/features/memory.feature
+++ b/modules/jvm/tests/features/memory.feature
@@ -36,6 +36,7 @@ Feature: OPENJDK-559 JVM Memory tests
@ubi9/openjdk-11
@ubi9/openjdk-17
@ubi9/openjdk-21
+ @openjdk-tech-preview/openjdk-21-jlink-rhel9
Scenario: Ensure Maven doesn't use MaxRAMPercentage=80
Given s2i build https://github.com/rh-openjdk/openjdk-container-test-applications.git from spring-boot-sample-simple
Then s2i build log should match regex INFO Using MAVEN_OPTS.*-XX:MaxRAMPercentage=25.0$
diff --git a/modules/jvm/tests/features/runtime.feature b/modules/jvm/tests/features/runtime.feature
index fcd338d3..86aabf1f 100644
--- a/modules/jvm/tests/features/runtime.feature
+++ b/modules/jvm/tests/features/runtime.feature
@@ -1,6 +1,7 @@
@ubi9/openjdk-11
@ubi9/openjdk-17
@ubi9/openjdk-21
+@openjdk-tech-preview/openjdk-21-jlink-rhel9
Feature: Openshift OpenJDK Runtime tests
@ubi9
diff --git a/modules/maven/s2i/tests/features/java_s2i.feature b/modules/maven/s2i/tests/features/java_s2i.feature
index 6e3c69c2..dc2d089f 100644
--- a/modules/maven/s2i/tests/features/java_s2i.feature
+++ b/modules/maven/s2i/tests/features/java_s2i.feature
@@ -3,6 +3,7 @@
@ubi9/openjdk-11
@ubi9/openjdk-17
@ubi9/openjdk-21
+@openjdk-tech-preview/openjdk-21-jlink-rhel9
Feature: Openshift OpenJDK S2I tests
# NOTE: these tests should be usable with the other images once we have refactored the JDK scripts.
# These builds do not actually run maven. This is important, because the proxy
diff --git a/modules/maven/s2i/tests/features/java_s2i_inc.feature b/modules/maven/s2i/tests/features/java_s2i_inc.feature
index c1415cab..baf8c342 100644
--- a/modules/maven/s2i/tests/features/java_s2i_inc.feature
+++ b/modules/maven/s2i/tests/features/java_s2i_inc.feature
@@ -1,6 +1,7 @@
@ubi9/openjdk-11
@ubi9/openjdk-17
@ubi9/openjdk-21
+@openjdk-tech-preview/openjdk-21-jlink-rhel9
Feature: Openshift OpenJDK S2I tests
# test incremental builds
diff --git a/modules/run/artifacts/opt/jboss/container/java/run/run-java.sh b/modules/run/artifacts/opt/jboss/container/java/run/run-java.sh
index 21720628..1d2d8fce 100755
--- a/modules/run/artifacts/opt/jboss/container/java/run/run-java.sh
+++ b/modules/run/artifacts/opt/jboss/container/java/run/run-java.sh
@@ -5,6 +5,7 @@ set -eo pipefail
export JBOSS_CONTAINER_UTIL_LOGGING_MODULE="${JBOSS_CONTAINER_UTIL_LOGGING_MODULE-/opt/jboss/container/util/logging}"
export JBOSS_CONTAINER_JAVA_RUN_MODULE="${JBOSS_CONTAINER_JAVA_RUN_MODULE-/opt/jboss/container/java/run}"
+export JBOSS_CONTAINER_UTIL_PATHFINDER_MODULE="${JBOSS_CONTAINER_UTIL_PATHFINDER_MODULE-/opt/jboss/container/util/pathfinder}"
# Default the application dir to the S2I deployment dir
if [ -z "$JAVA_APP_DIR" ]
@@ -12,6 +13,7 @@ if [ -z "$JAVA_APP_DIR" ]
fi
source "$JBOSS_CONTAINER_UTIL_LOGGING_MODULE/logging.sh"
+source "$JBOSS_CONTAINER_UTIL_PATHFINDER_MODULE/pathfinder.sh"
# ==========================================================
# Generic run script for running arbitrary Java applications
@@ -30,99 +32,6 @@ check_error() {
fi
}
-# detect Quarkus fast-jar package type (OPENJDK-631)
-is_quarkus_fast_jar() {
- if test -f quarkus-app/quarkus-run.jar; then
- log_info "quarkus fast-jar package type detected"
- echo quarkus-app/quarkus-run.jar
- return 0
- else
- return 1
- fi
-}
-
-# Try hard to find a sane default jar-file
-auto_detect_jar_file() {
- local dir=$1
-
- # Filter out temporary jars from the shade plugin which start with 'original-'
- local old_dir=$(pwd)
- cd ${dir}
- if [ $? = 0 ]; then
-
- if quarkus="$(is_quarkus_fast_jar)"; then
- echo "$quarkus"
- return
- fi
-
- local nr_jars=`ls *.jar 2>/dev/null | grep -v '^original-' | wc -l | tr -d '[[:space:]]'`
- if [ ${nr_jars} = 1 ]; then
- ls *.jar | grep -v '^original-'
- exit 0
- fi
-
- log_error "Neither \$JAVA_MAIN_CLASS nor \$JAVA_APP_JAR is set and ${nr_jars} JARs found in ${dir} (1 expected)"
- cd ${old_dir}
- else
- log_error "No directory ${dir} found for auto detection"
- fi
-}
-
-# Check directories (arg 2...n) for a jar file (arg 1)
-get_jar_file() {
- local jar=$1
- shift;
-
- if [ "${jar:0:1}" = "/" ]; then
- if [ -f "${jar}" ]; then
- echo "${jar}"
- else
- log_error "No such file ${jar}"
- fi
- else
- for dir in $*; do
- if [ -f "${dir}/$jar" ]; then
- echo "${dir}/$jar"
- return
- fi
- done
- log_error "No ${jar} found in $*"
- fi
-}
-
-load_env() {
- # Configuration stuff is read from this file
- local run_env_sh="run-env.sh"
-
- # Load default default config
- if [ -f "${JBOSS_CONTAINER_JAVA_RUN_MODULE}/${run_env_sh}" ]; then
- source "${JBOSS_CONTAINER_JAVA_RUN_MODULE}/${run_env_sh}"
- fi
-
- # Check also $JAVA_APP_DIR. Overrides other defaults
- # It's valid to set the app dir in the default script
- if [ -f "${JAVA_APP_DIR}/${run_env_sh}" ]; then
- source "${JAVA_APP_DIR}/${run_env_sh}"
- fi
-
- export JAVA_APP_DIR
-
- # JAVA_LIB_DIR defaults to JAVA_APP_DIR
- export JAVA_LIB_DIR="${JAVA_LIB_DIR:-${JAVA_APP_DIR}}"
- if [ -z "${JAVA_MAIN_CLASS}" ] && [ -z "${JAVA_APP_JAR}" ]; then
- JAVA_APP_JAR="$(auto_detect_jar_file ${JAVA_APP_DIR})"
- check_error "${JAVA_APP_JAR}"
- fi
-
- if [ "x${JAVA_APP_JAR}" != x ]; then
- local jar="$(get_jar_file ${JAVA_APP_JAR} ${JAVA_APP_DIR} ${JAVA_LIB_DIR})"
- check_error "${jar}"
- export JAVA_APP_JAR=${jar}
- else
- export JAVA_MAIN_CLASS
- fi
-}
-
# Combine all java options
get_java_options() {
local jvm_opts
@@ -226,7 +135,8 @@ mask_passwords() {
# Start JVM
startup() {
# Initialize environment
- load_env
+ # populates JAVA_APP_JAR and JAVA_LIB_DIR and possibly JAVA_MAIN_CLASS
+ setup_java_app_and_lib
local args
cd ${JAVA_APP_DIR}
diff --git a/modules/run/module.yaml b/modules/run/module.yaml
index 249e85eb..700dfe2f 100644
--- a/modules/run/module.yaml
+++ b/modules/run/module.yaml
@@ -59,3 +59,4 @@ modules:
- name: jboss.container.user
- name: jboss.container.java.jvm
- name: jboss.container.util.logging
+ - name: jboss.container.util.pathfinder
diff --git a/modules/run/tests/features/java.security.feature b/modules/run/tests/features/java.security.feature
index 9d48c16c..e335c516 100644
--- a/modules/run/tests/features/java.security.feature
+++ b/modules/run/tests/features/java.security.feature
@@ -1,6 +1,7 @@
@ubi9/openjdk-11
@ubi9/openjdk-17
@ubi9/openjdk-21
+@openjdk-tech-preview/openjdk-21-jlink-rhel9
Feature: Openshift S2I tests
Scenario: Check networkaddress.cache.negative.ttl has been set correctly
Given s2i build https://github.com/rh-openjdk/openjdk-container-test-applications.git from binary-cli-security-property
diff --git a/modules/s2i/bash/artifacts/usr/local/s2i/assemble b/modules/s2i/bash/artifacts/usr/local/s2i/assemble
index fa5e0f20..66190688 100644
--- a/modules/s2i/bash/artifacts/usr/local/s2i/assemble
+++ b/modules/s2i/bash/artifacts/usr/local/s2i/assemble
@@ -1,6 +1,6 @@
#!/bin/sh
-set -e
+set -eo pipefail
source "${JBOSS_CONTAINER_UTIL_LOGGING_MODULE}/logging.sh"
source "${JBOSS_CONTAINER_MAVEN_S2I_MODULE}/maven-s2i"
@@ -14,3 +14,55 @@ source "${JBOSS_CONTAINER_JAVA_S2I_MODULE}/maven-s2i-overrides"
# invoke the build
maven_s2i_build
+# run the pathfinder scripts to define JAVA_APP_JAR and JAVA_LIB_DIR
+source "${JBOSS_CONTAINER_UTIL_PATHFINDER_MODULE}/pathfinder.sh"
+setup_java_app_and_lib
+
+# include our jlink scripts
+if [ "$S2I_ENABLE_JLINK" = "true" ]; then
+
+ source "${JBOSS_CONTAINER_JAVA_JLINK_MODULE}/preflight.sh"
+ jlink_techpreview_warning
+ jlink_preflight_check
+
+ if [ ! -d "${S2I_JLINK_TEMP_PATH}" ]; then
+ log_info "S2I_JLINK_TEMP_PATH does not exist, creating ${S2I_JLINK_TEMP_PATH}"
+ mkdir -pm 775 "${S2I_JLINK_TEMP_PATH}"
+ fi
+
+ source "${JBOSS_CONTAINER_JAVA_JLINK_MODULE}/mkdeps.sh"
+ echo "Invoking mkdeps"
+ generate_deps || {
+ log_error "mkdeps failed, return code: $?"
+ exit 1
+ }
+
+ source "${JBOSS_CONTAINER_JAVA_JLINK_MODULE}/mkstrippeddeps.sh"
+ echo "Stripping dependencies"
+ mkstrippeddeps || {
+ log_error "stripping dependencies failed, return code: $?"
+ exit 1
+ }
+
+ source "${JBOSS_CONTAINER_JAVA_JLINK_MODULE}/generatejdkdeps.sh"
+ echo "Generating JDK dependencies"
+ generatejdkdeps || {
+ log_error "generating JDK dependencies failed, return code: $?"
+ exit 1
+ }
+
+ source "${JBOSS_CONTAINER_JAVA_JLINK_MODULE}/mkjreimage.sh"
+ echo "Linking jre"
+ generate_jre_image || {
+ log_error "Linking JRE failed, return code: $?"
+ exit 1
+ }
+
+ if [ "$S2I_DELETE_SOURCE" == "true" ]; then
+ if [ -n "$(find $S2I_JLINK_TEMP_PATH -maxdepth 0 -type d ! -empty 2> /dev/null)" ]; then
+ log_info "Cleaning up temporary file directory $S2I_JLINK_TEMP_PATH"
+ rm -rf $S2I_JLINK_TEMP_PATH
+ fi
+ fi
+fi
+
diff --git a/modules/s2i/bash/module.yaml b/modules/s2i/bash/module.yaml
index ffcfbc0b..fb70b2a6 100644
--- a/modules/s2i/bash/module.yaml
+++ b/modules/s2i/bash/module.yaml
@@ -16,6 +16,7 @@ modules:
- name: jboss.container.maven.s2i
- name: jboss.container.java.run
- name: jboss.container.util.logging
+ - name: jboss.container.util.pathfinder
- name: jboss.container.s2i.core
packages:
diff --git a/modules/s2i/core/artifacts/opt/jboss/container/s2i/core/s2i-core b/modules/s2i/core/artifacts/opt/jboss/container/s2i/core/s2i-core
index 47446df2..c02d7968 100644
--- a/modules/s2i/core/artifacts/opt/jboss/container/s2i/core/s2i-core
+++ b/modules/s2i/core/artifacts/opt/jboss/container/s2i/core/s2i-core
@@ -33,6 +33,7 @@ function s2i_core_env_init() {
S2I_IMAGE_SOURCE_MOUNTS="${S2I_IMAGE_SOURCE_MOUNTS:-${CUSTOM_INSTALL_DIRECTORIES}}"
S2I_ENABLE_INCREMENTAL_BUILDS="${S2I_ENABLE_INCREMENTAL_BUILDS:-true}"
S2I_DELETE_SOURCE="${S2I_DELETE_SOURCE:-true}"
+ S2I_ENABLE_JLINK="${S2I_ENABLE_JLINK:-false}"
}
# extensions may override this method to initialize environment variables
diff --git a/modules/s2i/core/tests/features/java_s2i_quarkus.feature b/modules/s2i/core/tests/features/java_s2i_quarkus.feature
index 7ab04b5e..1a14f093 100644
--- a/modules/s2i/core/tests/features/java_s2i_quarkus.feature
+++ b/modules/s2i/core/tests/features/java_s2i_quarkus.feature
@@ -2,6 +2,7 @@
@ubi9/openjdk-11
@ubi9/openjdk-17
@ubi9/openjdk-21
+@openjdk-tech-preview/openjdk-21-jlink-rhel9
Feature: Openshift OpenJDK S2I tests (Quarkus-based)
Scenario: Ensure Quarkus CDS doesn't fail due to timestamp mismatch (OPENDJK-1673)
diff --git a/modules/s2i/core/tests/features/s2i-core.feature b/modules/s2i/core/tests/features/s2i-core.feature
index b247bfe9..c2be89b1 100644
--- a/modules/s2i/core/tests/features/s2i-core.feature
+++ b/modules/s2i/core/tests/features/s2i-core.feature
@@ -1,6 +1,7 @@
@ubi9/openjdk-11
@ubi9/openjdk-17
@ubi9/openjdk-21
+@openjdk-tech-preview/openjdk-21-jlink-rhel9
Feature: Openshift S2I tests
# OPENJDK-84 - /tmp/src should not be present after build
Scenario: run an s2i build and check that /tmp/src has been removed afterwards
diff --git a/modules/util/pathfinder/artifacts/opt/jboss/container/util/pathfinder/pathfinder.sh b/modules/util/pathfinder/artifacts/opt/jboss/container/util/pathfinder/pathfinder.sh
new file mode 100644
index 00000000..3f4e0f4b
--- /dev/null
+++ b/modules/util/pathfinder/artifacts/opt/jboss/container/util/pathfinder/pathfinder.sh
@@ -0,0 +1,96 @@
+# Error is indicated with a prefix in the return value
+check_error() {
+ local msg=$1
+ if echo ${msg} | grep -q "^ERROR:"; then
+ log_error ${msg}
+ exit 1
+ fi
+}
+
+# detect Quarkus fast-jar package type (OPENJDK-631)
+is_quarkus_fast_jar() {
+ if test -f quarkus-app/quarkus-run.jar; then
+ log_info "quarkus fast-jar package type detected"
+ echo quarkus-app/quarkus-run.jar
+ return 0
+ else
+ return 1
+ fi
+}
+
+# Try hard to find a sane default jar-file
+auto_detect_jar_file() {
+ local dir=$1
+
+ # Filter out temporary jars from the shade plugin which start with 'original-'
+ local old_dir=$(pwd)
+ cd ${dir}
+ if [ $? = 0 ]; then
+ if quarkus="$(is_quarkus_fast_jar)"; then
+ echo "$quarkus"
+ return
+ fi
+ local nr_jars=`ls *.jar 2>/dev/null | grep -v '^original-' | wc -l | tr -d '[[:space:]]'`
+ if [ ${nr_jars} = 1 ]; then
+ ls *.jar | grep -v '^original-'
+ exit 0
+ fi
+
+ log_error "Neither \$JAVA_MAIN_CLASS nor \$JAVA_APP_JAR is set and ${nr_jars} JARs found in ${dir} (1 expected)"
+ cd ${old_dir}
+ else
+ log_error "No directory ${dir} found for auto detection"
+ fi
+}
+
+# Check directories (arg 2...n) for a jar file (arg 1)
+get_jar_file() {
+ local jar=$1
+ shift;
+
+ if [ "${jar:0:1}" = "/" ]; then
+ if [ -f "${jar}" ]; then
+ echo "${jar}"
+ else
+ log_error "No such file ${jar}"
+ fi
+ else
+ for dir in $*; do
+ if [ -f "${dir}/$jar" ]; then
+ echo "${dir}/$jar"
+ return
+ fi
+ done
+ log_error "No ${jar} found in $*"
+ fi
+}
+
+setup_java_app_and_lib() {
+ # Default the application dir to the S2I deployment dir
+ if [ -z "$JAVA_APP_DIR" ]
+ then JAVA_APP_DIR=/deployments
+ fi
+
+ # application-source provided shell script that may set environment
+ # variables
+ if [ -f "${JAVA_APP_DIR}/run-env.sh" ]; then
+ source "${JAVA_APP_DIR}/run-env.sh"
+ fi
+
+ export JAVA_APP_DIR
+
+ # JAVA_LIB_DIR defaults to JAVA_APP_DIR
+ export JAVA_LIB_DIR="${JAVA_LIB_DIR:-${JAVA_APP_DIR}}"
+ if [ -z "${JAVA_MAIN_CLASS}" ] && [ -z "${JAVA_APP_JAR}" ]; then
+ JAVA_APP_JAR="$(auto_detect_jar_file ${JAVA_APP_DIR})"
+ check_error "${JAVA_APP_JAR}"
+ fi
+
+ if [ "x${JAVA_APP_JAR}" != x ]; then
+ local jar="$(get_jar_file ${JAVA_APP_JAR} ${JAVA_APP_DIR} ${JAVA_LIB_DIR})"
+ check_error "${jar}"
+ export JAVA_APP_JAR=${jar}
+ else
+ export JAVA_MAIN_CLASS
+ fi
+}
diff --git a/modules/util/pathfinder/configure.sh b/modules/util/pathfinder/configure.sh
new file mode 100644
index 00000000..94810789
--- /dev/null
+++ b/modules/util/pathfinder/configure.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+set -euo pipefail
+
+SCRIPT_DIR=$(dirname $0)
+ARTIFACTS_DIR=${SCRIPT_DIR}/artifacts
+
+install -m 0644 -D {${ARTIFACTS_DIR},}/opt/jboss/container/util/pathfinder/pathfinder.sh
diff --git a/modules/util/pathfinder/module.yaml b/modules/util/pathfinder/module.yaml
new file mode 100644
index 00000000..de74802d
--- /dev/null
+++ b/modules/util/pathfinder/module.yaml
@@ -0,0 +1,34 @@
+schema_version: 1
+
+name: "jboss.container.util.pathfinder"
+version: "1.0"
+description: ^
+ "Provides support for determining Java application jar locations
+ as well as library directories"
+
+envs:
+- name: JBOSS_CONTAINER_UTIL_PATHFINDER_MODULE
+ value: /opt/jboss/container/util/pathfinder
+
+- name: JAVA_APP_DIR
+ description: ^
+ The directory where the application resides. All paths in your application
+ are relative to this directory.
+ example: "myapplication/"
+
+- name: JAVA_MAIN_CLASS
+ description: ^
+ A main class to use as argument for `java`. When this environment variable
+ is given, all jar files in **JAVA_APP_DIR** are added to the classpath as
+ well as **JAVA_LIB_DIR**.
+ example: "com.example.MainClass"
+
+- name: JAVA_LIB_DIR
+ description: ^
+ Directory holding the Java jar files as well an optional `classpath` file
+ which holds the classpath. Either as a single line classpath (colon
+ separated) or with jar files listed line-by-line. If not set
+ **JAVA_LIB_DIR** is the same as **JAVA_APP_DIR**.
+
+execute:
+- script: configure.sh
\ No newline at end of file
diff --git a/openjdk-21-jlink-rhel9.yaml b/openjdk-21-jlink-rhel9.yaml
new file mode 100644
index 00000000..e69ae665
--- /dev/null
+++ b/openjdk-21-jlink-rhel9.yaml
@@ -0,0 +1,64 @@
+# This is an Image descriptor for Cekit
+
+schema_version: 1
+
+from: "registry.access.redhat.com/ubi9/ubi-minimal"
+name: &name "openjdk-tech-preview/openjdk-21-jlink-rhel9"
+version: &version "1.23"
+description: "Source To Image (S2I) image for Red Hat OpenShift providing OpenJDK 21"
+
+labels:
+- name: "io.k8s.description"
+ value: "Platform for building and running plain Java applications (fat-jar and flat classpath)"
+- name: "io.k8s.display-name"
+ value: "Java Applications"
+- name: "io.openshift.tags"
+ value: "builder,java"
+- name: "maintainer"
+ value: "Red Hat OpenJDK "
+- name: "com.redhat.component"
+ value: "openjdk-21-jlink-tech-preview-ubi9-container"
+- name: "usage"
+ value: &docs "https://rh-openjdk.github.io/redhat-openjdk-containers/"
+- name: "com.redhat.license_terms"
+ value: "https://www.redhat.com/en/about/red-hat-end-user-license-agreements#UBI"
+- name: "org.opencontainers.image.documentation"
+ value: *docs
+- name: "name"
+ value: *name
+- name: "version"
+ value: *version
+
+envs:
+- name: PATH
+ value: $PATH:"/usr/local/s2i"
+- name: "JBOSS_IMAGE_NAME"
+ value: *name
+- name: "JBOSS_IMAGE_VERSION"
+ value: *version
+- name: "LANG"
+ value: "C.utf8"
+
+ports:
+- value: 8080
+- value: 8443
+
+modules:
+ repositories:
+ - path: modules
+ install:
+ - name: jboss.container.util.pkg-update
+ - name: jboss.container.openjdk.jdk
+ version: "21"
+ - name: jboss.container.maven
+ version: "3.9.21"
+ - name: jboss.container.util.tzdata
+ - name: jboss.container.java.s2i.bash
+ - name: jboss.container.util.tzdata
+ - name: jboss.container.java.jlink
+
+help:
+ add: true
+
+packages:
+ manager: microdnf
diff --git a/redhat/openjdk-21-jlink-rhel9.yaml b/redhat/openjdk-21-jlink-rhel9.yaml
new file mode 100644
index 00000000..3df38266
--- /dev/null
+++ b/redhat/openjdk-21-jlink-rhel9.yaml
@@ -0,0 +1,33 @@
+# This OSBS Base Image is designed and engineered to be the base layer for
+# Red Hat products. This base image is only supported for approved Red Hat
+# products. This image is maintained by Red Hat and updated regularly.
+from: registry.redhat.io/rhel9-osbs/osbs-ubi9-minimal
+osbs:
+ configuration:
+ container:
+ compose:
+ pulp_repos: true
+ packages:
+ - java-21-openjdk
+ - java-21-openjdk-devel
+ - java-21-openjdk-headless
+ signing_intent: release
+ repository:
+ name: containers/openjdk
+ branch: openjdk-21-jlink-tech-preview-ubi9
+
+packages:
+ manager: microdnf
+ content_sets:
+ x86_64:
+ - rhel-9-for-x86_64-baseos-rpms
+ - rhel-9-for-x86_64-appstream-rpms
+ ppc64le:
+ - rhel-9-for-ppc64le-baseos-rpms
+ - rhel-9-for-ppc64le-appstream-rpms
+ aarch64:
+ - rhel-9-for-aarch64-baseos-rpms
+ - rhel-9-for-aarch64-appstream-rpms
+ s390x:
+ - rhel-9-for-s390x-baseos-rpms
+ - rhel-9-for-s390x-appstream-rpms
diff --git a/templates/jlink/README.md b/templates/jlink/README.md
new file mode 100644
index 00000000..3eb9fd52
--- /dev/null
+++ b/templates/jlink/README.md
@@ -0,0 +1,125 @@
+# OpenShift Jlink integration (Tech Preview)
+
+To try it out,
+you need:
+
+1. Access to an OpenShift instance, such as [OpenShift Local](https://developers.redhat.com/products/openshift-local/overview)
+2. UBI9 OpenJDK ImageStreams that include `jlink-dev` changes (see below)
+3. The template [jlinked-app.yaml](jlinked-app.yaml).
+
+DISCLAIMER: This template requires OpenShift to be able to resolve ImageStreams, as such it can only be used in projects where the openshift.io/run-level label set to 0 or 1. This means it cannot be used with default, kube-public, kube-system, openshift, openshift-infra, openshift-node, and other system-created projects.
+
+## Stage 0: UBI9 OpenJDK ImageStreams with jlink-dev changes
+
+Whilst the `jlink-dev` feature is in Tech Preview, we must prepare separate
+UBI9 OpenJDK ImageStreams with `jlink-dev` support.
+
+1. Pull the Tech-Preview image
+
+ podman pull registry.access.redhat.com/openjdk-tech-preview/openjdk-21-jlink-rhel9:latest
+ podman tag registry.access.redhat.com/openjdk-tech-preview/openjdk-21-jlink-rhel9:latest \
+ openjdk-tech-preview/openjdk-21-jlink-rhel9:latest
+
+OR
+
+1. Build a suitable OpenJDK container image from [this
+ repository](https://github.com/jboss-container-images/openjdk),
+ branch `jlink-dev`. e.g.
+
+ cekit --descriptor ubi9-openjdk-21.yaml build podman
+
+2. Create an OpenShift project
+
+ oc new-project $PROJECT
+
+3. Within your OpenShift project,
+
+ oc create imagestream openjdk-21-jlink-tech-preview
+
+4. You may need to configure your container engine to not TLS-verify the OpenShift
+ registry. For Docker, add the following to `/etc/docker/daemon.json` and restart
+ the daemon:
+
+ {
+ "insecure-registries": [ "default-route-openshift-image-registry.apps-crc.testing" ]
+ }
+
+ For podman, add the following to `~/.config/containers/registries.conf`:
+
+ [[registry]]
+ location = "default-route-openshift-image-registry.apps-crc.testing"
+ insecure = true
+
+5. Log into the OpenShift registry, e.g.
+
+ REGISTRY_AUTH_PREFERENCE=docker oc registry login
+
+ or
+
+ oc registry login
+
+6. tag and push the dev image into it. The OpenShift console gives you the
+ exact URI for your instance
+
+ podman tag openjdk-tech-preview/openjdk-21-jlink-rhel9:latest default-route-openshift-image-registry.apps-crc.testing/$PROJECT/openjdk-21-jlink-tech-preview:latest
+ podman push default-route-openshift-image-registry.apps-crc.testing/$PROJECT/openjdk-21-jlink-tech-preview:latest
+
+## Stage 1: Load the template into OpenShift and instantiate it
+
+Create an OpenShift template `templates/jlink-app-template` from the jlinked-app template file
+
+ oc create -f templates/jlink/jlinked-app.yaml
+
+Process it to create the needed objects. You can list the parameters using
+
+ oc process --parameters jlink-app-template
+
+Some suitable test values for the parameters are
+
+ * JDK_VERSION: 21
+ * APP_URI: https://github.com/rh-openjdk/openjdk-container-test-applications
+ * REF: master
+ * CONTEXT_DIR: quarkus-quickstarts/getting-started-3.21.2-uberjar
+ * APPNAME: quarkus-quickstart
+ * TARGET_PORT: 8080
+ * SERVICE_PORT: 8080
+
+ oc process \
+ -p JDK_VERSION=21 \
+ -p APP_URI=https://github.com/rh-openjdk/openjdk-container-test-applications \
+ -p REF=master \
+ -p CONTEXT_DIR=quarkus-quickstarts/getting-started-3.21.2-uberjar \
+ -p APPNAME=quarkus-quickstart \
+ -p TARGET_PORT=8080 \
+ -p SERVICE_PORT=8080 \
+ templates/jlink-app-template \
+ | oc create -f -
+
+## Stage 2: Observe the results
+
+See all the OpenShift objects that were created:
+
+ oc get all
+
+## Stage 3: Kick off builds
+
+Instantiating the template will cause 3 separate BuildConfigs to be created and will automatically start their builds in sequence:
+
+1. $APPNAME-jlink-builder-jdk-$JDK_VERSION
+2. $APPNAME-jlink-s2i-jdk-$JDK_VERSION
+3. $APPNAME-multistage-buildconfig
+
+Where $APPNAME and $JDK_VERSION are the paremeters initially passed to the template.
+
+A build will automatically start for (1). Once complete, builds for (2) and (3) should be automatically triggered in sequence.
+
+## Stage 4: create deployment
+
+The ImageStreamTag `$APPNAME-lightweight-image:latest` will be populated with the new application container image.
+
+Create a deployment to see it work. E.g., in the Developer Perspective, select
+"+Add", "Container Images", "Image stream tag from internal registry", ...,
+"Create"
+
+Then from "Topology", select the "Open URL" icon to open the newly deployed
+App.
diff --git a/templates/jlink/jlinked-app.yaml b/templates/jlink/jlinked-app.yaml
new file mode 100644
index 00000000..79b200af
--- /dev/null
+++ b/templates/jlink/jlinked-app.yaml
@@ -0,0 +1,307 @@
+---
+apiVersion: template.openshift.io/v1
+kind: Template
+metadata:
+ annotations:
+ description: Template to produce imagestreams and buildconfigs for jlinked application
+ name: jlink-app-template
+##############################################################################
+# List of parameters required to create template
+parameters:
+- description: JDK version to produce a jmods image and imagestream for
+ name: JDK_VERSION
+ value: "21"
+ required: true
+- description: OpenJDK builder image version tag
+ name: BUILDER_IMAGE_TAG
+ value: "latest"
+- description: A name for the application used to ensure created resources are uniquely named
+ name: APPNAME
+ required: true
+- description: Application to run the jlink workflow on
+ name: APP_URI
+ required: true
+- description: Git Ref to run the jlink workflow on
+ name: REF
+ required: true
+- description: Context Dir to use for the jlink workflow
+ name: CONTEXT_DIR
+ required: true
+- description: A secret string used to configure the GitHub webhook
+ name: GITHUB_WEBHOOK_SECRET
+ generate: expression
+ from: "[a-zA-Z0-9]{16}"
+ required: true
+- description: Target port for the created Route
+ name: TARGET_PORT
+ value: "8080"
+ required: true
+- description: Port for the created Service to listen on
+ name: SERVICE_PORT
+ value: "8181"
+ required: true
+message: "... The GitHub webhook secret is ${GITHUB_WEBHOOK_SECRET} ..."
+##############################################################################
+# Following are the objects(imagestream and buildconfigs) for all the 3-stages
+objects:
+##############################################################################
+# stage-1: Output ImageStream
+- apiVersion: image.openshift.io/v1
+ kind: ImageStream
+ metadata:
+ name: ${APPNAME}-openjdk-${JDK_VERSION}-jlink-tech-preview
+ labels:
+ app: ${APPNAME}
+ app.kubernetes.io/part-of: ${APPNAME}
+ spec:
+ lookupPolicy:
+ local: false
+##############################################################################
+# stage-1: BuildConfig
+- apiVersion: build.openshift.io/v1
+ kind: BuildConfig
+ metadata:
+ name: ${APPNAME}-jlink-builder-jdk-${JDK_VERSION}
+ labels:
+ app: ${APPNAME}
+ app.kubernetes.io/part-of: ${APPNAME}
+ spec:
+ source:
+ dockerfile: |
+ FROM -
+ RUN if [ ! -f "/opt/jboss/container/java/jlink/preflight.sh" ]; then echo "jlink scripts doesn't exist" 2>&1; exit 1; fi
+ USER 0
+ RUN mkdir -p /mnt/jrootfs
+ RUN microdnf install --installroot /mnt/jrootfs --releasever 9 --setopt install_weak_deps=0 --nodocs -y \
+ --config=/etc/dnf/dnf.conf \
+ --noplugins \
+ --setopt=cachedir=/var/cache \
+ --setopt=reposdir=/etc/yum.repos.d \
+ --setopt=varsdir=/etc/dnf/vars \
+ grep gawk
+ RUN rm -rf /mnt/jrootfs/var/cache/* /mnt/jrootfs/var/lib/rpm /mnt/jrootfs/var/lib/dnf
+ USER 185
+ strategy:
+ dockerStrategy:
+ from:
+ kind: ImageStreamTag
+ name: openjdk-${JDK_VERSION}-jlink-tech-preview:${BUILDER_IMAGE_TAG} # Refer README.md to create this ImageStream
+ output:
+ to:
+ kind: ImageStreamTag
+ name: ${APPNAME}-openjdk-${JDK_VERSION}-jlink-tech-preview:latest
+ triggers:
+ - type: ConfigChange
+ - type: ImageChange
+ imageChange:
+ from:
+ kind: ImageStreamTag
+ name: openjdk-${JDK_VERSION}-jlink-tech-preview:${BUILDER_IMAGE_TAG}
+##############################################################################
+# stage-2: Output ImageStream
+- apiVersion: image.openshift.io/v1
+ kind: ImageStream
+ metadata:
+ name: ${APPNAME}-intermediate
+ labels:
+ app: ${APPNAME}
+ app.kubernetes.io/part-of: ${APPNAME}
+ spec:
+ lookupPolicy:
+ local: false
+##############################################################################
+# stage-2: BuildConfig
+- apiVersion: build.openshift.io/v1
+ kind: BuildConfig
+ metadata:
+ name: ${APPNAME}-jlink-s2i-jdk-${JDK_VERSION}
+ labels:
+ app: ${APPNAME}
+ app.kubernetes.io/part-of: ${APPNAME}
+ spec:
+ source:
+ type: Git
+ git:
+ uri: ${APP_URI}
+ ref: ${REF}
+ contextDir: ${CONTEXT_DIR}
+ strategy:
+ sourceStrategy:
+ from:
+ kind: ImageStreamTag
+ name: ${APPNAME}-openjdk-${JDK_VERSION}-jlink-tech-preview:latest # Output Imagestream from stage-1
+ pullPolicy: Always
+ env:
+ - name: S2I_ENABLE_JLINK
+ value: "true"
+ - name: LOGGING_SCRIPT_DEBUG
+ value: "true"
+ output:
+ to:
+ kind: ImageStreamTag
+ name: ${APPNAME}-intermediate:latest
+ triggers:
+ - type: ConfigChange
+ - type: ImageChange
+ imageChange:
+ from:
+ kind: ImageStreamTag
+ name: ${APPNAME}-openjdk-${JDK_VERSION}-jlink-tech-preview:latest # Output of stage-1 which serves as input to stage-2
+ - type: GitHub
+ github:
+ secret: ${GITHUB_WEBHOOK_SECRET}
+ event: push
+##############################################################################
+# stage-3: The ubi-micro ImageStream
+- apiVersion: image.openshift.io/v1
+ kind: ImageStream
+ metadata:
+ name: ${APPNAME}-ubimicro
+ labels:
+ app: ${APPNAME}
+ app.kubernetes.io/part-of: ${APPNAME}
+ spec:
+ lookupPolicy:
+ local: true
+ tags:
+ - from:
+ kind: DockerImage
+ name: registry.access.redhat.com/ubi9/ubi-micro
+ name: latest
+ referencePolicy:
+ type: Local
+##############################################################################
+# stage-3: Output ImageStream
+- apiVersion: image.openshift.io/v1
+ kind: ImageStream
+ metadata:
+ name: ${APPNAME}-lightweight-image
+ labels:
+ app: ${APPNAME}
+ app.kubernetes.io/part-of: ${APPNAME}
+ spec:
+ lookupPolicy:
+ # Must be true for the Deployment to resolve the ImageStream
+ local: true
+##############################################################################
+# stage-3: BuildConfig
+- apiVersion: build.openshift.io/v1
+ kind: BuildConfig
+ metadata:
+ name: ${APPNAME}-multistage-buildconfig
+ labels:
+ app: ${APPNAME}
+ app.kubernetes.io/part-of: ${APPNAME}
+ spec:
+ source:
+ images:
+ - from:
+ kind: ImageStreamTag
+ name: ${APPNAME}-intermediate:latest
+ paths:
+ - sourcePath: /mnt/jrootfs
+ destinationDir: jrootfs
+ - sourcePath: /deployments
+ destinationDir: deployments
+ - sourcePath: /tmp/jre/.
+ destinationDir: customJVM
+ - sourcePath: /opt/jboss/container/.
+ destinationDir: runScripts
+ type: Dockerfile
+ dockerfile: |
+ FROM -
+ ARG JAVA_HOME=/usr/lib/jvm/java
+
+ COPY jrootfs/* /
+ COPY deployments /
+ COPY customJVM ${JAVA_HOME}
+ COPY runScripts /opt/jboss/container/
+ # these are in the micro image
+ RUN rm -rf /var/lib/dnf /var/lib/rpm
+
+ ENV JAVA_HOME="${JAVA_HOME}" PATH="${JAVA_HOME}/bin:$PATH"
+ USER 185
+ CMD /opt/jboss/container/java/run/run-java.sh
+ strategy:
+ type: Docker
+ dockerStrategy:
+ from:
+ kind: ImageStreamTag
+ name: ${APPNAME}-ubimicro:latest
+ output:
+ to:
+ kind: ImageStreamTag
+ name: ${APPNAME}-lightweight-image:latest # Tag for the final output image
+ triggers:
+ - type: ConfigChange
+ - type: ImageChange
+ imageChange:
+ from:
+ kind: ImageStreamTag
+ name: ${APPNAME}-intermediate:latest # output of stage-2
+ - type: ImageChange
+ imageChange:
+ from:
+ kind: ImageStreamTag
+ name: ${APPNAME}-ubimicro:latest # ImageStreamTag for registry.access.redhat.com/ubi9/ubi-micro
+##############################################################################
+# DeploymentConfig and Route object specs
+# DeploymentConfigs are discouraged, however the documentation sugggests to still
+# use them if features are missing from Deployments, which in our case they are.
+- apiVersion: apps/v1
+ kind: Deployment
+ metadata:
+ name: ${APPNAME}-jlinked-app-deployment
+ labels:
+ app: ${APPNAME}
+ app.kubernetes.io/part-of: ${APPNAME}
+ spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ${APPNAME}
+ template:
+ metadata:
+ labels:
+ app: ${APPNAME}
+ app.kubernetes.io/part-of: ${APPNAME}
+ annotations:
+ # Allows Deployments to use ImageStreams
+ alpha.image.policy.openshift.io/resolve-names: '*'
+ spec:
+ containers:
+ - name: ${APPNAME}-jlinked-app-container
+ image: ${APPNAME}-lightweight-image:latest
+ ports:
+ - containerPort: ${{TARGET_PORT}}
+ protocol: TCP
+ strategy:
+ type: RollingUpdate
+- apiVersion: v1
+ kind: Service
+ metadata:
+ name: ${APPNAME}-jlinked-app-service
+ labels:
+ app: ${APPNAME}
+ app.kubernetes.io/part-of: ${APPNAME}
+ spec:
+ selector:
+ app: ${APPNAME}
+ ports:
+ - protocol: TCP
+ name: target-${TARGET_PORT}-tcp
+ port: ${{SERVICE_PORT}}
+ targetPort: ${{TARGET_PORT}}
+- apiVersion: route.openshift.io/v1
+ kind: Route
+ metadata:
+ name: ${APPNAME}-jlinked-app-route
+ labels:
+ app: ${APPNAME}
+ app.kubernetes.io/part-of: ${APPNAME}
+ spec:
+ to:
+ kind: Service
+ name: ${APPNAME}-jlinked-app-service
+ port:
+ targetPort: ${{TARGET_PORT}}
diff --git a/templates/ubi9-community-image-streams.json b/templates/ubi9-community-image-streams.json
new file mode 100644
index 00000000..c1de1edf
--- /dev/null
+++ b/templates/ubi9-community-image-streams.json
@@ -0,0 +1,458 @@
+{
+ "kind": "List",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "ubi9-openjdk-image-stream",
+ "annotations": {
+ "description": "ImageStream definition for Red Hat UBI9 OpenJDK.",
+ "openshift.io/provider-display-name": "Red Hat, Inc."
+ }
+ },
+ "items": [
+ {
+ "kind": "ImageStream",
+ "apiVersion": "image.openshift.io/v1",
+ "metadata": {
+ "name": "ubi9-openjdk-11",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 11 (UBI9)",
+ "openshift.io/provider-display-name": "Red Hat, Inc."
+ }
+ },
+ "spec": {
+ "tags": [
+ {
+ "name": "1.13",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 11 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 11 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.13"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-11:1.13"
+ }
+ },
+ {
+ "name": "1.14",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 11 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 11 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.14"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-11:1.14"
+ }
+ },
+ {
+ "name": "1.15",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 11 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 11 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.15"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-11:1.15"
+ }
+ },
+ {
+ "name": "1.16",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 11 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 11 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.16"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-11:1.16"
+ }
+ },
+ {
+ "name": "1.17",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 11 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 11 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.17"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-11:1.17"
+ }
+ },
+ {
+ "name": "1.18",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 11 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 11 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.18"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-11:1.18"
+ }
+ }
+ ]
+ }
+ },
+{
+ "kind": "ImageStream",
+ "apiVersion": "image.openshift.io/v1",
+ "metadata": {
+ "name": "ubi9-openjdk-17",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 17 (UBI9)",
+ "openshift.io/provider-display-name": "Red Hat, Inc."
+ }
+ },
+ "spec": {
+ "tags": [
+ {
+ "name": "1.13",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 17 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 17 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.13"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-17:1.13"
+ }
+ },
+ {
+ "name": "1.14",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 17 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 17 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.14"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-17:1.14"
+ }
+ },
+ {
+ "name": "1.15",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 17 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 17 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.15"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-17:1.15"
+ }
+ },
+ {
+ "name": "1.16",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 17 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 17 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.16"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-17:1.16"
+ }
+ },
+ {
+ "name": "1.17",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 17 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 17 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.17"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-17:1.17"
+ }
+ },
+ {
+ "name": "1.18",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 17 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 17 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.18"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-17:1.18"
+ }
+ }
+ ]
+ }
+ },
+{
+ "kind": "ImageStream",
+ "apiVersion": "image.openshift.io/v1",
+ "metadata": {
+ "name": "ubi9-openjdk-21",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 21 (UBI9)",
+ "openshift.io/provider-display-name": "Red Hat, Inc."
+ }
+ },
+ "spec": {
+ "tags": [
+ {
+ "name": "1.17",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 21 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 21 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.17"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-21:1.17"
+ }
+ },
+ {
+ "name": "1.18",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 21 (UBI9)",
+ "description": "Build and run Java applications using Maven and OpenJDK 21 upon UBI9.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,ubi9",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "1.18"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi9/openjdk-21:1.18"
+ }
+ }
+ ]
+ }
+ }, {
+ "kind": "ImageStream",
+ "apiVersion": "image.openshift.io/v1",
+ "metadata": {
+ "name": "java",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK",
+ "openshift.io/provider-display-name": "Red Hat, Inc."
+ }
+ },
+ "spec": {
+ "tags": [
+ {
+ "name": "openjdk-8-ubi8",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 8 (UBI 8)",
+ "description": "Build and run Java applications using Maven and OpenJDK 1.8 upon UBI8.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk",
+ "supports": "java:8,java",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "8"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi8/openjdk-8:latest"
+ }
+ },
+ {
+ "name": "8",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 8",
+ "description": "Build and run Java applications using Maven and OpenJDK 1.8 upon UBI8.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,hidden",
+ "supports": "java:8,java",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "8"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi8/openjdk-8:latest"
+ }
+ },
+ {
+ "name": "openjdk-11-ubi8",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 11 (UBI 8)",
+ "description": "Build and run Java applications using Maven and OpenJDK 11 upon UBI8.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk",
+ "supports": "java:11,java",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "11"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi8/openjdk-11:latest"
+ }
+ },
+ {
+ "name": "11",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 11",
+ "description": "Build and run Java applications using Maven and OpenJDK 11 upon UBI8.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk,hidden",
+ "supports": "java:11,java",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "11"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi8/openjdk-11:latest"
+ }
+ },
+ {
+ "name": "openjdk-17-ubi8",
+ "annotations": {
+ "openshift.io/display-name": "Red Hat OpenJDK 17 (UBI 8)",
+ "description": "Build and run Java applications using Maven and OpenJDK 17 upon UBI8.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk",
+ "supports": "java:17,java",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "17"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "DockerImage",
+ "name": "registry.access.redhat.com/ubi8/openjdk-17:latest"
+ }
+ },
+ {
+ "name": "latest",
+ "annotations": {
+ "openshift.io/display-name": "Java (Latest)",
+ "description": "Build and run Java applications using Maven.",
+ "iconClass": "icon-rh-openjdk",
+ "tags": "builder,java,openjdk",
+ "supports": "java",
+ "sampleRepo": "https://github.com/jboss-openshift/openshift-quickstarts",
+ "sampleContextDir": "undertow-servlet",
+ "version": "latest"
+ },
+ "referencePolicy": {
+ "type": "Local"
+ },
+ "from": {
+ "kind": "ImageStreamTag",
+ "name": "openjdk-17-ubi8"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/features/imagebasic.feature b/tests/features/imagebasic.feature
index cccff61e..d110b4e7 100644
--- a/tests/features/imagebasic.feature
+++ b/tests/features/imagebasic.feature
@@ -12,6 +12,7 @@ Feature: Tests for all openshift images
@ubi9/openjdk-11
@ubi9/openjdk-17
@ubi9/openjdk-21
+ @openjdk-tech-preview/openjdk-21-jlink-rhel9
Scenario: Check that builder labels are correctly set
Given image is built
Then the image should contain label io.openshift.s2i.scripts-url with value image:///usr/local/s2i
diff --git a/tests/features/java/ports.feature b/tests/features/java/ports.feature
index 0fa2a4a1..3079c182 100644
--- a/tests/features/java/ports.feature
+++ b/tests/features/java/ports.feature
@@ -1,6 +1,7 @@
@ubi9/openjdk-11
@ubi9/openjdk-17
@ubi9/openjdk-21
+@openjdk-tech-preview/openjdk-21-jlink-rhel9
Feature: Openshift OpenJDK port tests
Scenario: Check ports are available
diff --git a/ubi9-openjdk-17-runtime.yaml b/ubi9-openjdk-17-runtime.yaml
index fdee7cea..52d2f17f 100644
--- a/ubi9-openjdk-17-runtime.yaml
+++ b/ubi9-openjdk-17-runtime.yaml
@@ -22,6 +22,8 @@ labels:
value: &docs "https://rh-openjdk.github.io/redhat-openjdk-containers/"
- name: "com.redhat.license_terms"
value: "https://www.redhat.com/en/about/red-hat-end-user-license-agreements#UBI"
+- name: "org.opencontainers.image.source"
+ value: "https://github.com/rh-openjdk/redhat-openjdk-containers"
- name: "org.opencontainers.image.documentation"
value: *docs
- name: "name"
diff --git a/ubi9-openjdk-17.yaml b/ubi9-openjdk-17.yaml
index a701e347..ec412f02 100644
--- a/ubi9-openjdk-17.yaml
+++ b/ubi9-openjdk-17.yaml
@@ -22,6 +22,8 @@ labels:
value: &docs "https://rh-openjdk.github.io/redhat-openjdk-containers/"
- name: "com.redhat.license_terms"
value: "https://www.redhat.com/en/about/red-hat-end-user-license-agreements#UBI"
+- name: "org.opencontainers.image.source"
+ value: "https://github.com/rh-openjdk/redhat-openjdk-containers"
- name: "org.opencontainers.image.documentation"
value: *docs
- name: "name"