三、Dockerfile自定义镜像

目录

 镜像结构

 Dockerfile语法

 构建Java项目​编辑


 我们已经学习了如何去拉取一个镜像,还有如何基于镜像去创建和运行容器,我们这些所操作的所有镜像都是由dockerhub官方制作的镜像。你想一想我们将来自己写的微服务代码,能不能让dockerhub官方帮我们制作镜像啊?显然不能,且不说人家愿不愿意帮你制作,你自己的代码你好意思共享给别人吗?你放心吗?所以我们将来自己的微服务,一定要自己制作镜像,因此我们第三章就要带大家来学习一下如何基于dockerfile来自定义镜像

 镜像结构

我们在这一章里呢,我们会通过三部分来学习,第一呢,让大家了解一下镜像的结构,因为你要制作一个镜像,你一定得先了解它内部的构成。而第二呢我们就带大家去学习dockerfile的语法,最后我们会动手将一个JAVA项目构建成一个镜像。

我们接下来就进入第一部分镜像结构的一个了解,而要想了解镜像的结构,必须得先回顾一下镜像的概念?镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成,镜像包含系统函数库,环境,配置依赖等等,这不就是镜像的组成吗?

当然了,这只是镜像的组成,我们说结构还要看这些组成怎么样去组合。这些个组成他们有没有相互的一个依赖关系或者顺序呢?显然是有的呀,如果没有最底层的系统函数库,底层的文件系统,你怎么样就完成环境的配置呢?如果没有配置环境变量,你怎么样去做依赖的安装呢?如果没有依赖的安装,你怎么去完成应用的安装?如果没有应用安装,你怎么样去做应用的配置呢?可见,镜像不仅仅是把这一堆的东西揉在一起,而且还要按照一定的顺序去翻层构建。所以下面了我们就以MySQL的镜像为例,给大家讲解一下镜像结构,这一堆融在一起大家肯定很难去理解的。

我们把MYSQL镜像给他打散,这是我模拟的一个MYSQL镜像,它不是很完整,但足以说明问题了,大家来看这里,这里就分成了n层。它就是按照我们刚才所分析的那个依赖顺序来去分层的,那我们讲要是构建一个镜像,最底层一定是他所依赖的系统函数库吧,他在这儿就是用了一个Ubuntu的操作系统。当然它不是完整啊,只是MYSQL依赖的部分系统函数库还有部分文件,那它就想整个大楼的地基一样,只有先把它搞定,我们才能继续向上,所以这次我们一般称之为Base Images(基础镜像),在此基础上,是不是可以给MYSQL配置环境变量,搞定了环境变量,我们还要去搞定他所依赖的其他东西,当然我这儿没列出来啊,因为层数有限嘛,把这些都搞定了,我是不是可以开始安装MYSQL了?那我就把MYSQL的安装包拷进来。然后在此基础上,我就开始去rpm安装MYSQL,安装完了MYSQL,我是不是还要配置MYSQL的配置文件呢?那我得配置它的配置文件等等,所有的安装步骤全部做完,这个楼就盖的差不多了,还差个什么东西呢?入口(Entrypoint)。

 你把这一堆的文件揉成一个疙瘩,打了一个包,将来别人怎么启动里面的应用?你得给他一个入口,也就是启动的脚本,所以任何的一个镜像一定有这么一层,那现在我们的镜像这样就构建完成了。

我们在这个过程中从基础开始完成了环境变量的配置,依赖的安装,应用的安装等等,这每一次操作都会产生新的一层,这个东西称之为Layer(层),这时候有同学就有疑问了,你这个先后顺序,我能理解,但依赖关系有先有后,那你为什么要给它分层,你揉成一疙瘩不行吗?还真不行,你揉成一疙瘩,装了一个5.7的镜像,然后我们的系统升级了,我要搞一个5.8的镜像。

那你不能在原来基础上就改了,因为你原来全混成一团了。那怎么办呀?你只能从零开始再构建一个吧,从这个基础开始,在这上面整环境,整配置重来一遍,麻烦不麻烦呀。但是我要分层了,那可就不一样了,我在构建5.7的时候就开始注意这事了,整完基础我给它分一层,整完环境我给它分一层,整完配置我再给它分一层,这样,我逐层构建,直到上面开始构建5.7,然后安装等等。那现在我要想构建5.8了,我发现,原来可能就是上面这几层我不想要了,我把这几层砍掉,下面这几层我是不是可以基于它继续往上构建。是不是可以提高一定的复用性,节省一些这个时间。

我们将来自己构建镜像,也应该从基础开始逐层构建,这也就是镜像的结构了

 镜像是一个分层结构,每层成为一个Layer,在任何的一个镜像结构当中一般都会有两层。Base Images(基础镜像层),也就是这个镜像所依赖的最基础的东西。

(Entrypoint)作为入口就是镜像当中应用启动的命令脚本,除非你这个镜像压根不想让人启动,这样的镜像才不需要入口。

除了Images(基础镜像层)和入口(Entrypoint)以外,剩下的部分我们就不能确定了,因为镜像构建的时候,中间到底要做哪些动作我们不知道,但是你可以知道的是每做一次操作一定会产生新的一层,就在这两个之间。

 Dockerfile语法

我们就来学习一下如何自定义镜像,那自定义镜像一定会用到dockerfile,是一个文本文件,其中包含一个个的指令(Instruction),用指令来说明要执行什么操作来构建镜像。 每一个指令都会形成一层Layer。它就可以当做是一个镜像构建的说明书,将来我们的docker会按照这里面的指令去构建好我们的镜像,每一个指令就会形成一层的Layer。这里我列出了一些dockerfield的常见指令,我们用的最多就这些了,因为我们构建Java项目嘛,没有那么复杂。

比如说第一个指令的是FROM,是指定一个基础镜像,一般是操作系统,比方说这里的  FROM centos:6  就是基于centos6就完成构建,或者你也可以基于Unbutu,16.0.4之类的也都可以。

下面ENV它是个缩写,environment,就是环境变量,环境变量一般是一个键值,一旦配好了以后,在后续的过程中,大家都可以使用这个环境变量里面配好的东西,比方说我们可以配好一个目录,那在后续使用过程中大家都可以用这个目录。

然后再往下,COPY,就是我们的复制,我们本地呢有一个JAVA的一个项目包,将来我们要拷它到镜像里面去,就可以用这个COPY里面去了。

RUN,是运行的意思,它特指是执行Liunx的shell命令,一般是安装命令,比如说我这里有一个依赖需要安装,或者解压,我后面都可以利用RUN,后面跟上shell命令就行了。

再往下就是EXPORT,它是指暴露端口,这个可不是真正暴露端口啊,大家还记得我们以前在创建容器时要加 -p 参数吧,那个才是指定宿主机和容器的映射端口,容器将来暴露谁。这里只是指定说,我监听的是什么端口,它是给那个镜像的使用者看的,就像使用者一看,原来你这里用的是8080啊,那我 - p  参数冒号后面那一部分是就必须写8080了,起这么个作用啊。-p不能少的,但这个加我不加,那么其实都可以啊,加了的话尽量使用这一看就很明白了。

再往下就是ENTRYPOINT 就是启动命令了,一个镜像一定有一个启动的脚本,一个Java项目启动脚本的非常简单,就是Java -jar xx.jar就可以了。这些就是我们dockerfile比较常见的命令了,如果大家更详细的去了解其他的一些,可以参考一下这个网站啊,这上面都有详细语法说明,请参考官网文档: https://docs.docker.com/engine/reference/builder

 构建Java项目

 

 

 

 

 

 

 -----------------------------------------------------------

DockerFIle和我们要构建镜像在同一级目录,所以这里有点。

 

 

 我们打开文档看一眼,要经过很多步,而且这么多步骤当中,其实真正是来构建JAVA项目的,就是这一行拷贝。

因为Java项目不需要安装,拷过来数就能用。我们把它放到最下的。

上面的动作其实都是在安装jdk,那大家想一想看,如果说我现在又有一个微服务需要构建了,将来咱们有成千上百的微服务。每个微服务在做构建时都要执行的完整的流程,觉得麻烦吗?是不是挺麻烦的,我们的镜像既然已经做了分层,而这里的前n层,大家看不管是这个Java项目还是再换个Java项目,前n层会不会变?那我为什么不把这前n层提前构建好?做一个镜像先放到那儿,以后我都在这个基础上再构建,是不是就方便多了?这就是分层的好处吧,实际上有人已经帮我们做的一件事儿了。

有一个名为java:8-alpine镜像,它是一个体积非常小的jdk一个镜像,那也就是说这个镜像已经帮我们把前n部分全做完了。如果说我来构建镜像时,我是以它为基础的话,同学们,前几步构建jdk这些动作是不是都可以省掉了?我是不是可以把前面全删掉?我只需要基于java:8-alpine镜像构建就行了

我们中间是不是省了超级多,那以后你再构建其他微服务都这样做。

把刚刚我们改的Dockerfile文件给覆盖一下

现在我来再一次构建

 

 到这我们镜像构建的所有案例都结束了

猜你喜欢

转载自blog.csdn.net/weixin_59496235/article/details/126807899