各位小伙伴大家好,我是运维虫子!
上一篇文章,我们知道了容器的两大核心,namespace与cgroup,也清楚了他们的工作原理以及docker与传统虚拟化的区别。
今天我们来了解一下docker的镜像。这次我们从docker镜像使用文件系统开始聊起。
联合文件系统
docker支持多种graphDriver(联合文件系统),包括vfs,deviceMapper,overlay,overlay2,aufs等,其中最常用的是aufs,但是随着Linux内核把overlay引入以后,overlay就越来越受到重视了。
什么是联合文件系统呢,我们以overlay来举例,overlayfs通过三个目录:lower目录、upper目录、以及work目录实现,其中lower目录可以是多个,work目录为工作基础目录,挂载后内容会被清空,且在使用过程中其内容用户不可见,最后联合挂载完成给用户呈现的统一视图称为为merged目录。
先来看以下的文件结构:
[root@Docker ~]# tree .├── chongzi1│ ├── a│ └── b└── chongzi2 ├── b └── c2 directories, 4 files
通过overlay联合挂载到一个新的目录chongzi:
mount -t overlay overlay -o lowerdir=chongzi1,upperdir=chongzi2,workdir=chongzi chongzi
这时候,我们可以看到chongzi1和chongzi2的文件已经联合挂载到chongzi目录下了。
注:不知道大家有没有注意,我故意创建了两个b文件,那么联合挂载以后显示的b是哪个目录下的b呢,大家可以自行判断一下。
[root@Docker ~]# tree.├── chongzi│ ├── a│ ├── b│ └── c├── chongzi1│ ├── a│ └── b└── chongzi2 ├── b └── c
我们进行一个删除操作:
[root@Docker ~]# cd chongzi[root@Docker ~]# rm -rf a[root@Docker ~]# cd[root@Docker ~]# tree.├── chongzi│ ├── b│ └── c├── chongzi1│ ├── a│ └── b└── chongzi2 ├── a ├── b └── c
我们可以看到chongzi目录下a已经没了,但是为什么chongzi2下面还有个a呢?大家可以通过下面的图来思考一下。
容器镜像为了看起来更加真实,我们一般会把一个操作系统的文件挂载给镜像的“/”目录,而这个挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的“容器镜像”。它还有一个更为专业的名字,叫作:rootfs(根文件系统)。
在上述图中可以看到三个层结构,即:lowerdir、uperdir、merged,其中lowerdir是只读的image的layer,其实就是rootfs。而upperdir则是在lowerdir之上的一层,这层是读写层,在启动一个容器时候会进行创建,所有的对容器数据更改都发生在这里层。最后merged目录是容器的挂载点,也就是给用户暴露的统一视角。
docker镜像
了解联合文件系统以后,我们来进一步分析一下docker镜像。
容器镜像为了看起来更加真实,我们一般会把一个操作系统的文件挂载给镜像的“/”目录,而这个挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的“容器镜像”。它还有一个更为专业的名字,叫作:rootfs(根文件系统)。
docker info,查看docker的文件系统默认存储:
docker info
图中可以看出现在的docker默认版本已经是overlay2。所以我们重点来看看overlay2。
我们通过构建一个Ubuntu镜像的过程来了解:
[root@Docker ~]# docker pull ubuntuUsing default tag: latestlatest: Pulling from library/ubuntuda7391352a9b: Pull complete 14428a6d4bcd: Pull complete 2c2d948710f2: Pull complete Digest: sha256:c95a8e48bf88e9849f3e0f723d9f49fa12c5a00cfc6e60d2bc99d87555295e4cStatus: Downloaded newer image for ubuntu:latestdocker.io/library/ubuntu:latest
对Ubuntu镜像进行查看
docker image inspect ubuntu:latest
可以看到Ubuntu镜像对应的目录LowerDir,UpperDir,MergedDir,WorkDir以及对应的rootfs。
我们启动一个Ubuntu容器进行查看:
docker run -idt --name yunweichongzi ubuntu:latest
查看overlay2挂载情况:
[root@Docker ~]# mount | grep overlayoverlay on /var/lib/docker/overlay2/6536a9b8521249193d4f8a1e18729deaedae1e321f87b09cd97e7be675d459c9/merged type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/APOHNZ2NXGCRL4CDRYDQN65DXA:/var/lib/docker/overlay2/l/TKGVO7PGF23AKNZCUFXHHPWQOY:/var/lib/docker/overlay2/l/6KA4DCYAIJQG4FBUVMHX5GR6M4:/var/lib/docker/overlay2/l/3P6DVX2OJPFSAE5ITF43POQHJG,upperdir=/var/lib/docker/overlay2/6536a9b8521249193d4f8a1e18729deaedae1e321f87b09cd97e7be675d459c9/diff,workdir=/var/lib/docker/overlay2/6536a9b8521249193d4f8a1e18729deaedae1e321f87b09cd97e7be675d459c9/work)
查看工作目录,发现已经包含了完整的操作系统文件:
ls /var/lib/docker/overlay2/ID/merged/bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
查看init目录:
ls /var/lib/docker/overlay2/ID/diff/dev etc
因此,一个容器完整的层应由三个部分组成,如下图:
镜像层:也称为rootfs,提供容器启动的文件系统。
init层: 用于修改容器中一些文件如/etc/hostname、/etc/resolv.conf等
容器层:使用联合挂载统一给用户提供的可读写目录。
总结
正是因为docker的rootfs增量以及联合挂载系统,才有了容器镜像的层,同时也保证了容器镜像的环境一致性,容器完美的解决了“开发到测试到部署”的每一个流程。这也正是容器的魅力所在。
通过三篇文章,我们对docker有了更清晰的认识。一个“容器”,实际上是一个由 Linux Namespace、Linux Cgroups 和 rootfs 三种技术构建出来的进程的隔离环境。
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上。
下一篇:我们来说说k8s到底是什么?
多年致力于互联网搬砖,各种互联网技术都稍有涉猎。如果大家遇到一些问题可以私信或者留言给我。我们可以一起讨论!