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

projectDependencies layer is omitted when executing a partial maven build #2697

Closed
danielwegener opened this issue Aug 12, 2020 · 8 comments
Closed

Comments

@danielwegener
Copy link

danielwegener commented Aug 12, 2020

Environment:

  • Jib version: 2.5.2
  • Build tool: Maven 3.6.3
  • OS: mac os x 10.15.2

Description of the issue:
Running Maven with a partial reactor build, e.g. ./mvnw package jib:build -pl name-service in the multimodule-example (https://github.com/GoogleContainerTools/jib/tree/master/examples/multi-module) does add the shared-library.jar to the dependencies or snapshot dependencies layer, but not to the project dependencies layer.

Expected behavior:
Reactor dependencies should not be added to the dependencies layer because every change in a reactor module would lead to the recreation of the (usually quite big) dependencies layer.

Steps to reproduce:

  1. export PROJECT_ID=<your own Google Cloud Platform project>
  2. ./mvnw install -pl !name-service
  3. ./mvnw package jib:build -pl name-service OR (if no gcp address) ./mvnw package jib:dockerBuild -pl name-service
  4. docker history gcr.io/${PROJECT_ID}/multimodule/name-service:0.1.0
  5. ./mvnw install jib:build OR (if no gcp address) ./mvnw install jib:dockerBuild
  6. docker history gcr.io/${PROJECT_ID}/multimodule/name-service:0.1.0

Log output:
For 4):

➜  multi-module git:(master) ✗ docker history gcr.io/multimodule/name-service:0.1.0 
IMAGE               CREATED             CREATED BY               SIZE                COMMENT
9612edbaf472        50 years ago        jib-maven-plugin:2.5.2   1.45kB              classes
<missing>           50 years ago        jib-maven-plugin:2.5.2   0B                  resources
<missing>           50 years ago        jib-maven-plugin:2.5.2   16MB                dependencies
<missing>           50 years ago        bazel build ...          100MB               
<missing>           50 years ago        bazel build ...          8.41MB              
<missing>           50 years ago        bazel build ...          1.93MB              
<missing>           50 years ago        bazel build ...          15.1MB              
<missing>           50 years ago        bazel build ...          1.79MB          

For 6):

➜  multi-module git:(master) ✗ docker history gcr.io/multimodule/name-service:0.1.0
IMAGE               CREATED             CREATED BY               SIZE                COMMENT
05e4a9e68ba5        50 years ago        jib-maven-plugin:2.5.2   1.45kB              classes
<missing>           50 years ago        jib-maven-plugin:2.5.2   0B                  resources
<missing>           50 years ago        jib-maven-plugin:2.5.2   2.25kB              project dependencies
<missing>           50 years ago        jib-maven-plugin:2.5.2   16MB                dependencies
<missing>           50 years ago        bazel build ...          100MB               
<missing>           50 years ago        bazel build ...          8.41MB              
<missing>           50 years ago        bazel build ...          1.93MB              
<missing>           50 years ago        bazel build ...          15.1MB              
<missing>           50 years ago        bazel build ...          1.79MB              

Additional Information:
Problem is in
com.google.cloud.tools.jib.maven.MavenProjectProperties#getProjectDependencies
which uses session.getProjects() while it should use session.getAllProjects().

@loosebazooka
Copy link
Member

loosebazooka commented Aug 12, 2020

I think this is a misuse of the reactor. Using -pl and not also -am does not actually rebuild the dependency project or even consider it. Under those conditions, the reference is resolved from Maven central or your local Maven repo and not from within the project. For all practical purposes, it is an external non-project dependency

@danielwegener
Copy link
Author

danielwegener commented Aug 12, 2020

True. Understood, I wasn't aware that artifacts from reactor-excluded dependencies are pulled from the local repo and not the other projects target directory (if available). To be honest, in our workflow we always use the clean install command, this is why I never may have recognized that difference.

I have edited the reproducer above, using the "install" phase.

The question is then if project dependencies means "dependencies in the same reactor build" or "dependencies from the same multimodule maven project". I would have expected the latter and that mvn install jib:build and mvn install -pl !name-service && mvn compile jib:build -pl name-service would produce the same result.

@chanseokoh
Copy link
Member

chanseokoh commented Aug 12, 2020

"dependencies from the same multimodule maven project"

I think this is dangerous. By mvn compile -pl module-A without -am, it purposely tells the Maven reactor to build only module-A and not consider other modules at all (i.e., same as building a single standalone Maven project). And as such, Maven doesn't look into other modules but tries to resolve dependencies from external sources, such as Maven Central or ~/.m2/repositoriy. (In other words, Jib's behavior and Maven's are aligned by not using project dependencies.) They are external dependency repositories. From my perspective, getting an artifact from an external repository and marking them as "project dependencies" is not the right thing to do. It falsely makes you believe that the artifacts came from locally building them from project source, while the reality is that they came from somewhere else external and are static, totally independent of your local project source. Just as you didn't realize that the artifact came from your local Maven repo, not knowing which version you are using or where the dependency is coming from is dangerous. The artifact in your local Maven repo will be outdated whenever you make a change to your project and until you run mvn install. The current behavior did let you discover the danger.

I think Jib should not mark artifacts retrieved from external repositories as "project dependencies."

@chanseokoh
Copy link
Member

If you have to continue using your workflow but still want a way to move such dependencies into a separate layer, see #1962 (comment)

@loosebazooka
Copy link
Member

loosebazooka commented Aug 12, 2020

So @danielwegener generally maven isn't great at the multimodule workflows for non lifecycle goals. This is something we, as the jib team, have had to grapple with.

./mvnw package jib:build -pl module-A -am

will try to trigger jib:build on module-A and all of module-A's project dependencies (which we don't necessarily want).

There are two options.

  1. explicitly configure the jib plugin with <skip>true</skip> on all non-jib projects, which seems like a common pattern in maven multimodule builds.

  2. Bind jib:build to the package lifecycle phase on module-A and use

    ./mvnw package -pl module-A -am
    

    This runs regular package on the dependency modules, and additionally run's jib:build on module-A

both of which are not super ideal, but it is the consequence of maven's build structure.

The question is then if project dependencies means "dependencies in the same reactor build" or "dependencies from the same multimodule maven project"

To this point, you are right, there is some value is clearing this up. Technically we mean "reactor".

@danielwegener
Copy link
Author

danielwegener commented Aug 13, 2020

If you have to continue using your workflow but still want a way to move such dependencies into a separate layer, see #1962 (comment)

Yes, I've tried the layer-filter-extension even before I knew the project dependencies layer would exist, but do not have a good glob to match all my internal dependencies (without repeating them, also having another layer "ontop" of classes and additional files felt a bit unclean).

I think this is dangerous...

I do not see that this is adding any new danger by considering "potentially not just yet built"-dependencies beeing project dependencies. Other packing plugins like the maven-war-plugin or the assembly plugin AFAIK would also do not make a big difference if a multimodule-dependency was built "just in this reactor run" or from earlier seperate builds. The resulting artifact would in most cases be the same.

For me as a user the practical purpose of the project dependencies layer would be that it is small and can change frequently while the dependencies layer would not have to be touched that often. I would not expect any guarantee that anything within project dependencies was "built by me". Just that it behaves consistently across different invocations of the reactor (like other plugins that seem to pick either from the reactor projects artifacts or the local repository silently - and not really making this distinction).

Said that, thanks for the comprehensive replies, I understand your points and I guess I can get what I want with a small jib-extension that post-processes the ContainerBuildPlan.

@danielwegener
Copy link
Author

I think the same happens when you --resume-from an aborted multi-module build (every module skipped is not added to the project-dependencies layer). Is this also an desired behaviour?

@chanseokoh
Copy link
Member

chanseokoh commented Sep 28, 2020

I don't know much about --resume-from, but based on what you said, I'll assume here that it can end up not building some of the sub-modules.

@danielwegener I'd say the behavior isn't "desired" but an unfortunate limitation due to Maven. Unlike Gradle, Maven doesn't have a way to trigger running other plugins or some build phases from a plugin. Even for a single-module project, Jib explicitly requires the user to first run mvn compile (or mvn package for the <containerizingMode>packaged mode) so that all the binaries and resources are fully prepared and generated in the output directory. In the same vein, for a multi-module project, the user must first do mvn package (often with -pl and --also-make) to have all the project output in each target/ directories of the sub-modules. It is the user's responsibility to build each sub-module first; we are not aware of any way to auto-trigger building dependency projects in Maven.

Adding @loosebazooka in case he has other things to say.

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

Successfully merging a pull request may close this issue.

3 participants