Skip to content

Optimize docker layers #1684

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

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open

Optimize docker layers #1684

wants to merge 16 commits into from

Conversation

dwickern
Copy link
Collaborator

@dwickern dwickern commented Feb 10, 2025

I numbered the layers 10, 20, 30, 40 instead of 1, 2, 3, 4 so that it's easier to sandwich something in between the existing layers. For example, I build multiple docker images that have some dependencies in common. This will allow me to move those dependencies into their own layer between 10 and 20, without having to re-number all the layers.

The main fix here is to make sure project artifacts are not being mixed with libraryDependencies. This was an issue with Play Framework in particular because they have some non-standard artifacts (the -assets and -sans-externalized jars). Previously we had a special case for the classpath jar but not the launcher jar. Now we consider anything that's not an external dependency to be a project artifact.

Layer 10 - jlink JRE
Layer 20 - external dependencies
Layer 30 - conf directory
Layer 40 - project artifacts

Fixes #1677

This PR builds on prior work in #1425 and #1326

@dwickern
Copy link
Collaborator Author

I used a play-scala-seed as the basis for my scripted test. It's not going to work on sbt 2.x because Play is only published for sbt 1.x.

CI calls this command:

addCommandAlias("validateDocker", "scripted docker/*")

I wonder if there's an easy way to exclude docker/test-layer-groups-playframework when running scripted from sbt 2.x

@muuki88 muuki88 added docker minor release drafter version labels Feb 24, 2025
@muuki88
Copy link
Contributor

muuki88 commented Feb 24, 2025

Awesome work already @dwickern . I'll try to find some time to review this.

I wonder if there's an easy way to exclude docker/test-layer-groups-playframework when running scripted from sbt 2.x

I don't recall any 😢 My first naive approach would be to not use play as the seed 😅
What's the exact error?

@dwickern dwickern force-pushed the optimize-docker-layers branch from 1f8864b to 7482062 Compare February 24, 2025 18:17
@dwickern dwickern force-pushed the optimize-docker-layers branch from cce68af to 8e8ca41 Compare February 24, 2025 21:26
@dwickern
Copy link
Collaborator Author

The error was trying to resolve Play's sbt plugin for sbt 2.0.0-M3, which doesn't exist

[info] Running docker/test-layer-groups-playframework
[info] [info] welcome to sbt 2.0.0-M3 (Eclipse Adoptium Java 11.0.26)
[info] [warn] sbt version mismatch, using: 2.0.0-M3, in build.properties: "1.10.7", use 'reboot' to use the new value.
[info] [info] loading project definition from /tmp/sbt_2bbbfa03/project
[info] [warn]
[info] [warn] Note: Unresolved dependencies path:
[info] [error] sbt.librarymanagement.ResolveException: Error downloading org.playframework:sbt-plugin_sbt2.0.0-M3_3:3.0.6
[info] [error] Not found
[info] [error] Not found
[info] [error] not found: https://repo1.maven.org/maven2/org/playframework/sbt-plugin_sbt2.0.0-M3_3/3.0.6/sbt-plugin_sbt2.0.0-M3_3-3.0.6.pom
[info] [error] not found: /home/runner/.ivy2/local/org.playframework/sbt-plugin_sbt2.0.0-M3_3/3.0.6/ivys/ivy.xml

I created a docker-sbt1.0 directory which will run against sbt 1.0 only:

src
├── main
├── sbt-test
│   ├── docker
│   │   ├── alias
│   │   ├── build-command
│   │   ├── build-options
│   │   ├── entrypoint
│   │   ├── ...
│   ├── docker-sbt1.0
│   │   └── test-layer-groups-playframework

validateDocker aliases to ; +scripted docker/*; ++ 2 scripted docker-sbt1.0/*.

+scripted docker/* runs against both sbt versions
++ 2 scripted docker-sbt1.0/* syntax is described here. It will run against scala 2 only and consequently sbt 1.0 only

Play support for sbt 2.x is being tracked in playframework/playframework#12898.

@dwickern dwickern force-pushed the optimize-docker-layers branch 3 times, most recently from caff5e6 to 6050b88 Compare February 24, 2025 23:20
@dwickern dwickern force-pushed the optimize-docker-layers branch from fab755c to a921e4f Compare February 24, 2025 23:59
@dwickern
Copy link
Collaborator Author

I've been banging my head against this and I think I finally know what's happening. We run scripted tests by publishing sbt-native-packager version 0.0.0-SNAPSHOT. Play Framework depends on a version of sbt-native-packager which is considered newer (any version is newer than 0.0.0-SNAPSHOT) and so the scripted test is running against a production release.

We need to fetch tags in order for sbt-dynver
to detect the version, otherwise the version
defaults to 0.0.0-SNAPSHOT.

This causes the `test-layer-groups-playframework`
scripted test to fail because Play Framework
depends on a newer version of sbt-native-packager.

See https://github.com/sbt/sbt-dynver#setup
According to the comment on the previous line
@dwickern dwickern marked this pull request as ready for review February 25, 2025 18:11
Copy link
Contributor

@muuki88 muuki88 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to merge and release @dwickern ❤️

Comment on lines +128 to +132
case (_, path) if path.startsWith(jreDir) => 10
case (file, _) if dependencies(file) => 20
case (_, path) if path.startsWith(confDir) => 30
case (_, path) if path.startsWith(libDir) => 40
case (_, path) if path.startsWith(binDir) => 40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the gist of this change, right? LGTM 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docker minor release drafter version
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Optimize Docker image layering
2 participants