首页 > 解决方案 > 如何优化多个相关 maven java 项目的 docker 构建?(缓存)

问题描述

我管理一个大型专有系统,该系统损害了 Java 中的十几个服务。我们有一组核心 Java 库,它们都共享),所有组件/应用程序都是使用 maven 构建的。尽管每个应用程序都有自己独特的依赖项集,但在核心 SDK jar 之外。我无法弄清楚在 docker 内部构建和部署的最佳方法是什么。理想情况下,我希望使用多阶段构建方法在 docker 中实现整个生命周期。但是,我看不到如何使用大量依赖项来优化它。

看起来我可以做两种方法。

  1. 像我们以前一样构建,使用 maven 和 CI 服务器 (jenkins) 上的公共缓存,以便一次性获取并缓存依赖项,并可供所有应用程序访问。然后为每个应用程序创建一个 dockerfile,将产品 jar 及其依赖项(或 fat jar)复制到容器中,并将其设置为执行。这种方法的缺点是构建本身在开发人员和 CI 服务器之间可能会有所不同。可能使用像 nexus 这样的本地 maven 缓存,只是为了避免每次都从 Internet 中提取 deps?但这仍然不能解决开发构建不一定匹配 CI 构建环境的问题。

  2. 为每个项目使用多阶段 dockerfile。我已经尝试过了,它确实有效,并且我设法让 Maven 依赖层缓存起来,这样它就不会经常获取。不幸的是,每个应用程序的中间构建层达到了 1-2gb,我无法从守护进程中删除“悬空”中间体,或者所有缓存都被吹走。这也意味着如果 pom 中的某些内容发生变化,则必须为每个应用程序下载 jar 中的大量重复项。(即它们都使用 junit 和 log4j 以及许多其他相似之处)

有没有办法以最佳方式解决我没有看到的问题?我发现的所有博客基本上都集中在上面的 2 种方法上(其中一些专注于在容器中运行 maven 本身,这对我来说真的没有解决任何问题)。如果没有其他好的解决方案,我可能最终需要选择选项 1。

我已经检查了 stackoverflow 和博客,我能找到的所有内容似乎都假设您实际上只是在构建一个应用程序而不是它们的套件,因此不重复依赖项下载变得很重要。

标签: javamavendocker

解决方案


我认为只要--update-snapshots在 maven 构建中设置选项,就可以使用 .m2/repository 文件系统缓存。它可以更好地扩展,因为每个构建环境只缓存每个 .jar 一次,而不是每个应用程序一次。此外,单个依赖项的更改不会使整个缓存失效,如果您使用 docker-layer-caching 就会出现这种情况。

不幸的是,目前这不能与多阶段构建很好地结合起来,但你并不是唯一一个需要它的人。 此问题--volume要求向docker build 命令添加一个选项。这个要求在 Dockerfile: 中允许这样的指令RUN --mount=m2repo=/var/mvn/repo mvn install

这两个功能都允许您在多阶段构建期间使用本地 maven 文件系统缓存。

目前,我建议您保留选项 1 作为解决方案,除非您面临许多由于构建环境不同而导致的问题。


推荐阅读