本文转载请联系网管谢bi公众号。如何将Java应用程序打包成Docker镜像?对于熟悉Docker的同学来说,这应该是一个很简单的问题。将项目打包成JAR包,然后在Dockerfile中使用ADD命令将JAR文件放入镜像中,启动命令设置并执行这个JAR文件。例如,使用Maven构建的Spring应用可以使用如下Dockerfile构建镜像。FROMopenjdk:8-jreADDtarget/*.jar/application.jarENTRYPOINT["java","-jar","/application.jar"]上面的Dockerfile很好理解。Maven构建的Java项目的目录结构为project│pom.xml└────src//源文件目录││└────main││└────java└└────target//class目录和jar文件会用mvncleanpackage打包在目标目录下生成JAR文件,通过java-jar命令执行编译好的程序。因此,在上面的Dockerfile中,执行了将目标目录下的JAR添加到Docker镜像中和设置jar-jar/application.jar为容器的启动命令这两个步骤。不过,除了这种最原始的方法,我们还可以使用一些Maven插件,或者Docker的多阶段打包功能,来完成将Java应用程序打包成Docker镜像的动作。Maven插件构建镜像spotify的dockerfile-maven-plugin和Google的jib-maven-plugin是两个比较知名的插件。下面简单介绍一下dockerfile-maven-plugin的配置和使用。其实使用方法很简单。我们在POM文件中引入这个插件,结合上面的Dockerfile,让插件帮我们完成应用镜像的打包。com.examplehello-spring0.0.1-SNAPSHOThelloworldcom.spotifydockerfile-maven-plugin1.4.10defaultbuild推送${docker.registry.url}/${image.prefix}/${artifactId}${project.version}${project.build.finalName}.jar中使用的dockerplugin.registry.url和image.prefix是我为Docker的镜像仓库单独设置的属性。1.8kevinyan001可以在这里设置随意私有仓库的远程地址和镜像前缀,比如在阿里云的镜像服务上创建一个名为docker-demo的空间,上面的属性需要这样配置:1.8docker-demoregistry.cn-beijing.aliyuncs.com配置插件后在POM文件当我们打包应用程序并执行mvccleanpackage操作时,dockerfile-maven-plugin会根据我们的配置自动打包一个名为kevinyan001/hello-spring:0.0.1-SNAPSHOT的Docker镜像。dockerfile-maven-plugin不仅可以帮我们打包应用镜像,还可以让它帮我们推送镜像到远程仓库,不过我觉得用处不大。有兴趣的同学可以上网搜索一下这部分功能如何配置。使用Docker的多阶段构建打包镜像上面介绍了使用Maven插件帮助我们打包Java应用的镜像。其实我们也可以把mvncleanpackage这个步骤交给Docker。当然,如果把Java应用的源代码放在Docker镜像中,编译打包,发布,肯定是有问题的。我们知道,在Dockerfile中,ADD和RUN每条指令都是在单独的一层执行的。指令越多,创建的图像就越多。更大,包括Java项目的源代码也是一种风险。不过好在Docker后来支持了多阶段构建,允许我们在一个Dockerfile中定义多个构建阶段,先拉起一个容器完成构建以供使用,比如我们可以在这个阶段完成JAR的打包,以及那么第二阶段第一阶段复用一个jre镜像,将上一阶段打包的JAR文件复制到新镜像中。》这在Go语言中有一个优势,可以将第一阶段编译好的二进制可执行文件直接复制到一个基本的linux镜像中,让Go应用程序在容器中运行。对于Go应用程序的多阶段打包,可以查看我上一篇文章中的在线Go项目的Docker镜像是如何构建的?了解一下。使用下面的Dockerfile通过多阶段构建完成Java应用的Docker镜像打包。#Dockerfile也可以不放在项目目录下,并通过-f指定Dockerfile的位置,例如执行如下命令dockerbuild-t-f.FROMkevinyan001/aliyun-mvn:0.0.1ASMAVEN_BUILDCOPYpom.xml/build/COPYsrc/build项目根目录下/srcWORKDIR/build/#mountanonymoushostdirectoryas.m2storageforcontianerVOLUME/root/.m2RUNmvncleanpackage-Dmaven.test.skip=true--quietFROMopenjdk:8-jreCOPY--from=MAVEN_BUILD/build/target/*.jar/app/application.jarENTRYPOINT["java","-jar","/app/application.jar"]我们上面使用的Dockerfiles不需要放在项目的根目录下。现在支持通过-f指定Dockerfile的位置。例如在项目根目录下执行如下命令完成镜像的打包。dockerbuild-tkevinyan001/hello-spring:0.0.1-f。上面第一个镜像是自己做的,因为Maven官方镜像的远程仓库比较慢,所以只能自己打包,去阿里云的镜像源。试了之后速度并不快,主要是任何一个Spring项目的依赖太多。如果大家有什么加快Docker构建速度的方法,可以留言一起讨论。不可否认,多阶段构建产生的Go镜像基本都在10M左右,而Spring应用却可以轻松达到数百兆。这对容器的构建速度和网络传输的成本都有影响。那么Spring应用的形象如何呢?至于减肥,这将在以后的文章中讨论。