如何为Java应用程序

时间:2015-07-29 09:28:27

标签: java maven gradle docker dockerfile

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

问题

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

有三种方法:

让构建工具控制进程

在这种情况下,我的构建工具控制整个过程。因此它准备了JAR文件,在创建JAR之后,它调用Docker来创建映像。这是因为事先创建了JAR,Docker可能忘记了创建JAR所需的构建过程。

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

让Docker控制构建

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

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

编辑:

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

两个独立的构建

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

结论

在我看来,更好的方法是让构建工具控制进程。这将产生干净的泊坞窗图像,因为图像是我们想要提供的,这是非常重要的。为避免可能无法正常工作的Dockerfile,应将其作为构建的一部分创建。因此,没有人会不小心使用它来开始破坏构建。

但这不允许我与DockerHub集成。

问题

我还有另一种方法吗?

8 个答案:

答案 0 :(得分:28)

docker注册表中心有一个Maven image,可用于创建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

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:

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现在具有multi-stage build功能。这使得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"]

答案 1 :(得分:7)

  

java应用程序的结构

Demo
└── src
|    ├── main
|    │   ├── java
|    │   │   └── org
|    │   │       └── demo
|    │   │           └── App.java
|    │   └── resources
|    │       └── application.properties
|    └── test
|         └── java
|               └── org
|                   └── demo
|                         └── App.java  
├──── Dockerfile
├──── pom.xml
  

Dockerfile的内容

FROM java:8
EXPOSE 8080
ADD /target/demo.jar demo.jar
ENTRYPOINT ["java","-jar","demo.jar"]
  

构建和运行图片的命令

     
      
  • 转到项目目录。让我们说D:/ Demo
  •   
$ cd D/demo
$ mvn clean install
$ docker build demo .
$ docker run -p 8080:8080 -t demo
  

检查容器是否正在运行

$ docker ps
  

输出

CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                    NAMES
55c11a464f5a        demo1               "java -jar demo.jar"   21 seconds ago      Up About a minute   0.0.0.0:8080->8080/tcp   cranky_mayer

答案 2 :(得分:3)

最简单的方法是让构建工具控制流程。否则,您将必须维护构建工具的构建文件(例如Maven的pom.xml或Gradle的build.gradle)以及Dockerfile

为Java应用程序构建Docker容器的简单方法是使用JibMavenGradle插件。

例如,如果您正在使用Maven并希望将容器构建到正在运行的Docker守护程序,则只需运行以下命令即可:

mvn compile com.google.cloud.tools:jib-maven-plugin:0.9.2:dockerBuild

您也可以使用Jib build directly to a Docker registry,而无需安装docker ,运行Docker守护程序(需要root特权)或编写Dockerfile。它也更快,并且可重复生成图像。

在Github仓库中查看有关Jib的更多信息:https://github.com/GoogleContainerTools/jib

答案 3 :(得分:1)

有几件事:

  • 如果您删除添加它们的同一指令中的文件,它们将不会消耗图像中的空间。如果您查看官方图像的某些Dockerfiles,您将看到他们下载源代码,构建它并在同一步骤中删除它们(例如https://github.com/docker-library/python/blob/0fa3202789648132971160f686f5a37595108f44/3.5/slim/Dockerfile)。这意味着你需要做一些讨厌的体操,但这是完全可行的。

  • 我没有看到两个独立的Dockerfiles的问题。关于这一点的好处是你可以使用JRE而不是JDK来托管你的jar。

答案 4 :(得分:1)

我们暂时使用了Spotify Docker Maven Plugin。该插件允许您将Docker绑定到Maven生命周期的一个阶段。

一个例子: 通过配置插件将构建的应用程序作为资源添加到Docker构建上下文,在打包(阶段:包)应用程序之后运行Docker构建。在部署阶段,运行Docker推送目标,将Docker镜像推送到注册表。这可以在普通部署插件旁边运行,该插件将工件发布到像Nexus这样的存储库中。

稍后,我们将构建分解为CI服务器上的两个单独的作业。由于Docker只是运行应用程序的一种方式(有时我们需要在不同环境中发布的应用程序而不仅仅是Docker),因此Maven构建不应该依赖Docker。

因此,第一份工作在Nexus中发布了应用程序(通过Maven部署)。第二个作业(可以是第一个作业的下游依赖项)下载最新的发布工件,执行Docker构建并将映像推送到注册表。要下载最新版本,我们使用Versions Maven Plugin(版本:use-latest-releases)以及Maven Dependency Plugin(依赖:get和dependency:copy)。

还可以针对特定版本的应用程序启动第二个作业,以(重新)为旧版本构建Docker镜像。此外,您可以使用构建管道(在Jenkins上),它执行两个作业并将发布版本或发布工件传递给Docker构建。

答案 5 :(得分:0)

有运行jar或war包的替代用法

  • 将jar添加到图像中。
  • 为java设置heapsize
  • 通过入口点运行jar命令

示例dockerfile

FROM base
ADD sample.jar renamed.jar
ENV HEAP_SIZE 256m
ENTRYPOINT exec java -Xms$HEAP_SIZE -Xmx$HEAP_SIZE -jar renamed.jar

另外在tomcat上的包部署示例

FROM tomcat7
ADD sample.war ${CATALINA_HOME}/webapps/ROOT.war
CMD ${CATALINA_HOME}/bin/catalina.sh run

将dockerfiles构建为图像

cp tomcat.dockerfile /workingdir/Dockerfile
docker build -t name /workingdir/Dockerfile .

列出图片

docker images

使用image创建容器

docker run --name cont_name --extra-vars var1=val1 var2=val2 imagename

答案 6 :(得分:0)

Here我描述了我在开发环境中的表现。

  • 使用Maven在本地构建war / jar
  • 将其复制到本地Docker文件夹
  • 运行Intellij Docker plugin,创建包含war / jar的docker镜像,运行应用程序服务器并将其部署在远程Docker服务器上

希望它有所帮助。

答案 7 :(得分:0)

使用Jib工具包含Java应用程序而无需编写dockerfile

Jib 是Google维护的开源Java工具,用于构建Java应用程序的Docker映像。它简化了容器化,因为有了它,我们不需要编写dockerfile 。实际上,我们甚至不必安装docker 即可自行创建和发布docker镜像。

Google将Jib发布为Maven和Gradle插件。 https://github.com/GoogleContainerTools/jib

  

使用Maven项目对Java应用程序进行容器化

     

https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin#quickstart

     

使用Gradle项目对Java应用程序进行容器化

     

https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin#quickstart