Skip to content

Commit

Permalink
Image resolvers should support both ubi 8 and 9
Browse files Browse the repository at this point in the history
  • Loading branch information
edeandrea committed May 28, 2024
1 parent 22ec638 commit 5cb3d06
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
import java.util.stream.Stream;

/**
* Can extract information from Dockerfile that uses {@code registry.access.redhat.com/ubi8/openjdk-$d-runtime:$d.$d} as the
* base image
* Can extract information from Dockerfile that uses
* {@code registry.access.redhat.com/ubi([8-9]|[1-9][0-9]+)/openjdk-$d-runtime:$d.$d} as the
* base image, where the java version must be >= 17
*/
class RedHatOpenJDKRuntimeBaseProvider implements DockerFileBaseInformationProvider {
private static final Pattern PATTERN = Pattern
.compile(".*ubi([8-9]|[1-9][0-9]+)/openjdk-(1[7-9]|[2-9][0-9]+|[1-9][0-9][0-9]+)-runtime.*");

@Override
public Optional<DockerFileBaseInformation> determine(Path dockerFile) {
Expand All @@ -21,10 +24,9 @@ public Optional<DockerFileBaseInformation> determine(Path dockerFile) {
if (fromOpt.isPresent()) {
String fromLine = fromOpt.get();
String baseImage = fromLine.substring(4).trim();
Pattern pattern = Pattern.compile(".*ubi8/openjdk-(\\w+)-runtime.*");
Matcher matcher = pattern.matcher(baseImage);
Matcher matcher = PATTERN.matcher(baseImage);
if (matcher.find()) {
String match = matcher.group(1);
String match = matcher.group(2);
try {
return Optional.of(new DockerFileBaseInformationProvider.DockerFileBaseInformation(baseImage,
Integer.parseInt(match)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,57 @@
import java.util.stream.Stream;

/**
* Can extract information from Dockerfile that uses {@code registry.access.redhat.com/ubi8/ubi-minimal:$d.$d} as the
* Can extract information from Dockerfile that uses {@code registry.access.redhat.com/ubi([8-9]|[1-9][0-9]+)/ubi-minimal:$d.$d}
* as the
* base image
*/
class UbiMinimalBaseProvider implements DockerFileBaseInformationProvider {
private static final Pattern BASE_IMAGE_PATTERN = Pattern.compile(".*/ubi([8-9]|[1-9][0-9]+)/ubi-minimal");
private static final Pattern JAVA_VERSION_PATTERN = Pattern
.compile("ARG JAVA_PACKAGE=java-(1[7-9]|[2-9][0-9]+|[1-9][0-9][0-9]+)-openjdk-headless");

public static final String UBI_MINIMAL_PREFIX = "registry.access.redhat.com/ubi8/ubi-minimal";
private enum State {
FROM_NOT_ENCOUNTERED,
MATCHING_FROM_FOUND,
ARG_JAVA_PACKAGE_FOUND,
NON_MATCHING_FROM_FOUND,
EXCEPTION_OCCURRED
}

@Override
public Optional<DockerFileBaseInformation> determine(Path dockerFile) {
AtomicInteger state = new AtomicInteger(0); //0: 'FROM' not yet encountered, 1: matching 'FROM' found, 2: ARG JAVA_PACKAGE found, 3: non matching 'FROM' found, 4: exception occurred
AtomicInteger state = new AtomicInteger(State.FROM_NOT_ENCOUNTERED.ordinal()); //0: 'FROM' not yet encountered, 1: matching 'FROM' found, 2: ARG JAVA_PACKAGE found, 3: non matching 'FROM' found, 4: exception occurred
AtomicReference<String> baseImage = new AtomicReference<>(null);
AtomicInteger javaVersion = new AtomicInteger(0);
try (Stream<String> lines = Files.lines(dockerFile)) {
lines.takeWhile(s -> state.get() < 2).forEach(s -> {
lines.takeWhile(s -> state.get() < State.ARG_JAVA_PACKAGE_FOUND.ordinal()).forEach(s -> {
if (s.startsWith("FROM")) {
String image = s.substring(4).trim();
if (image.startsWith(UBI_MINIMAL_PREFIX)) {
Matcher matcher = BASE_IMAGE_PATTERN.matcher(image);
if (matcher.find()) {
baseImage.set(image);
state.set(1);
state.set(State.MATCHING_FROM_FOUND.ordinal());
} else {
state.set(3);
state.set(State.NON_MATCHING_FROM_FOUND.ordinal());
}
} else if (s.startsWith("ARG JAVA_PACKAGE")) {
Pattern pattern = Pattern.compile("ARG JAVA_PACKAGE=java-(\\w+)-openjdk-headless");
Matcher matcher = pattern.matcher(s);
Matcher matcher = JAVA_VERSION_PATTERN.matcher(s);
if (matcher.find()) {
String match = matcher.group(1);
try {
javaVersion.set(Integer.parseInt(match));
state.set(2);
state.set(State.ARG_JAVA_PACKAGE_FOUND.ordinal());
} catch (NumberFormatException ignored) {
state.set(4);
state.set(State.EXCEPTION_OCCURRED.ordinal());
}
}
}
});
} catch (IOException ignored) {
state.set(4);
state.set(State.EXCEPTION_OCCURRED.ordinal());
}
if (state.get() == 2) {

if (state.get() == State.ARG_JAVA_PACKAGE_FOUND.ordinal()) {
return Optional.of(new DockerFileBaseInformation(baseImage.get(), javaVersion.get()));
}
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,53 @@

import static io.quarkus.container.image.docker.common.deployment.TestUtil.getPath;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.params.ParameterizedTest.ARGUMENTS_WITH_NAMES_PLACEHOLDER;
import static org.junit.jupiter.params.ParameterizedTest.DISPLAY_NAME_PLACEHOLDER;
import static org.junit.jupiter.params.ParameterizedTest.INDEX_PLACEHOLDER;

import java.nio.file.Path;
import java.util.stream.Stream;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import io.quarkus.container.image.docker.common.deployment.DockerFileBaseInformationProvider.DockerFileBaseInformation;

class RedHatOpenJDKRuntimeBaseProviderTest {

private final DockerFileBaseInformationProvider sut = new RedHatOpenJDKRuntimeBaseProvider();

@Test
void testImageWithJava17() {
Path path = getPath("openjdk-17-runtime");
@ParameterizedTest(name = DISPLAY_NAME_PLACEHOLDER + "[" + INDEX_PLACEHOLDER + "] (" + ARGUMENTS_WITH_NAMES_PLACEHOLDER
+ ")")
@MethodSource("imageCombinations")
void testImage(int javaVersion, int ubiVersion, String imageVersion) {
var path = getPath("ubi%d-openjdk-%d-runtime".formatted(ubiVersion, javaVersion));
var result = sut.determine(path);
assertThat(result).hasValueSatisfying(v -> {
assertThat(v.baseImage()).isEqualTo("registry.access.redhat.com/ubi8/openjdk-17-runtime:1.19");
assertThat(v.javaVersion()).isEqualTo(17);
});
assertThat(result)
.isNotNull()
.get()
.extracting(
DockerFileBaseInformation::baseImage,
DockerFileBaseInformation::javaVersion)
.containsExactly(
"registry.access.redhat.com/ubi%d/openjdk-%d-runtime:%s".formatted(ubiVersion, javaVersion,
imageVersion),
javaVersion);
}

@Test
void testImageWithJava21() {
Path path = getPath("openjdk-21-runtime");
var result = sut.determine(path);
assertThat(result).hasValueSatisfying(v -> {
assertThat(v.baseImage()).isEqualTo("registry.access.redhat.com/ubi8/openjdk-21-runtime:1.19");
assertThat(v.javaVersion()).isEqualTo(21);
});
static Stream<Arguments> imageCombinations() {
return Stream.of(
Arguments.of(17, 8, "1.19"),
Arguments.of(21, 8, "1.19"),
Arguments.of(17, 9, "1.18"),
Arguments.of(21, 9, "1.18"));
}

@Test
void testUnhandled() {
Path path = getPath("ubi-java17");
Path path = getPath("ubi8-java17");
var result = sut.determine(path);
assertThat(result).isEmpty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,52 @@

import static io.quarkus.container.image.docker.common.deployment.TestUtil.getPath;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.params.ParameterizedTest.ARGUMENTS_WITH_NAMES_PLACEHOLDER;
import static org.junit.jupiter.params.ParameterizedTest.DISPLAY_NAME_PLACEHOLDER;
import static org.junit.jupiter.params.ParameterizedTest.INDEX_PLACEHOLDER;

import java.nio.file.Path;
import java.util.stream.Stream;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import io.quarkus.container.image.docker.common.deployment.DockerFileBaseInformationProvider.DockerFileBaseInformation;

class UbiMinimalBaseProviderTest {

private final DockerFileBaseInformationProvider sut = new UbiMinimalBaseProvider();

@Test
void testImageWithJava17() {
Path path = getPath("ubi-java17");
@ParameterizedTest(name = DISPLAY_NAME_PLACEHOLDER + "[" + INDEX_PLACEHOLDER + "] (" + ARGUMENTS_WITH_NAMES_PLACEHOLDER
+ ")")
@MethodSource("imageCombinations")
void testImage(int ubiVersion, int javaVersion, String imageVersion) {
var path = getPath("ubi%d-java%d".formatted(ubiVersion, javaVersion));
var result = sut.determine(path);
assertThat(result).hasValueSatisfying(v -> {
assertThat(v.baseImage()).isEqualTo("registry.access.redhat.com/ubi8/ubi-minimal:8.9");
assertThat(v.javaVersion()).isEqualTo(17);
});
assertThat(result)
.isNotNull()
.get()
.extracting(
DockerFileBaseInformation::baseImage,
DockerFileBaseInformation::javaVersion)
.containsExactly(
"registry.access.redhat.com/ubi%d/ubi-minimal:%s".formatted(ubiVersion, imageVersion),
javaVersion);
}

@Test
void testImageWithJava21() {
Path path = getPath("ubi-java21");
var result = sut.determine(path);
assertThat(result).hasValueSatisfying(v -> {
assertThat(v.baseImage()).isEqualTo("registry.access.redhat.com/ubi8/ubi-minimal:8.9");
assertThat(v.javaVersion()).isEqualTo(21);
});
static Stream<Arguments> imageCombinations() {
return Stream.of(
Arguments.of(8, 17, "8.9"),
Arguments.of(8, 21, "8.9"),
Arguments.of(9, 17, "9.4"),
Arguments.of(9, 21, "9.4"));
}

@Test
void testUnhandled() {
Path path = getPath("openjdk-17-runtime");
Path path = getPath("ubi8-openjdk-17-runtime");
var result = sut.determine(path);
assertThat(result).isEmpty();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.4

ARG JAVA_PACKAGE=java-17-openjdk-headless
ARG RUN_JAVA_VERSION=1.3.8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
# Install java and the run-java script
# Also set up permissions for user `1001`
RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
&& microdnf update \
&& microdnf clean all \
&& mkdir /deployments \
&& chown 1001 /deployments \
&& chmod "g+rwX" /deployments \
&& chown 1001:root /deployments \
&& curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
&& chown 1001 /deployments/run-java.sh \
&& chmod 540 /deployments/run-java.sh \
&& echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security

# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=1001 target/quarkus-app/*.jar /deployments/
COPY --chown=1001 target/quarkus-app/app/ /deployments/app/
COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/

EXPOSE 8080
USER 1001

ENTRYPOINT [ "/deployments/run-java.sh" ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.4

ARG JAVA_PACKAGE=java-21-openjdk-headless
ARG RUN_JAVA_VERSION=1.3.8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
# Install java and the run-java script
# Also set up permissions for user `1001`
RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
&& microdnf update \
&& microdnf clean all \
&& mkdir /deployments \
&& chown 1001 /deployments \
&& chmod "g+rwX" /deployments \
&& chown 1001:root /deployments \
&& curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
&& chown 1001 /deployments/run-java.sh \
&& chmod 540 /deployments/run-java.sh \
&& echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security

# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=1001 target/quarkus-app/*.jar /deployments/
COPY --chown=1001 target/quarkus-app/app/ /deployments/app/
COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/

EXPOSE 8080
USER 1001

ENTRYPOINT [ "/deployments/run-java.sh" ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM registry.access.redhat.com/ubi9/openjdk-17-runtime:1.18

ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'

# Append additional options to the java process, you can add -XshowSettings:vm to also display the heap size.
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"

# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/

EXPOSE 8080
USER 185

ENTRYPOINT [ "java", "-jar", "/deployments/quarkus-run.jar" ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Use Java 21 base image
FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.18

ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'

# Append additional options to the java process, you can add -XshowSettings:vm to also display the heap size.
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"

# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/

EXPOSE 8080
USER 185

ENTRYPOINT [ "java", "-jar", "/deployments/quarkus-run.jar" ]

0 comments on commit 5cb3d06

Please sign in to comment.