先抛出几个我在学习过程当中产生的几个问题.git
1. 容器镜像是什么, 和装系统时的镜像有什么关系?github
2. 容器镜像的做用是什么?docker
3. 不一样版本的ubuntu镜像有什么区别, 好比说 ubuntu:18.04和ubuntn:16.04 的区别?shell
使用docker pull <image name>下载一个镜像看看ubuntu
能够看到咱们仅仅是pull了一个ubuntu18.04的镜像, docker pull的结果却出现了多行, 这是由于镜像是分红多层的. 具体为何要分层? 每一层又是什么? 下文咱们会谈到.缓存
因为docker 18.04采用的是overlayfs2做为默认的存储驱动, 因此下载的镜像都存储在/var/lib/docker/overlay2 中.学习
能够看到这里的目录个数和镜像层数是一致. 而且除了0c开头的那一层, 其余目录都是有diff和work两个子目录 . 0c开头的目录就是整个镜像最底层的只读层 ui
l目录下所有都是指向这些diff目录的软连接.让咱们进入0c.../diff中看看, 能够看到在diff目录中是一套完整的根目录. 因此说本质上, 根目录就是一个rootfs. this
跟装系统时的镜像没有一点点关系.spa
本节来讲说如何使用, 使用Dockerfile构建本身的镜像, dockfile由一系列的命令构成。我目前用过的有FROM RUN CMD ADD COPY命令。
From用来制定一个基础镜像层。
RUN命令会在一个新的镜像层上执行参数中所指定的任何命令, 并commit命令的执行结果。
CMD命令在我初次使用时, 与RUN有所混淆. 可是其实两者是彻底不一样的, CMD只是指定了运行容器时的初始命令, 可是在镜像构建时没有commit任何命令的结果。
举例来讲, 下图是一个Dockerfile. 在其中咱们先在一个新的镜像层建立一个shell脚本, 而后在CMD中运行这个脚本。
能够看到容器执行CMD中指定的命令.
2.1 分层特性
在咱们使用docker run命令启动一个容器时, 就会在现有的只读镜像层之上在建立一个可读写的容器层. 当咱们将这些容器删除时, 这些容器层也会被删除.
可是容器层之下的镜像层却不会改变.
图盗自(docker reference)
经过这种共享相同的镜像层的方式, 容器即实现了必定的隔离(容器层之间), 又节省了空间.
2.2 写时拷贝(COW)
若是容器须要读底层的文件或者目录, 那么直接读取底层的文件. 可是若是容器须要修改底层的文件, 那么容器层就会拷贝一个底层的文件.
虽然说都是COW策略, 可是实现起来, 不一样的存储驱动也是有所不一样的.
以overlayfs/overlayfs2为例:
1. 搜索全部的镜像层, 找到要修改的文件, 这个过程从最新的一层直到最底层. 另外搜索结果会放到缓存中, 加速下一次的查找。
2. 执行copy_up操做, 将文件拷贝到容器层
3. 修改文件的拷贝, 同时底层的文件对于容器层是不可见的.
只说了修改和读取, 那么当容器层要删除一个镜像层的文件时, 会发生什么呢? 让咱们看看。
先直接在底层镜像层中建立一个文件, 还记得上文中说到的那个只有diff目录和link文件的目录吗?那个就是最底层的镜像层。
咱们直接在diff/tmp/目录中建立一个文件, 文件名为thisIsAFileCreateImageLayer
而后运行一个容器, 进入tmp目录, 能够看到这个文件对于容器是可见的.
在容器层删除该文件
在镜像层看看
由上图能够看到在镜像层, 该文件是依然存在的, 这是由于在容器层, 在容器层删除文件或者目录
时, overlayfs采用了whiteouts和opaque技术.
Whiteouts是一个设备号为0/0的字符设备文件. 当上层目录中发现一个whiteout文件时, 在上层目录中读取底层的同名的文件时, 底层的文件就会被忽略.
以下图所示, 在新建立的容器层中咱们能够看到一个设备号为0,0的字符设备文件.
接下来我来尝试解答一下我以前的疑问:
其实前两个问题已经获得了解答, 先说说第三个问题
3. 不一样版本的ubuntu镜像有什么区别, 好比说 ubuntu:18.04和ubuntn:16.04 的区别?
不一样版本的ubuntu的区别我目前知道的区别是软件库的版本不一样.