一.自定义镜像
我们从docker网站上能够下载到很多镜像,但是让我们自己的Java项目想要制作成镜像,并让别人下载使用时,我们该怎样制作镜像呢?这就用到自定义镜像了。
镜像中主要包括程序运行所需要的系统函数库,应用程序,运行配置文件等文件包。而构建镜像的过程就是把上述文件打包的过程。
那Java应用在运行时需要哪些东西,找到这些打成包就行了。
在思考这些问题前,我们首先想想部署Java镜像的步骤:

JRE和JVM是和操作系统密切相关的,不同的操作系统所匹配的JVM是不一样的,因此我们在部署一个java应用的时候,不仅要Jar包和JRE,而且还需要操作系统(Linux服务器)。这样这个Java应用不依赖于所部署的操作系统。如该JRE基于Ubuntu系统,但是服务器是Linux系统的,这样可以将Ubuntu系统JRE所需要的函数库集成起来。
但是我们并不知道Ubuntu系统JRE所需要的函数库有哪些,因此我们可以采用一种笨办法。直接把整个Ubuntu的运行环境都搬过来。

镜像的构建和部署一个Java应用的步骤是一样的,这样我们就可以构建一个Java镜像。到时候直接执行脚本就行了。这个镜像就达到了直接运行的目的。
1.首先我们要准备Linux运行环境所需要的系统函数库。

2.准备JRE及环境变量和配置

3.准备Jar包

4.编写运行脚本

完成了这四步就构建了一个Java镜像

二.层
这当中的每一步都会产生很多文件,而docker在构建时不会将每一步产生的文件合并在一起打成一个包发出去,而是会把每一步操作产生的文件分别打成包,作为镜像的一部分,最终合在一起是一个完整的镜像。也就是说docker镜像是由很多压缩包合并成的。这些压缩包称为层。
那么docker为什么要分层呢?有以下好处:
增强解耦,如果后面我们知道了jre运行时具体依赖哪些系统函数库,我们就可以构建一个新的系统函数库镜像,这就能缩小镜像体积。如果我们不解耦而将所有镜像耦合在一起。那么下次再制作镜像时,上次构建的新镜像就无法使用了。而解耦后就可以避免这一点。下次再制作镜像时,可以使用原来制作好的镜像。
这种使用频率高,在构建镜像时作为基础的,称为基础镜像。可以共享,下载的时候有了不用下载,速度快。本地存储量减小。
我们可以在下载镜像时观察到这一点。

证明基础镜像已存在。
同理,最顶层的叫做入口,即启动脚本。

三.Dockerfile
上述分层虽然逻辑清晰,但是操作麻烦,我们不仅要找到镜像,还要压缩打包。好在docker为我们做好了,我们只需要描述清楚入口,基础,中间层。docker就能帮我们完成镜像构建。这就用到Dockerfile。

1.FROM:指定基础镜像,这些基础镜像在docker中基本上都是做好现成的。
2.ENTRYPOINT:入口,启动脚本java -jar。
3.ENV:配置环境变量。
4.COPY:要制作镜像,要将jar包和jre拷贝到镜像中的指定目录。不存在会自动创建。
5.RUN:文件拷贝进去要进行解压缩,并配置环境变量。执行shell命令。
6.EXPOSE:端口暴露,比如java应用监听8080,就可以写8080。但是不是将来使用镜像的人就可以通过8080访问,仍要通过端口映射才行。
但是这些指令,很多我们用不到,而且可以通过镜像实现。我们来看案例:
左边是我们通过一系列指令来实现的。其中FROM,ENV,COPY jdk,RUN都是来配置JDK镜像的,那么既然ubuntu镜像都有人做,JDK镜像怎么会没人做呢?右边就是我们用来配置JDK的镜像,这些镜像包含了左边的一系列操作。我们只需要执行COPY jar包和设置入口即可。