如何为 Java 应用程序构建 docker 容器 [英] How to build a docker container for a Java application

查看:44
本文介绍了如何为 Java 应用程序构建 docker 容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做的是为我的 Java 应用程序构建一个 docker 镜像,但以下注意事项对于大多数编译语言应该是正确的.

在我的构建服务器上,我想为我的应用程序生成一个 docker 镜像作为可交付成果.为此,我必须使用一些构建工具(通常是 Gradle、Maven 或 Ant)编译应用程序,然后将创建的 JAR 文件添加到 docker 镜像.因为我希望 docker 镜像只执行 JAR 文件,所以我当然会从一个已经安装了 Java 的基础镜像开始.

On my build server I want to produce a docker image for my application as the deliverable. For this I have to compile the application using some build tool (typically Gradle, Maven or Ant) and then add the created JAR file to the docker image. As I want the docker image to just execute the JAR file I will of course start from a base image with Java already installed.

在这种情况下,我的构建工具控制了整个过程.因此它准备 JAR 文件,并在创建 JAR 后调用 Docker 来创建映像.这是因为 JAR 是预先创建的,而 Docker 可能会忽略创建 JAR 所需的构建过程.

In this case my build tool controls the whole process. So it prepares the JAR file and after the JAR is created it calls Docker to create the image. This works as the JAR is created beforehand and Docker can be oblivious of the build process needed to create the JAR.

但我的 Dockerfile 不再是独立的.它的工作取决于在 Docker 之外发生的步骤.在我的 Dockerfile 中,我将有一个 COPYADD 语句,用于将 JAR 文件复制到映像.如果未事先创建 jar,此语句将失败.因此,仅执行 Dockerfile 可能不起作用.如果您想与仅使用现有 Dockerfile 构建的服务(如 DockerHub 上的自动构建功能)集成,这将成为一个问题.

But my Dockerfile is no longer standalone. It depends on steps to happen outside of Docker for it work. In my Dockerfile I will have a COPY or ADD statement that is supposed to copy the JAR file to the image. This statement will fail when the jar is not created beforehand. So just executing the Dockerfile might not work. This becomes a problem if you want to integrate with services that just build using the present Dockerfile like the auto-build feature on DockerHub.

在这种情况下,创建映像的所有必要步骤都添加到 Dockerfile 中,因此只需执行 Docker 构建即可创建映像.

In this case all necessary steps to create the image are added to the Dockerfile so the image can be created by just executing the Docker build.

这种方法的主要问题是无法向 Dockerfile 添加应该在创建的 docker 镜像之外执行的命令.这意味着我必须将我的源代码和我的构建工具添加到 docker 镜像并在镜像中构建我的 JAR 文件.这将导致我的图像比它必须的大,因为添加了所有在运行时不必要的文件.这也会为我的图像添加额外的图层.

The main problem with this approach is that there is no way to add to a Dockerfile commands that should be executed outside the docker image being created. This means I have to add my source code and my build tools to the docker image and build my JAR file inside the image. This will result in my image being bigger than it has to be due to all the files added that will be unnecessary at runtime. This will also add extra layers to my image.

正如@adrian-mouat 指出的那样,如果我在一个 RUN 语句中添加源、构建应用程序并删除源,我可以避免向 Docker 映像添加不必要的文件和层.这意味着创建一些疯狂的连锁命令.

As @adrian-mouat pointed out if I would add the sources, build the application and deleted the sources in one RUN statement I could avoid adding unnecessary files and layers to the Docker image. This would mean creating some insane chained command.

在这种情况下,我们将构建分为两部分:首先,我们使用构建工具创建 JAR 文件并将其上传到存储库(Maven 或 Ivy 存储库).然后我们触发一个单独的 Docker 构建,它只是从存储库中添加 JAR 文件.

In this case we split our build in two: first we create the JAR file using our build tool and upload it to a repository (Maven or Ivy repository). We then trigger a separate Docker build that just adds the JAR file from the repository.

在我看来,更好的方法是让构建工具控制过程.这将产生一个干净的 docker 镜像,因为镜像是我们想要交付的,所以这很重要.为了避免可能无法正常工作的 Dockerfile,应该在构建过程中创建它.所以没有人会不小心使用它来启动一个损坏的构建.

In my opinion the better way would be letting the build tool control the process. This is will result in a clean docker image and as the image is what we want to deliver this is of importance. To avoid having a potentially not working Dockerfile lying around this should be created as part of the build. So no one would accidentally use it to start a broken build.

但这不允许我与 DockerHub 集成.

But this will not allow me to integrate with DockerHub.

还有其他我想念的方式吗?

Is there another way I am missing?

自从我第一次创建这个问题以来的几年里,很多东西都发生了变化.在这一点上,我提倡使用 Googel 的 JIB 工具.它与最常见的 Java 构建工具(Maven 和 Gradle)集成,并允许您直接从构建中创建容器.这比我多年前考虑的任何旧方法都要简洁得多.

In the years since I first created this question a lot of stuff has changed. At this point I would advocate using Googel's JIB Tool. It integrates with the most common Java Build Tools (Maven and Gradle) and allows you to create container directly from your build. This is much more concise than any of the old approaches I considered all these years ago.

我发现 James Ward 的这篇博文和视频更好地反映了当前最先进的技术.https://cloud.google.com/blog/topics/developers-practitioners/comparing-containerization-methods-buildpacks-jib-and-dockerfile

I found this blog post and video from James Ward that reflects better what is currently state of the art. https://cloud.google.com/blog/topics/developers-practitioners/comparing-containerization-methods-buildpacks-jib-and-dockerfile

推荐答案

docker 注册中心有一个 Maven 镜像,可用于创建 Java 容器.

The docker registry hub has a Maven image that can be used to create java containers.

使用这种方法,构建机器不需要预先安装 Java 或 Maven,Docker 控制整个构建过程.

Using this approach the build machine does not need to have either Java or Maven pre-installed, Docker controls the entire build process.

├── Dockerfile
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── org
    │   │       └── demo
    │   │           └── App.java
    │   └── resources
    │       └── log4j.properties
    └── test
        └── java
            └── org
                └── demo
                    └── AppTest.java

图像构建如下:

docker build -t my-maven .

并运行如下:

$ docker run -it --rm my-maven
0    [main] INFO  org.demo.App  - hello world

Dockerfile

FROM maven:3.3-jdk-8-onbuild
CMD ["java","-jar","/usr/src/app/target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]

<小时>

更新

如果您想优化图像以排除源,您可以创建一个仅包含构建的 jar 的 Dockerfile:


Update

If you wanted to optimize your image to exclude the source you could create a Dockerfile that only includes the built jar:

FROM java:8
ADD target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar /opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar
CMD ["java","-jar","/opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]

并分两步构建镜像:

docker run -it --rm -w /opt/maven 
   -v $PWD:/opt/maven 
   -v $HOME/.m2:/root/.m2 
   maven:3.3-jdk-8 
   mvn clean install

docker build -t my-app .

__

Docker 现在具有多阶段构建能力.这使 Docker 能够构建包含构建工具但仅包含运行时依赖项的映像.

Docker now has a multi-stage build capability. This enables Docker to build an image containing the build tools but only the runtime dependencies.

下面的例子演示了这个概念,注意jar是如何从第一个构建阶段的目标目录复制的

The following example demonstrates this concept, note how the jar is copied from target directory of the first build phase

FROM maven:3.3-jdk-8-onbuild 

FROM java:8
COPY --from=0 /usr/src/app/target/demo-1.0-SNAPSHOT.jar /opt/demo.jar
CMD ["java","-jar","/opt/demo.jar"]

这篇关于如何为 Java 应用程序构建 docker 容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆