namespace和cgroup都不是新技术,都利用了Linux现有的已经相对成熟的容器化技术,它都不是docker的创举,docker的创举是overylayfs,它开创性的提出了基于分层的文件系统来管理整个容器镜像。
容器使用了union fs文件系统,可以将多个目录,mount成为一个目录(虚拟目录里面)。不同的目录在这个虚拟目录里面又可以有独立的权限,也即是将两个不同的目录,挂载到同一个目录下面,然后通过读写权限的设置,使得呈现最终的文件目录给容器(模拟成了一个完整的操作系统)。
dockerfile它利用源码的方式,dockerfile里面定义了你的基础镜像是什么,中间要去运行哪些命令,比如中间需要安装依赖包,或者去拷贝一些要运行的二进制文件,最后还允许通过entrypoint命令来定义容器镜像运行的时候要执行哪些进程的命令。
通过这种方式以源代码的方式去定义一个容器镜像用来运行哪一个应用程序的,这刚好符合了微服务的架构思想。
Linux文件系统会分为两个部分,一个是bootfs,一个是rootfs
docker本身是没有完整的操作系统的,它利用的主机,无论是物理机还是虚拟机,docker启动的容器没有独立的操作系统,不需要自己的Bootloader ,所以没有bootfs的,因为主机已经启动起来了,但是它需要rootfs。
Linux
docker启动过程:首先初始化rootfs以readonly方式加载并且检查,但是检查完毕之后,并不是将rootfs直接变为可写,让你直接去写,而是在这个readonly的文件层基础之上,再添加新的readwrite层。
这样一层一层堆叠,下面的层永远都是只读的,当所有层级加载完毕之后,它会将最上面的一层变为readwrite。所有你针对这个容器的修改事实上都是在最上面这一层进行修改,并不会修改下面的readonly层。
Union FS是层层叠加的,可以看到在做镜像构建的时候,差不多每条指令都会作为一个文件层保存下来。
可以查看到每一层里面执行了什么样的命令。
[root@docker ~]# docker history busybox
IMAGE CREATED CREATED BY SIZE COMMENT
ec3f0931a6e6 3 weeks ago /bin/sh -c #(nop) CMD ["sh"] 0B
3 weeks ago /bin/sh -c #(nop) ADD file:1c8507e3e9b22b977?? 1.24MB
在docker run的时候,就会去回放这个镜像,按照层级一级一级的去加载,通过unionfs方式去加载,这会有不同的驱动,会将dockerfile里面的每一层加载,每一层是readonly的层,然后不断的叠加,将下面一层变为readonly,最终将上面变为writeable,这个时候完整的操作系统所需要的文件系统就存在了,rootfs也就存在了,容器就可以去读取这些文件了。
由于镜像具有共享特性,所以对容器可写层的操作需要依赖存储驱动提供的写时复制和用时分配 机制,以此来支持对容器可写层的修改,进而提高对存储和内存资源的利用率。
写操作对于这种文件系统,修改一个已经存在的文件,这个文件又在底层。不会直接去修改底层的文件,需要将这个文件复制出来,然后做的任何更改都会保存在上面那层 (一个镜像是可以被多个容器使用的,而且一个镜像里面的不同层也是可以被多个镜像共享的,所以就有了写时复制,这样就确保下面的基础镜像层永远都不会被修改)
随着overlayfs出现了第二个版本,引入了内核的发行版,如果要选文件系统更多的是overlayfs。device mapper性能要比overlayfs性能差不少。所以选择存储驱动的时候就直接选overylayfs2,新版本的Linux kernel就默认带了overylayfs的驱动,而且是overylayfs2。
docker本身内嵌了containerd,相当于docker功能当中的一个子集,而且它作为一个独立的开源项目出现。
OverlayFS 也是一种与 AUFS 类似的联合文件系统,同样属于文件级的存储驱动,包含了最初的 Overlay 和更新更稳定的 overlay2。
Overlay 只有两层:upper 层和 Lower 层。Lower 层代表镜像层,upper 层代表容器可写层。
相当于可以将多个目录mount成为一个合并的目录,在合并的时候有多个源,需要指定哪个源是下层,哪个源是上层。合并之后就会做merge。
$ mkdir upper lower merged work
$ echo "from lower" > lower/in_lower.txt
$ echo "from upper" > upper/in_upper.txt
$ echo "from lower" > lower/in_both.txt
$ echo "from upper" > upper/in_both.txt
$ sudo mount -t overlay overlay -o
lowerdir=`pwd`/lower,upperdir=`pwd`/upper,workdir=`pwd`/work `pwd`/merged
$ cat merged/in_both.txt
$ delete merged/in_both.txt
$ delete merged/in_lower.txt
$ delete merged/in_upper.txt
[root@docker ~]# docker inspect 37d084d8e21b
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/9bc4b82d74b358bd6a5508b8ce88c06bd0b1690351cce7a0d9654f50a7404793-init/diff:/var/lib/docker/overlay2/b80927bc79e591361567dfda28d821c498f2da6b945069929295040afb2b42d3/diff",
"MergedDir": "/var/lib/docker/overlay2/9bc4b82d74b358bd6a5508b8ce88c06bd0b1690351cce7a0d9654f50a7404793/merged",
"UpperDir": "/var/lib/docker/overlay2/9bc4b82d74b358bd6a5508b8ce88c06bd0b1690351cce7a0d9654f50a7404793/diff",
"WorkDir": "/var/lib/docker/overlay2/9bc4b82d74b358bd6a5508b8ce88c06bd0b1690351cce7a0d9654f50a7404793/work"
[root@docker ~]# docker history busybox
IMAGE CREATED CREATED BY SIZE COMMENT
ec3f0931a6e6 3 weeks ago /bin/sh -c #(nop) CMD ["sh"] 0B
3 weeks ago /bin/sh -c #(nop) ADD file:1c8507e3e9b22b977?? 1.24MB
可以看到容器镜像文件系统是怎么来的,dockerfile里面有很多层,每一层都被加载到LowerDir里面了,然后最上面有UpperDir。