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

查看:128
本文介绍了如何为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.

这种方法的主要问题是无法将应在正在创建的Docker映像之外执行的命令添加到Dockerfile中.这意味着我必须将我的源代码和构建工具添加到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?

推荐答案

docker注册中心具有

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天全站免登陆