理解docker镜像原理

docker学习记录

Posted by CHuiL on April 23, 2019

docker镜像与镜像层

要理解镜像,首先需要知道镜像是由一层一层镜像层堆叠起来的,而我们往往看的镜像(比如通过docker images)一般指的是镜像的顶层 image

如上图,在Dockerfile文件中,每一个命令都会生成一个新的镜像层,并且这些层是由层级关系的,下一层为上一层的父层,由指针连接起来;

  • FROM ubuntu:14.04 :设置基础镜像,此时会使用基础镜像 ubuntu:14.04 的所有镜像层,为简单起见,图中将其作为一个整体展示。
  • ADD run.sh / :将 Dockerfile 所在目录的文件 run.sh 加至镜像的根目录,此时新一层的镜像只有一项内容,即根目录下的 run.sh 。
  • VOLUME /data :设定镜像的 VOLUME ,此 VOLUME 在容器内部的路径为 /data。需要注意的是,此时并未在新一层的镜像中添加任何文件,但更新了镜像的 json 文件,以便通过此镜像启动容器时获取这方面的信息。
  • CMD [”./run.sh”] :设置镜像的默认执行入口,此命令同样不会在新建镜像中添加任何文件,仅仅在上一层镜像 json 文件的基础上更新新建镜像的 json 文件。

 每个镜像层都包含有一个json文件,里面记载着Dockerfile里创建新一层时对应的命令,以及文件信息,父层镜像,容器运行的环境配置等等(大部分信息都是在上一层镜像的json文件基础上更新新建的json文件)
 这样构建到最后,顶部的镜像层就代表为这一整个镜像(使用docker images 和docker history时会发现,images中出现的镜像总是docker history中列出的镜像的顶层)
 由于aufs存储驱动,镜像层之间是可共享的,所以这些镜像层自然是read-only的,也因此docker利用aufc大大降低了磁盘的使用空间。  

docker镜像与容器

一般我们通过docerfile来创建镜像,对于容器来说,镜像就是容器运行的环境,因为镜像往往配置包含了我们需要的文件,环境配置等等,但这些都属于静态内容,而容器是动态内容;
 作为静态的镜像,转化为动态docker有两个条件,转化的依据和执行这种转化的操作的执行者;

转化的依据

转化的其实就是依据是每个镜像的 json 文件,Docker 可以通过解析 Docker 镜像的 json 的文件,获知应该在这个镜像之上运行什么样的进程,应该为进程配置怎么样的环境变量,此时也就实现了静态向动态的转变。

转化的执行

谁来执行这个转化工作?答案是 Docker 守护进程。也许大家早就理解这样一句话: Docker 容器实质上就是一个或者多个进程,而容器的父进程就是 Docker 守护进程。这样的,转化工作的执行就不难理解了:Docker 守护进程手握 Docker 镜像的 json 文件,为容器配置相应的环境,并真正运行 Docker 镜像所指定的进程,完成 Docker 容器的真正创建。

容器进程文件系统进行读写操作

不会篡改Docker镜像,Docker守护进程会在Docker镜像的最上层之上,再添加一个可读可写层,容器所有写操作都会作用到这一层中。在容器需要写底层镜像层中的文件时,会将此文件从镜像层拷贝至最上层的可读可写层,然后容器进程在对读写层中的副本进行写操纵。对容器进程来讲,它只能看到最上层文件。

参考

一图看尽 docker 容器文件系统 深入分析 Docker 镜像原理