容器技术基础(四)——Dockerfile|学习笔记

开发者学堂课程【现代应用容器技术快速入门:容器技术基础(四)——Dockerfile】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/830

容器技术基础(四)——Dockerfile

------马永亮


目录

一、镜像的相关操作

二、Dockerfile的文件格式

三、Docker支持的instructions

四、容器运行时

 

一、镜像的相关操作

其实Docker就是一个简单的文本文件,只不过它遵循特定的语法格式,能够告诉我们Docker有一个特定的命令叫docker image build,或者直接使用docker build去将对应的文件,基于指定的基础镜像,或者从零开始去打包出一个符合docker容器使用规范的,甚至是符合镜像规范的镜像文件。事实上,在docker的使用环境当中啊,生成docker镜像的途径不只是Docker feel一种,一般有两种方式来制作镜像,最为简单的一种方式就是基于容器来制作。

●镜像的生成途径

 ◆Dockerfile

 ◆基于容器制作

容器技术基础(四)——Dockerfile|学习笔记

事实上,在Docker的使用环境当中,生成docker镜像的途径不只是Docker一种,一般有两种方式来制作镜像,最为简单的一种方式就是基于容器来制作。正常情况启动于容器的时候,就是在指定的那个镜像的分层堆栈的最上层附加一个刻写层,二号就归该容器使用。基于所谓的写实复制原则来完成对应文件的变更。因此容器的进程运行过程当中,如果在该读写层上生成了任何文件,这个时候可以理解为这就生成一个新的镜像层。随后基于该层次的变更,保存为直接让这个层次上生成内容基于底层镜像的内容的叠加生成为一个新的镜像是没有任何问题的。所以第一种方式,可以基于容器内部运行以后生。这就是一个提供了制作镜像的最简单的方法。简单来说,就是可以启动一个类似于具有交混基础且满足所需条件的基础文件和运行环境的这么一个景象。在该基础之上,打开它的交互的接口,补充一些文件进来,或者修改修改配置文件,再重新打包成镜像文件即可。而这种镜像的打包,就使用docker container commit命令就能够完成。其中有个命令叫做doctor tan turn or commit,这个commit就是create new image from a containers changes就是基于该容器的或者指定的容器的科学层当中的变更来生成新镜像的,当然为了避免镜像的身材过于臃肿,可以在生成镜像过程当中将生成的这些临时文件、中间文件和不需要的文件一定要消除掉,否则的话,镜像将会携带有大量这种临时的或者不重要的文件。显然对于镜像分发和对用户的这个本地的存储空间的占用都无疑是一种资源浪费。

第二种方式就是dockerfile,为用户提供了一种专门制定docker镜像的一种规范的方法,而且是一种易于分发,让别人复现的方法,它其实就是一个文本文件,就是一个文成文本的文件,只不过这个文件适用于告诉另外一个命令,叫做Docker image build这个命令。来基于该文件中所指示的一步步的步骤,通过添加文件、删除文件、运行命令等各类操作补充完整以后生成的那个所谓的科学层来生成镜像的。所以,从某种意义上来讲Docker fell有点类似于先去指定一个基础形象,所以他也完全类似于是先基于指定的镜像先启动一个容器来。这个容器也会有一个所谓的容器同时也会有一个所谓的中间层或(可写层),随后所有的指令所施加的操作都保存在这个容器的可写层当中,在最后把这个可写层给他保存下来,所以他完全类似于docker commit(Docker container commit)的类似操作,只不过Docker file当中所指定的所有操作,包括要运行命令,都只能基于基础镜像来完成。

容器技术基础(四)——Dockerfile|学习笔记

所以两种方法并没有实质上的区别。

二、Docker file的文件格式

容器技术基础(四)——Dockerfile|学习笔记

就Docker file文件来讲,它主要由两类两类代码行组成或者两类行组成。一类就是以井号开头的注释行,一类,就是由指令及其指令参数所组成的指令行,对着instruction和instructions专用的arguments,一个docker file文件中可以有N个注释行,也可以有N个指令行。但是考虑到对应的docker镜像就是由多层镜像叠加而成的,而且他们基于写时复制的方式实现工作。因而他们的性能肯定会有一定程度的损耗,因而这里的镜像层次越低,层级越少,通常很可能性能越好,但是镜像的层级越少,那被复用的几率也就越低。这需要折中和权衡,找一个合适的范方法来进行解决。

而指令是不区分字符大小写的,但是指令中的参数,如果使用到文件系统的路径,则很有可能区分大小写。而后一旦指定一个定义好了一个docker file文件,随后docker Emerge Bill的命令,基于该文件开始去制作镜像的时候,它是一次以顺序,运行各个指令的。因此,这些指令(docker 文件)中的这些指令并没有复杂的循环条件什么之类的,它以此顺序运行完成。通常第一个指令应该是from或者与from能够关联的,像bug之类的参数指令。from就是用来指明基于哪个基础镜像启动一个临时的中间构建环境来构建新镜像的,所以他手动启动了一个容器,基于容器上手动做操作来添加文件什么之类的,几乎没有什么本质上的区别。

示例:

容器技术基础(四)——Dockerfile|学习笔记

这个示例文件里边没有任何注释行,仅仅给出了几个指令,每一个指令都有它对应的参数。第一个指令,使用了from指定基于哪个基础镜像文件来打算构建新镜像,而后为新建的镜像指定使用label参数来指定了一些标签,第一个第二建值,而且等于为1.20第三个运行指定的命令来完成相应的程序,包安装什么之类。定一些环境变量,以便于被该镜像启动的容器内部的进程所使用。它们通常是作为配置信息使用的,然后enter和CMD则是用来定义对应的该镜像作为启动容器时的镜像,是默认要运行的命令。

三、Dockerfile 支持的instructions

容器技术基础(四)——Dockerfile|学习笔记

1、from是用来指定基础镜像的,而这个基础镜像很有可能是需要通过参数来传递的,要期望这个docker fell能够更好的复用的话,希望能够像Docker像docker build(image build)命令,这个命令传递一些参数来替换某些内部的信息的,那这些传递过来的参数通常把它称为叫ARG叫argument,事实上From背后的内容是可以调用arguments所定的参数的,而这些参数的传递则完全可以通过arguments的定义,或者通过docker image build当中的传递,像那个对应的参数传值来进行引用。

2、label,其实就是像新建的镜像,附加一些键值格式的标签,然后因为定义环境变量,这的环境变量与ARG的不同之处在于,ARG是在Bill的过程中使用的ENV做的的环境变量,通常是在基于该新镜像使用docker container run命令启动为容器以后,能够被容器中的进程所使用的。

3、RUN表示在Docker Bill的过程当中打算运行的命令,用来为新镜像安装一些软件,删除一些软件或者添加一些文件什么之类的来生成中间数据的。

4、CMD与RUN不同地方在于,CMD也是用来指定的命令,只不过这个命令指定的是使用docker container run命令。基于该镜像启动容器是要在容器内部word里的命令和CMD,CMD很容易被覆盖,如果不想被覆盖,可以使用ENTERYPOINT。

5、PENTRYPOINT和CMD同时使用的时候有一些约定俗成的法则,如果二者同时出现,那么PENTRYPOINT则是默认运行命令,CMD指定的参数则是PENTRYPOINT所指定的那个命令的参数,也就是CMD成了传递给PENTRYPOINT命令所指定的命令中的参数。而且如果CMD出现多条的时候只有最后一个生效,PENTRYPOINT出现多个的话是会同时生效的,并且是自上而下依次运行。

6、WORKDIR是指定工作目录的,这个工作目录通常是作为CMD或者PENTRYPOINT所指定的默认命令启动起来以后的工作目录,也可以理解为EUN命令也仍然受到工作目录的影响,而且在一个docker file当中,WORKDIR是可以出现多次的,每一次它的作用范围只是之后的几个指令,比如制定WORKDIR后面订了几个指令,那么第一个WORKDIR只对这三个指令有效,后续的其他的指令是第二个WORKDIR第二的生效范围。

7、ADD和COPY是新镜像当中打算要制作的信箱当中去添加文件的,所不同的地方在于他们所制的功能有一定的区别,比如ADD支持通过互联网自动下载获取文件以后放到进行当中,ADD如果下载到的是一个格式的镜文件的话,它还能自动进行展开,需要遵循特定的格式来使用VOLUMR。

8、VOLUME为镜像文件中的进程运行默认就指定要使用存储券来持久存储数和脱离容器生命周期存储数据,但是需要在Docker RUN的时候使用选项激活EXPOSE就是暴露端口,但真正暴露依然是要"-P"选项。

9、USER以指定的用户运行,默认情况下,它很有可能是以容器中的根用户,也就是如此用户来运行进程的。为了避免出现安全问题,即便那个root不是真root,通常也需要将它切换成容器中的普通用户来运行。USER就是指定UID借地信息的。

10、ONBUILD则表示,在构建过程当中要触发的一些其他操作要触发器,这里指的是如果建好了目标新景象,再建一个更高级的镜像的时候这个ONBUILD中所指的指定的那些指令就可以在这个过程中被激活被激活。在使用生效逻辑生效阶段比较独特,在该Docker当中定义的ONBUILD对于该镜像的制作过程来讲不生效,而是对于生成的新镜像将来被别人作为基础镜像时才会生效。

11、HEALTHCHECCK这是自定义停止信号时HEALTHCHECCK自定义指定检测,在容器中运行的进程中,健康状态的命令是需要指定默认系统的,默认要加的cell类型,尤其是要指定Work类型的这种容器镜像的时候,通常可能要把shell指定为BT这样的批处理程序。

、容器运行时

Docker在底层的运行时,在LXC的基础上添加了一些更加便捷的容器使用方法,从而使得容器技术以现代容应用容器的面貌发扬光大,而doctor有很多的功能,叫Docker容器管理、Docker镜像管理、网络管理。其实较早版本的Docker纯粹是一个单体应用程序。

1、从Docker说起

●OCI(Open Container Initiative)

 ◆较早版本的Docker是一个单体系统,但其内部的各类功能间并不存在依赖关系,每类功能都可以在一个独立的工具中实现,而且每个工具都可以基于通用格式和同一个容器标准来协作。

 ◆于是,2015年6月,Docker、Google、CoreOS和其他供应商创建了OCI标准,它包括

  ★image-spec:镜像格式规范

  ★runtime-spec:运行时规范

 ◆Docker将用于运行容器的代码(libcontainer)作为一个名为runC的项目分解出来,并捐赠给了 OCI作为参考实现。

2、Docker程序组件

●为了兼容OCI规范,自1.11.0版本起始,Docker引擎由一个单一组件拆分成4个独立的项目

 ◆docker engine( docker-daemon)

 ◆containerd:守护进程,高级别的container runtime

  ★几乎囊括了容能运行时所需要的容然创建、启动、停止、中止、信号处理和删除,以及镜像管理(镜像和元信息等)等所有功能

  ★通过grpc向上层调用者公开其API,可被兼容的任何上层系统所调用,到如DockerEngine或kubernetes牌宫器编排系统

  ★但具体的容器管理还需要OCI兼容的runtime负责完成

 ●containerd-shim:支持多种不同的OCIruntime

 ● runc:低级别的contaner runtime

容器技术基础(四)——Dockerfile|学习笔记

3、其它的容器运行时

●CRI-O:一款类似于containerd的高级运行时,在底层同样需要调用低级运行时负责具体的容器管理任务,支持与OCI兼容的运行时(目前使用runC。

●Podman:另一款兼容OCI规范的高级容器运行时,它起初是CRI-O项目的一部分,后来单独分离成为libpod项目,podman是相关的命令行管理工具。

 ◆Podman在管理容器时使用无守护进程模型,它直接通过runC容器运行时进程(而非守护程序)与镜像;

Registry、容器和镜像存储以及Linux内核直接交互。

●KataContainers:在专用的精简内核中运行容器;

 ◆提供网络、1/O和内存的隔离,并可以通过虚拟化VT扩展利用硬件强制隔离,因而更像一个传统的精简版的;

虚拟机或轻量化的虚拟机但它又是一个容器技术;

 ◆支持OCI规范和KubernetesCR接口,并能够提供与标准Linux容器一致的性能。

4、低级和高级容器运行时

●低级别容器运行时:仅支持容器生命周期管理

●高级别容器运行时:镜像管理等高级功能

容器技术基础(四)——Dockerfile|学习笔记

5、CRI和容器运行时

●最初,Kubernetes使用Docker作为其容器运行时,并管理运行Docker容器的集群节点;

●后来,Kubernetes设计了CRI,以便能够与更多容器运行时协同

 ◆由Kubernetes自v1.5引入

 ◆将Kubelet与容器运行时解耦

容器技术基础(四)——Dockerfile|学习笔记

6、Docker和CRI

●但是,Docker并不支持CRI调用

 ◆于是,专门设计了dockershim充当         kubelet和Docker的中间层

 ◆在Docker拆分为四个组件后,Kubernetes便支持直接使用containerd进行容器管理,但仍需要一个CRI-

Containerd中间层

●后来,CRI-Containerd作为Containerd的插件直接提供

容器技术基础(四)——Dockerfile|学习笔记

Docker发展关键步骤:尤其以是DRI为技术站为核心的演进,经历了这样几个阶段。最早的时候,Kubernetes是通过CRI经由Docker使用的垫片,因为Docker本身并不理解CRI,因为docker是早于DRI出生的,又为了让Kubernetes能够支持CRI,所以Kubernetes不得不使用一个专门的工具叫Docker的垫片,以便于对接的DRI,从而到达contentrD。由contain借助于软C来运行容器,这是light与docker结合时的层级。后来发现过度的层级实在是太多了,所以后来doctor,等后来container D发展到1.0时代以后,Kubernetes就可以直接遵循CRI规范了,只是遵循CRI规范的一部分代码被单独的一个组件来提供了,这个时候Docker就不直接使用了Kubernetes发展到一点儿一之后,所以肯定是发展到1.1之后,这个专门的用于对接到CRI之上的这个功能模块,甚至于被作为contentrD的插件儿有可能就直接提供了。因而此时Kubernetes规范接口,是完全可以与contatinerd进行交互,进而完成容器管理的。

7、CRI和OCI

●CRI用于定义Kubernetes与容器运行时的协同

●OCI仅负责定义容器的格式

容器技术基础(四)——Dockerfile|学习笔记

8、Docker将何以自处?

●Kubernetes切换到containerd,是否意味着不能再使用Docker了?

 ◆显然,答案是,可以继续使用!

 ◆使用了containerd 1.1版本的Docker Engine将继续能够用于容器管理的其它用途;


容器技术基础(四)——Dockerfile|学习笔记


上一篇:Dojo学习笔记(九):Dojo布局——对齐方式容器


下一篇:Android之自定义Dialog屏幕旋转时自动关闭解决方法