Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java 9 long classpath support to enable deterministic class loading order #3280

Merged
merged 9 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public enum LayerType {
PROJECT_DEPENDENCIES("project dependencies"),
RESOURCES("resources"),
CLASSES("classes"),
EXTRA_FILES("extra files");
EXTRA_FILES("extra files"),
JVM_ARG_FILES("jvm arg files");

private final String name;

Expand Down
2 changes: 2 additions & 0 deletions jib-gradle-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ All notable changes to this project will be documented in this file.

### Changed

- Jib now creates an additional layer that contains two small text files: `/app/jib-classpath-file` and `/app/jib-main-class-file`. They hold, respectively, the final Java runtime classpath and the main class computed by Jib that are suitable for app execution on JVM. For example, with Java 9+, setting the container entrypoint to `java --class-path @/app/jib-classpath-file @/app/jib-main-class-file` will work to start the app. (This is basically the default entrypoint set by Jib when the entrypoint is not explicitly configured by the user.) The files are always generated whether Java 8 or 9+, or whether `jib.container.entrypoint` is explicitly configured. The files can be helpful especially when setting a custom entrypoint for a shell script that needs to get the classpath and the main class computed by Jib, or for [AppCDS](https://github.com/GoogleContainerTools/jib/issues/2471). ([#3280](https://github.com/GoogleContainerTools/jib/pull/3280))
- For Java 9+ apps, the default Java runtime classpath explicitly lists all the app dependencies, preserving the dependency loading order declared by Gradle. This is done by changing the default entrypoint to use the new classpath JVM argument file (basically `java -cp @/app/jib-classpath-file`). As such, `jib.container.expandClasspathDependencies` takes no effect for Java 9+. ([#3280](https://github.com/GoogleContainerTools/jib/pull/3280))
- Timestamps of file entries in a tarball built with `jibBuildTar` are set to the epoch, making the tarball reproducible. ([#3158](https://github.com/GoogleContainerTools/jib/issues/3158))

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import static com.google.common.truth.Truth.assertThat;

import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -27,7 +26,6 @@
import java.util.zip.GZIPInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;

Expand All @@ -46,11 +44,12 @@ public void testGradleLayerConfiguration_configurationName() throws IOException

// the expected order is:
// no base image layers (scratch)
// classes (0)
// resources (1)
// dependencies (2)
// jvm arg files (0)
// classes (1)
// resources (2)
// dependencies (3)
// verify dependencies
List<String> dependencies = layers.get(2);
List<String> dependencies = layers.get(3);
assertThat(dependencies).containsExactly("app/", "app/libs/", "app/libs/dependency2").inOrder();
}

Expand All @@ -59,18 +58,20 @@ public void testGradleLayerConfiguration_configurationName_prioritizeSystemPrope
throws IOException {
configTestProject.build(
"jibBuildTar",
"--stacktrace",
"-Djib.configurationName=otherConfiguration",
"-b=build-configuration.gradle");
Path jibTar = configTestProject.getProjectRoot().resolve("build/jib-image.tar");
List<List<String>> layers = getLayers(jibTar);

// the expected order is:
// no base image layers (scratch)
// classes (0)
// resources (1)
// dependencies (2)
// jvm arg files (0)
// classes (1)
// resources (2)
// dependencies (3)
// verify dependencies
List<String> dependencies = layers.get(2);
List<String> dependencies = layers.get(3);
assertThat(dependencies).containsExactly("app/", "app/libs/", "app/libs/dependency3").inOrder();
}

Expand All @@ -82,57 +83,53 @@ public void testGradleLayerConfiguration_multiModule() throws IOException {

List<List<String>> layers = getLayers(jibTar);

Assert.assertEquals(6, layers.size());
assertThat(layers).hasSize(7);

// the expected order is:
// no base image layers (scratch)
// extra-files (0)
// classes (1)
// resources (2)
// project dependencies (3)
// snapshot dependencies (4)
// dependencies (5)
// jvm arg files (1)
// classes (2)
// resources (3)
// project dependencies (4)
// snapshot dependencies (5)
// dependencies (6)

// verify dependencies
List<String> dependencies = layers.get(5);
List<String> expectedDependencies =
ImmutableList.of("app/", "app/libs/", "app/libs/dependency-1.0.0.jar");
Assert.assertEquals(expectedDependencies, dependencies);
assertThat(layers.get(6))
.containsExactly("app/", "app/libs/", "app/libs/dependency-1.0.0.jar")
.inOrder();

// verify snapshot dependencies
List<String> snapshotDependencies = layers.get(4);
List<String> expectedSnapshotDependencies =
ImmutableList.of("app/", "app/libs/", "app/libs/dependencyX-1.0.0-SNAPSHOT.jar");
Assert.assertEquals(expectedSnapshotDependencies, snapshotDependencies);
assertThat(layers.get(5))
.containsExactly("app/", "app/libs/", "app/libs/dependencyX-1.0.0-SNAPSHOT.jar")
.inOrder();

// verify project dependencies
List<String> projectDependencies = layers.get(3);
List<String> expectedProjectDependencies =
ImmutableList.of("app/", "app/libs/", "app/libs/lib.jar");
Assert.assertEquals(expectedProjectDependencies, projectDependencies);
assertThat(layers.get(4)).containsExactly("app/", "app/libs/", "app/libs/lib.jar").inOrder();

// verify resources
List<String> resources = layers.get(2);
List<String> expectedResources =
ImmutableList.of(
"app/", "app/resources/", "app/resources/resource1.txt", "app/resources/resource2.txt");
Assert.assertEquals(expectedResources, resources);
assertThat(layers.get(3))
.containsExactly(
"app/", "app/resources/", "app/resources/resource1.txt", "app/resources/resource2.txt")
.inOrder();

// verify classes
List<String> classes = layers.get(1);
List<String> expectedClasses =
ImmutableList.of(
assertThat(layers.get(2))
.containsExactly(
"app/",
"app/classes/",
"app/classes/com/",
"app/classes/com/test/",
"app/classes/com/test/HelloWorld.class");
Assert.assertEquals(expectedClasses, classes);

// verify jvm arg files
assertThat(layers.get(1))
.containsExactly("app/", "app/jib-classpath-file", "app/jib-main-class-file")
.inOrder();

// verify extra files
List<String> extraFiles = layers.get(0);
List<String> expectedExtraFiles = ImmutableList.of("extra-file");
Assert.assertEquals(expectedExtraFiles, extraFiles);
assertThat(layers.get(0)).containsExactly("extra-file");
}

@Test
Expand All @@ -143,22 +140,27 @@ public void testGradleLayerConfiguration_simpleModule() throws IOException {

List<List<String>> layers = getLayers(jibTar);

Assert.assertEquals(1, layers.size());
assertThat(layers).hasSize(2);

// the expected order is:
// no base image layers (scratch)
// classes (0)
// jvm arg files (0)
// classes (1)

// verify classes
List<String> classes = layers.get(0);
List<String> expectedClasses =
ImmutableList.of(
assertThat(layers.get(1))
.containsExactly(
"app/",
"app/classes/",
"app/classes/com/",
"app/classes/com/test/",
"app/classes/com/test/HelloWorld.class");
Assert.assertEquals(expectedClasses, classes);
"app/classes/com/test/HelloWorld.class")
.inOrder();

// verify jvm arg files
assertThat(layers.get(0))
.containsExactly("app/", "app/jib-classpath-file", "app/jib-main-class-file")
.inOrder();
}

// returns all files in layers (*.tar.gz) in a image tar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ public void testBuild_simple()
assertThat(getEntrypoint(targetImage))
.isEqualTo(
"[java -cp /d1:/d2:/app/resources:/app/classes:/app/libs/* com.test.HelloWorld]");
assertThat(getLayerSize(targetImage)).isEqualTo(9);
assertThat(getLayerSize(targetImage)).isEqualTo(10);
}

@Test
Expand Down Expand Up @@ -306,7 +306,7 @@ public void testDockerDaemon_simple_multipleExtraDirectories()
+ "1970-01-01T00:00:01Z\n1970-01-01T00:00:01Z\n",
JibRunHelper.buildToDockerDaemonAndRun(
simpleTestProject, targetImage, "build-extra-dirs.gradle"));
assertThat(getLayerSize(targetImage)).isEqualTo(10); // one more than usual
assertThat(getLayerSize(targetImage)).isEqualTo(11); // one more than usual
}

@Test
Expand All @@ -318,7 +318,7 @@ public void testDockerDaemon_simple_multipleExtraDirectoriesWithAlternativeConfi
+ "1970-01-01T00:00:01Z\n1970-01-01T00:00:01Z\n",
JibRunHelper.buildToDockerDaemonAndRun(
simpleTestProject, targetImage, "build-extra-dirs2.gradle"));
assertThat(getLayerSize(targetImage)).isEqualTo(10); // one more than usual
assertThat(getLayerSize(targetImage)).isEqualTo(11); // one more than usual
}

@Test
Expand All @@ -330,7 +330,7 @@ public void testDockerDaemon_simple_multipleExtraDirectoriesWithClosure()
+ "1970-01-01T00:00:01Z\n1970-01-01T00:00:01Z\nbaz\n1970-01-01T00:00:01Z\n",
JibRunHelper.buildToDockerDaemonAndRun(
simpleTestProject, targetImage, "build-extra-dirs3.gradle"));
assertThat(getLayerSize(targetImage)).isEqualTo(10); // one more than usual
assertThat(getLayerSize(targetImage)).isEqualTo(11); // one more than usual
}

@Test
Expand Down
2 changes: 2 additions & 0 deletions jib-maven-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ All notable changes to this project will be documented in this file.

### Changed

- Jib now creates an additional layer that contains two small text files: `/app/jib-classpath-file` and `/app/jib-main-class-file`. They hold, respectively, the final Java runtime classpath and the main class computed by Jib that are suitable for app execution on JVM. For example, with Java 9+, setting the container entrypoint to `java --class-path @/app/jib-classpath-file @/app/jib-main-class-file` will work to start the app. (This is basically the default entrypoint set by Jib when the entrypoint is not explicitly configured by the user.) The files are always generated whether Java 8 or 9+, or whether `jib.container.entrypoint` is explicitly configured. The files can be helpful especially when setting a custom entrypoint for a shell script that needs to get the classpath and the main class computed by Jib, or for [AppCDS](https://github.com/GoogleContainerTools/jib/issues/2471). ([#3280](https://github.com/GoogleContainerTools/jib/pull/3280))
- For Java 9+ apps, the default Java runtime classpath explicitly lists all the app dependencies, preserving the dependency loading order declared by Maven. This is done by changing the default entrypoint to use the new classpath JVM argument file (basically `java -cp @/app/jib-classpath-file`). As such, `<container><expandClasspathDependencies>` takes no effect for Java 9+. ([#3280](https://github.com/GoogleContainerTools/jib/pull/3280))
- Timestamps of file entries in a tarball built with `jib:buildTar` are set to the epoch, making the tarball reproducible. ([#3158](https://github.com/GoogleContainerTools/jib/issues/3158))

### Fixed
Expand Down
Loading