如何为 Java 应用程序构建 Docker 容器问题有三种方法可以做到这一点:结论问题2020年6月更新2021年2月更新例更新
我想做的是为我的Java应用程序构建一个docker映像,但对于大多数编译语言来说,以下注意事项应该是正确的。
问题
在我的构建服务器上,我想为我的应用程序生成一个 docker 映像作为可交付结果。为此,我必须使用一些构建工具(通常是Gradle,Maven或Ant)编译应用程序,然后将创建的JAR文件添加到docker映像中。由于我希望 docker 映像只执行 JAR 文件,我当然会从已安装 Java 的基础映像开始。
有三种方法可以做到这一点:
让构建工具控制过程
在这种情况下,我的构建工具控制整个过程。因此,它准备JAR文件,并在创建JAR后调用Docker来创建映像。这之所以有效,是因为 JAR 是事先创建的,而 Docker 可能会忘记创建 JAR 所需的构建过程。
但是我的 Dockerfile 不再是独立的。这取决于Docker之外发生的步骤才能正常工作。在我的 Dockerfile 中,我将有一个 or 语句,它应该将 JAR 文件复制到映像中。如果未事先创建 jar,则此语句将失败。因此,仅执行 Dockerfile 可能不起作用。如果您想与仅使用当前Dockerfile构建的服务(如DockerHub上的自动构建功能)集成,这将成为一个问题。COPY
ADD
让 Docker 控制构建
在这种情况下,创建映像的所有必要步骤都将添加到 Dockerfile 中,以便只需执行 Docker 构建即可创建映像。
这种方法的主要问题是,没有办法向 Dockerfile 添加应该在正在创建的 docker 映像之外执行的命令。这意味着我必须将源代码和构建工具添加到 docker 映像中,并在映像内生成 JAR 文件。这将导致我的映像大于它必须的大小,因为添加的所有文件在运行时都是不必要的。这也将为我的图像添加额外的图层。
编辑:
正如@adrian-mouat所指出的那样,如果我在一个RUN语句中添加源代码,构建应用程序并删除源代码,我可以避免向Docker映像添加不必要的文件和层。这将意味着创建一些疯狂的链接命令。
两个独立的构建
在这种情况下,我们将构建一分为二:首先,我们使用构建工具创建JAR文件,然后将其上传到存储库(Maven或Ivy存储库)。然后,我们触发一个单独的 Docker 构建,该构建仅从存储库中添加 JAR 文件。
结论
在我看来,更好的方法是让构建工具控制该过程。这将产生一个干净的 docker 映像,并且由于映像是我们想要交付的,因此这一点很重要。为了避免周围有一个可能不工作的Dockerfile,应该将其创建为构建的一部分。因此,没有人会意外地使用它来启动损坏的构建。
但这不允许我与DockerHub集成。
问题
我还有别的缺失方式吗?
2020年6月更新
自从我第一次创建这个问题以来的几年里,很多东西都发生了变化。在这一点上,我主张使用Googel的JIB工具。它与最常见的Java构建工具(Maven和Gradle)集成,并允许您直接从构建中创建容器。这比我多年前考虑过的任何旧方法都要简洁得多。
2021年2月更新
我发现詹姆斯·沃德(James Ward)的这篇博客文章和视频更好地反映了目前最先进的技术。https://cloud.google.com/blog/topics/developers-practitioners/comparing-containerization-methods-buildpacks-jib-and-dockerfile