如何为Java应用程序构建Docker容器

如何解决如何为Java应用程序构建Docker容器

Docker注册表中心具有一个Maven映像,可用于创建Java容器。

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

├── 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

Docker文件

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

更新资料

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

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 .

__

更新(2017-07-27)

Docker现在具有多阶段构建功能。这使Docker可以构建包含构建工具但仅包含运行时依赖项的映像。

以下示例演示了此概念,请注意如何从第一个构建阶段的目标目录复制jar

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映像,但是以下注意事项对于大多数编译语言都应适用。

问题

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

有三种方法可以做到这一点:

让构建工具控制过程

在这种情况下,我的构建工具将控制整个过程。因此,它准备了JAR文件,并在创建JAR之后调用Docker创建映像。这是在预先创建JAR时起作用的,并且Docker可以忽略创建JAR所需的构建过程。

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

让Docker控制构建

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

这种方法的主要问题是无法将应在正在创建的Docker映像之外执行的命令添加到Dockerfile中。这意味着我必须将我的源代码和构建工具添加到Docker映像中,并在该映像中构建我的JAR文件。由于所有添加的文件在运行时都不需要,因此这将导致我的映像大于必须的映像。这还将为我的图像添加额外的图层。

编辑:

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

两个独立的版本

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

结论

我认为更好的方法是 让构建工具控制该过程
。这将产生一个干净的docker映像,并且因为该映像是我们想要提供的,所以这很重要。为了避免可能无法正常工作的Dockerfile被创建,应将其作为构建的一部分。因此,没有人会意外地使用它来启动损坏的版本。

但这不允许我与DockerHub集成。

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?